delve 0.0.7
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +24 -0
- data/LICENSE +25 -0
- data/README.md +6 -0
- data/ROADMAP.md +92 -0
- data/Rakefile +25 -0
- data/bin/delve +15 -0
- data/delve.gemspec +17 -0
- data/doc/examples/ascii.rb +34 -0
- data/doc/examples/astar.rb +39 -0
- data/doc/examples/border.rb +13 -0
- data/doc/examples/cellular.rb +15 -0
- data/doc/examples/display.rb +27 -0
- data/doc/examples/engine.rb +29 -0
- data/doc/examples/menu.rb +22 -0
- data/doc/examples/noise.rb +37 -0
- data/doc/examples/progress.rb +25 -0
- data/doc/examples/rogue.rb +15 -0
- data/lib/delve.rb +109 -0
- data/lib/delve/component/collision.rb +17 -0
- data/lib/delve/component/movement.rb +78 -0
- data/lib/delve/component/position.rb +30 -0
- data/lib/delve/component/symbol.rb +23 -0
- data/lib/delve/display/curses_renderer.rb +63 -0
- data/lib/delve/display/display.rb +51 -0
- data/lib/delve/engine.rb +30 -0
- data/lib/delve/entity.rb +23 -0
- data/lib/delve/event_queue.rb +48 -0
- data/lib/delve/fov/discrete_shadowcasting.rb +78 -0
- data/lib/delve/fov/fov.rb +83 -0
- data/lib/delve/game.rb +22 -0
- data/lib/delve/generator/cellular.rb +111 -0
- data/lib/delve/generator/dungeon.rb +19 -0
- data/lib/delve/generator/map.rb +30 -0
- data/lib/delve/generator/noise.rb +33 -0
- data/lib/delve/generator/rogue.rb +403 -0
- data/lib/delve/input/curses_input.rb +28 -0
- data/lib/delve/input/input.rb +12 -0
- data/lib/delve/path/astar.rb +83 -0
- data/lib/delve/path/path.rb +70 -0
- data/lib/delve/scheduler/action_scheduler.rb +38 -0
- data/lib/delve/scheduler/scheduler.rb +37 -0
- data/lib/delve/scheduler/simple_scheduler.rb +21 -0
- data/lib/delve/screen_manager.rb +41 -0
- data/lib/delve/widgets/border.rb +44 -0
- data/lib/delve/widgets/key_value.rb +36 -0
- data/lib/delve/widgets/menu.rb +84 -0
- data/lib/delve/widgets/multi_line.rb +51 -0
- data/lib/delve/widgets/progress.rb +37 -0
- data/lib/delve/widgets/text.rb +37 -0
- data/lib/delve/widgets/viewport.rb +67 -0
- data/rot.js.LICENSE +25 -0
- data/templates/Gemfile.erb +4 -0
- data/templates/README.md.erb +22 -0
- data/templates/binfile.erb +21 -0
- data/templates/game_screen.rb.erb +51 -0
- data/templates/gemspec.erb +27 -0
- data/templates/loading_screen.rb.erb +46 -0
- data/templates/player_factory.rb.erb +19 -0
- data/templates/title_screen.rb.erb +42 -0
- data/templates/world.rb.erb +63 -0
- data/test/component/collision_test.rb +39 -0
- data/test/component/movement_test.rb +155 -0
- data/test/component/position_test.rb +43 -0
- data/test/component/symbol_test.rb +30 -0
- data/test/delve_test.rb +61 -0
- data/test/display/curses_renderer_test.rb +60 -0
- data/test/display/display_test.rb +86 -0
- data/test/engine_test.rb +36 -0
- data/test/entity_test.rb +48 -0
- data/test/event_queue_test.rb +86 -0
- data/test/game_test.rb +47 -0
- data/test/generator/dungeon_test.rb +21 -0
- data/test/generator/map_test.rb +31 -0
- data/test/generator/noise_test.rb +49 -0
- data/test/input/curses_input_test.rb +24 -0
- data/test/input/input_test.rb +21 -0
- data/test/path/astar_test.rb +22 -0
- data/test/path/path_test.rb +41 -0
- data/test/scheduler/action_scheduler_test.rb +54 -0
- data/test/scheduler/scheduler_test.rb +50 -0
- data/test/scheduler/simple_scheduler_test.rb +33 -0
- data/test/screen_manager_test.rb +92 -0
- data/test/widgets/border_test.rb +60 -0
- data/test/widgets/key_value_test.rb +68 -0
- data/test/widgets/menu_test.rb +103 -0
- data/test/widgets/multi_line_test.rb +73 -0
- data/test/widgets/progress_test.rb +96 -0
- data/test/widgets/text_test.rb +66 -0
- data/test/widgets/viewport_test.rb +154 -0
- metadata +193 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
class Path
|
2
|
+
|
3
|
+
@@default_options = { topology: :eight }
|
4
|
+
|
5
|
+
def initialize(to_x, to_y, free_checker, options = Hash.new)
|
6
|
+
raise 'Cannot initialize path if to_x is nil' if to_x.nil?
|
7
|
+
raise 'Cannot initialize path if to_y is nil' if to_y.nil?
|
8
|
+
raise 'Cannot initialize path if free checker is nil' if free_checker.nil?
|
9
|
+
raise 'Cannot initialize path if free checker does not respond to #free?' unless free_checker.respond_to? :free?
|
10
|
+
|
11
|
+
@to_x = to_x
|
12
|
+
@to_y = to_y
|
13
|
+
@from_x = nil
|
14
|
+
@from_y = nil
|
15
|
+
@free_checker = free_checker
|
16
|
+
@options = @@default_options.merge options
|
17
|
+
|
18
|
+
@dirs = directions(options[:topology])
|
19
|
+
end
|
20
|
+
|
21
|
+
def compute(from_x, from_y)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def get_neighbours(cx, cy)
|
26
|
+
result = Array.new
|
27
|
+
(0..@dirs.length-1).each do |i|
|
28
|
+
dir = @dirs[i]
|
29
|
+
x = cx + dir[0]
|
30
|
+
y = cy + dir[1]
|
31
|
+
|
32
|
+
next unless @free_checker.free? x, y
|
33
|
+
result << [x, y]
|
34
|
+
end
|
35
|
+
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
def directions(v)
|
40
|
+
dirs = {
|
41
|
+
:four => [
|
42
|
+
[ 0, -1],
|
43
|
+
[ 1, 0],
|
44
|
+
[ 0, 1],
|
45
|
+
[-1, 0]
|
46
|
+
],
|
47
|
+
:eight => [
|
48
|
+
[ 0, -1],
|
49
|
+
[ 1, -1],
|
50
|
+
[ 1, 0],
|
51
|
+
[ 1, 1],
|
52
|
+
[ 0, 1],
|
53
|
+
[-1, 1],
|
54
|
+
[-1, 0],
|
55
|
+
[-1, -1]
|
56
|
+
],
|
57
|
+
:six => [
|
58
|
+
[-1, -1],
|
59
|
+
[ 1, -1],
|
60
|
+
[ 2, 0],
|
61
|
+
[ 1, 1],
|
62
|
+
[-1, 1],
|
63
|
+
[-2, 0]
|
64
|
+
]
|
65
|
+
}
|
66
|
+
|
67
|
+
dirs[v]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'delve/scheduler/scheduler'
|
2
|
+
|
3
|
+
class ActionScheduler < Scheduler
|
4
|
+
|
5
|
+
@@default_duration = 1
|
6
|
+
|
7
|
+
def initialize(event_queue)
|
8
|
+
@duration = @@default_duration
|
9
|
+
super event_queue
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove(item)
|
17
|
+
@duration = @@default_duration if item == @current
|
18
|
+
super item
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(item, repeat, time=@@default_duration)
|
22
|
+
@queue.add item, time
|
23
|
+
super item, repeat
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_duration(time)
|
27
|
+
@duration = time if @current
|
28
|
+
end
|
29
|
+
|
30
|
+
def next
|
31
|
+
if @current and !@repeat.index(@current).nil?
|
32
|
+
@queue.add(@current, @duration || @@default_duration)
|
33
|
+
@duration = @@default_duration
|
34
|
+
end
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Scheduler
|
2
|
+
|
3
|
+
def initialize(event_queue)
|
4
|
+
@queue = event_queue
|
5
|
+
@current = nil
|
6
|
+
@repeat = Array.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def time
|
10
|
+
@queue.time
|
11
|
+
end
|
12
|
+
|
13
|
+
def next
|
14
|
+
@current = @queue.get
|
15
|
+
@current
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove(item)
|
19
|
+
result = @queue.remove item
|
20
|
+
|
21
|
+
index = @repeat.index item
|
22
|
+
@events.delete_at index if index
|
23
|
+
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear
|
28
|
+
@queue.clear
|
29
|
+
@current = nil
|
30
|
+
@repeat = Array.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def add(item, repeat=false)
|
34
|
+
@repeat << item if repeat
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'delve/scheduler/scheduler'
|
2
|
+
|
3
|
+
class SimpleScheduler < Scheduler
|
4
|
+
|
5
|
+
def initialize(event_queue)
|
6
|
+
super event_queue
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(item, repeat)
|
10
|
+
@queue.add item, 0
|
11
|
+
super item, repeat
|
12
|
+
end
|
13
|
+
|
14
|
+
def next
|
15
|
+
if @current and !@repeat.index(@current).nil?
|
16
|
+
@queue.add(@current, 0)
|
17
|
+
end
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ScreenManager
|
2
|
+
def initialize
|
3
|
+
@screen_stack = Array.new
|
4
|
+
end
|
5
|
+
|
6
|
+
def empty?
|
7
|
+
@screen_stack.empty?
|
8
|
+
end
|
9
|
+
|
10
|
+
def push_screen(screen)
|
11
|
+
@screen_stack.push screen
|
12
|
+
end
|
13
|
+
|
14
|
+
def pop_screen
|
15
|
+
@screen_stack.pop
|
16
|
+
end
|
17
|
+
|
18
|
+
def update(input)
|
19
|
+
raise 'Cannot handle key when no screens are present' if empty?
|
20
|
+
raise 'Cannot handle key when input is nil' unless input
|
21
|
+
@screen_stack.last.update input
|
22
|
+
end
|
23
|
+
|
24
|
+
def render(display)
|
25
|
+
raise 'Cannot render when no screens are present' if empty?
|
26
|
+
raise 'Cannot render when display is nil' unless display
|
27
|
+
|
28
|
+
bottom = @screen_stack.length - 1
|
29
|
+
screens = @screen_stack.length - 1
|
30
|
+
|
31
|
+
(0..screens).reverse_each do |i|
|
32
|
+
if !@screen_stack[i].partial?
|
33
|
+
break
|
34
|
+
end
|
35
|
+
bottom = i-1
|
36
|
+
end
|
37
|
+
(bottom..screens).each do |i|
|
38
|
+
@screen_stack[i].render display
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class BorderWidget
|
2
|
+
def initialize(x, y, width, height, heading=nil, fg=:white, bg=:black)
|
3
|
+
raise 'Cannot initialize border widget when x is nil' unless x
|
4
|
+
raise 'Cannot initialize border widget when y is nil' unless y
|
5
|
+
raise 'Cannot initailize border widget when width is nil' unless width
|
6
|
+
raise 'Cannot initialize border widget when height is nil' unless height
|
7
|
+
raise 'Cannot initialize border widget when heading is wider than width + 4' if heading and heading.length > width + 4
|
8
|
+
|
9
|
+
@x = x
|
10
|
+
@y = y
|
11
|
+
@width = width
|
12
|
+
@height = height
|
13
|
+
@heading = heading
|
14
|
+
@fg = fg
|
15
|
+
@bg = bg
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw(display)
|
19
|
+
raise 'Cannot draw text when display is nil' unless display
|
20
|
+
|
21
|
+
header_text = " #{@heading} "
|
22
|
+
if header_text.length.odd?
|
23
|
+
header_text = "#{header_text} "
|
24
|
+
end
|
25
|
+
center_point = ((@x + @width) / 2).floor
|
26
|
+
half_text = (header_text.length / 2).ceil
|
27
|
+
header_start = center_point - half_text
|
28
|
+
header_end = center_point + half_text
|
29
|
+
|
30
|
+
(@x..(@x+@width-1)).each do |x|
|
31
|
+
char = (x == @x || x == (@x+@width-1)) ? '+' : '-'
|
32
|
+
if @heading and x > header_start and x <= header_end
|
33
|
+
char = header_text[x-header_start-1]
|
34
|
+
end
|
35
|
+
display.draw x, @y, char, @fg, @bg
|
36
|
+
display.draw x, (@y+@height-1), (x == @x || x == (@x+@width-1)) ? '+' : '-', @fg, @bg
|
37
|
+
end
|
38
|
+
|
39
|
+
((@y+1)..(@y+@height-2)).each do |y|
|
40
|
+
display.draw @x, y, '|', @fg, @bg
|
41
|
+
display.draw (@x+@width-1), y, '|', @fg, @bg
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class KeyValueWidget
|
2
|
+
attr_accessor :value
|
3
|
+
|
4
|
+
def initialize(x, y, label, value)
|
5
|
+
raise 'Cannot initialize key value widget when x is nil' unless x
|
6
|
+
raise 'Cannot initialize key value widget when y is nil' unless y
|
7
|
+
raise 'Cannot initialize key value widget when label is nil' unless label
|
8
|
+
raise 'Cannot initialize key value widget when value is nil' unless value
|
9
|
+
|
10
|
+
@x = x
|
11
|
+
@y = y
|
12
|
+
@label = label
|
13
|
+
@value = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def draw(display)
|
17
|
+
raise 'Cannot draw text when display is nil' unless display
|
18
|
+
|
19
|
+
x = @x
|
20
|
+
@label.each_char do |c|
|
21
|
+
display.draw x, @y, c
|
22
|
+
x += 1
|
23
|
+
end
|
24
|
+
|
25
|
+
display.draw x, @y, ':'
|
26
|
+
x += 1
|
27
|
+
display.draw x, @y, ' '
|
28
|
+
x += 1
|
29
|
+
|
30
|
+
@value.each_char do |c|
|
31
|
+
display.draw x, @y, c
|
32
|
+
x += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
class MenuWidget
|
2
|
+
def initialize(x, y, items, foreground=:white, background=:black, highlight=:red)
|
3
|
+
raise 'Cannot initialize menu widget when x is nil' unless x
|
4
|
+
raise 'Cannot initialize menu widget when y is nil' unless y
|
5
|
+
raise 'Cannot initialize menu widget when items is nil' unless items
|
6
|
+
raise 'Cannot initialize menu widget when items is empty' if items.empty?
|
7
|
+
|
8
|
+
@x = x
|
9
|
+
@y = y
|
10
|
+
@items = items
|
11
|
+
@selected_index = 0
|
12
|
+
@fg = foreground
|
13
|
+
@bg = background
|
14
|
+
@highlight = highlight
|
15
|
+
end
|
16
|
+
|
17
|
+
def selected_item
|
18
|
+
key = @items.keys[@selected_index]
|
19
|
+
@items[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def next
|
23
|
+
@selected_index += 1
|
24
|
+
if @selected_index >= @items.keys.length
|
25
|
+
@selected_index = 0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def previous
|
30
|
+
@selected_index -= 1
|
31
|
+
if @selected_index < 0
|
32
|
+
@selected_index = @items.keys.length - 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def select(key)
|
37
|
+
return false if !@items.keys.include? key
|
38
|
+
@selected_index = @items.keys.index key
|
39
|
+
end
|
40
|
+
|
41
|
+
def draw(display)
|
42
|
+
raise 'Cannot draw text when display is nil' unless display
|
43
|
+
|
44
|
+
items = 0
|
45
|
+
@items.keys.each do |key|
|
46
|
+
chars = 0
|
47
|
+
y = determine_y display
|
48
|
+
@items[key].each_char do |c|
|
49
|
+
fg = @selected_index == items ? @bg : @fg
|
50
|
+
bg = @selected_index == items ? @fg : @bg
|
51
|
+
x = determine_x display
|
52
|
+
text_color = (c == key || c == key.upcase) ? @highlight : fg
|
53
|
+
display.draw(x + chars, y + items, c, text_color, bg)
|
54
|
+
chars += 1
|
55
|
+
end
|
56
|
+
items += 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def determine_x display
|
62
|
+
if @x == :center
|
63
|
+
return (display.width / 2.0).ceil - (longest_line / 2.0).floor
|
64
|
+
end
|
65
|
+
@x
|
66
|
+
end
|
67
|
+
|
68
|
+
def determine_y display
|
69
|
+
if @y == :center
|
70
|
+
return ((display.height / 2.0).ceil) - (@items.keys.length / 2.0).floor
|
71
|
+
end
|
72
|
+
@y
|
73
|
+
end
|
74
|
+
|
75
|
+
def longest_line
|
76
|
+
value = -1
|
77
|
+
@items.keys.each do |key|
|
78
|
+
if value < @items[key].length
|
79
|
+
value = @items[key].length
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return value
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class MultiLineWidget
|
2
|
+
def initialize(x, y, lines)
|
3
|
+
raise 'Cannot initialize text widget when x is nil' unless x
|
4
|
+
raise 'Cannot initialize text widget when y is nil' unless y
|
5
|
+
raise 'Cannot initialize text widget when lines is nil' unless lines
|
6
|
+
|
7
|
+
@x = x
|
8
|
+
@y = y
|
9
|
+
@lines = lines
|
10
|
+
end
|
11
|
+
|
12
|
+
def draw(display)
|
13
|
+
raise 'Cannot draw text when display is nil' unless display
|
14
|
+
|
15
|
+
y = determine_y(display)
|
16
|
+
@lines.each do |line|
|
17
|
+
x = determine_x(display)
|
18
|
+
line.each_char do |c|
|
19
|
+
display.draw x, y, c
|
20
|
+
x += 1
|
21
|
+
end
|
22
|
+
y += 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def determine_x display
|
28
|
+
if @x == :center
|
29
|
+
return (display.width / 2.0).ceil - (longest_line / 2.0).floor
|
30
|
+
end
|
31
|
+
@x
|
32
|
+
end
|
33
|
+
|
34
|
+
def determine_y display
|
35
|
+
if @y == :center
|
36
|
+
return ((display.height / 2.0).ceil) - (@lines.length / 2.0).floor
|
37
|
+
end
|
38
|
+
@y
|
39
|
+
end
|
40
|
+
|
41
|
+
def longest_line
|
42
|
+
value = -1
|
43
|
+
@lines.each do |line|
|
44
|
+
if value < line.length
|
45
|
+
value = line.length
|
46
|
+
end
|
47
|
+
end
|
48
|
+
return value
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class ProgressWidget
|
2
|
+
attr_accessor :current, :max
|
3
|
+
|
4
|
+
def initialize(x, y, width, current, max, fg, bg)
|
5
|
+
raise 'Cannot initialize progress widget when x is nil' unless x
|
6
|
+
raise 'Cannot initialize progress widget when y is nil' unless y
|
7
|
+
raise 'Cannot initialize progress widget when width is nil' unless width
|
8
|
+
raise 'Cannot initialize progress widget when current value is nil' unless current
|
9
|
+
raise 'Cannot initialize progress widget when max value is nil' unless max
|
10
|
+
raise 'Cannot initialize progress widget when foreground color is nil' unless fg
|
11
|
+
raise 'Cannot initialize progress widget when background color is nil' unless bg
|
12
|
+
|
13
|
+
@x = x
|
14
|
+
@y = y
|
15
|
+
@width = width
|
16
|
+
@current = current
|
17
|
+
@max = max
|
18
|
+
@fg = fg
|
19
|
+
@bg = bg
|
20
|
+
end
|
21
|
+
|
22
|
+
def draw(display)
|
23
|
+
raise 'Cannot draw text when display is nil' unless display
|
24
|
+
|
25
|
+
percent = 1.0 * @current / @max
|
26
|
+
to_fill = (percent * @width).ceil
|
27
|
+
|
28
|
+
x = @x
|
29
|
+
(0..@width-1).each do |i|
|
30
|
+
color = i < to_fill ? @fg : @bg
|
31
|
+
display.draw x, @y, ' ', color, color
|
32
|
+
x += 1
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|