karnowski-ruby-warrior 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 +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +156 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/bin/rubywarrior +8 -0
- data/features/levels.feature +50 -0
- data/features/profiles.feature +46 -0
- data/features/step_definitions/common_steps.rb +7 -0
- data/features/step_definitions/interaction_steps.rb +53 -0
- data/features/support/env.rb +8 -0
- data/features/support/mockio.rb +57 -0
- data/features/towers.feature +14 -0
- data/lib/ruby_warrior.rb +41 -0
- data/lib/ruby_warrior/abilities/attack.rb +24 -0
- data/lib/ruby_warrior/abilities/base.rb +36 -0
- data/lib/ruby_warrior/abilities/bind.rb +19 -0
- data/lib/ruby_warrior/abilities/direction_of.rb +13 -0
- data/lib/ruby_warrior/abilities/direction_of_stairs.rb +13 -0
- data/lib/ruby_warrior/abilities/distance.rb +13 -0
- data/lib/ruby_warrior/abilities/explode.rb +16 -0
- data/lib/ruby_warrior/abilities/feel.rb +13 -0
- data/lib/ruby_warrior/abilities/health.rb +13 -0
- data/lib/ruby_warrior/abilities/listen.rb +15 -0
- data/lib/ruby_warrior/abilities/look.rb +15 -0
- data/lib/ruby_warrior/abilities/pivot.rb +16 -0
- data/lib/ruby_warrior/abilities/rescue.rb +23 -0
- data/lib/ruby_warrior/abilities/rest.rb +20 -0
- data/lib/ruby_warrior/abilities/shoot.rb +23 -0
- data/lib/ruby_warrior/abilities/walk.rb +20 -0
- data/lib/ruby_warrior/config.rb +11 -0
- data/lib/ruby_warrior/core_additions.rb +25 -0
- data/lib/ruby_warrior/floor.rb +71 -0
- data/lib/ruby_warrior/game.rb +160 -0
- data/lib/ruby_warrior/level.rb +93 -0
- data/lib/ruby_warrior/level_loader.rb +52 -0
- data/lib/ruby_warrior/player_generator.rb +41 -0
- data/lib/ruby_warrior/position.rb +80 -0
- data/lib/ruby_warrior/profile.rb +86 -0
- data/lib/ruby_warrior/space.rb +63 -0
- data/lib/ruby_warrior/tower.rb +14 -0
- data/lib/ruby_warrior/turn.rb +38 -0
- data/lib/ruby_warrior/ui.rb +64 -0
- data/lib/ruby_warrior/units/archer.rb +34 -0
- data/lib/ruby_warrior/units/base.rb +95 -0
- data/lib/ruby_warrior/units/captive.rb +30 -0
- data/lib/ruby_warrior/units/sludge.rb +30 -0
- data/lib/ruby_warrior/units/thick_sludge.rb +13 -0
- data/lib/ruby_warrior/units/warrior.rb +58 -0
- data/lib/ruby_warrior/units/wizard.rb +34 -0
- data/ruby-warrior.gemspec +191 -0
- data/script/console +8 -0
- data/spec/fixtures/short-tower/level_001.rb +14 -0
- data/spec/fixtures/short-tower/level_002.rb +14 -0
- data/spec/fixtures/walking_player.rb +5 -0
- data/spec/ruby_warrior/abilities/attack_spec.rb +51 -0
- data/spec/ruby_warrior/abilities/base_spec.rb +24 -0
- data/spec/ruby_warrior/abilities/bind_spec.rb +19 -0
- data/spec/ruby_warrior/abilities/direction_of_spec.rb +13 -0
- data/spec/ruby_warrior/abilities/direction_of_stairs_spec.rb +13 -0
- data/spec/ruby_warrior/abilities/distance_spec.rb +13 -0
- data/spec/ruby_warrior/abilities/explode_spec.rb +21 -0
- data/spec/ruby_warrior/abilities/feel_spec.rb +13 -0
- data/spec/ruby_warrior/abilities/health_spec.rb +13 -0
- data/spec/ruby_warrior/abilities/listen_spec.rb +17 -0
- data/spec/ruby_warrior/abilities/look_spec.rb +15 -0
- data/spec/ruby_warrior/abilities/pivot_spec.rb +18 -0
- data/spec/ruby_warrior/abilities/rescue_spec.rb +40 -0
- data/spec/ruby_warrior/abilities/rest_spec.rb +29 -0
- data/spec/ruby_warrior/abilities/shoot_spec.rb +22 -0
- data/spec/ruby_warrior/abilities/walk_spec.rb +25 -0
- data/spec/ruby_warrior/floor_spec.rb +81 -0
- data/spec/ruby_warrior/game_spec.rb +96 -0
- data/spec/ruby_warrior/level_loader_spec.rb +54 -0
- data/spec/ruby_warrior/level_spec.rb +163 -0
- data/spec/ruby_warrior/player_generator_spec.rb +12 -0
- data/spec/ruby_warrior/position_spec.rb +103 -0
- data/spec/ruby_warrior/profile_spec.rb +125 -0
- data/spec/ruby_warrior/space_spec.rb +165 -0
- data/spec/ruby_warrior/tower_spec.rb +15 -0
- data/spec/ruby_warrior/turn_spec.rb +42 -0
- data/spec/ruby_warrior/ui_spec.rb +96 -0
- data/spec/ruby_warrior/units/archer_spec.rb +23 -0
- data/spec/ruby_warrior/units/base_spec.rb +133 -0
- data/spec/ruby_warrior/units/captive_spec.rb +34 -0
- data/spec/ruby_warrior/units/sludge_spec.rb +27 -0
- data/spec/ruby_warrior/units/thick_sludge_spec.rb +19 -0
- data/spec/ruby_warrior/units/warrior_spec.rb +60 -0
- data/spec/ruby_warrior/units/wizard_spec.rb +23 -0
- data/spec/spec_helper.rb +7 -0
- data/templates/README.erb +20 -0
- data/templates/player.rb +5 -0
- data/towers/beginner/level_001.rb +15 -0
- data/towers/beginner/level_002.rb +17 -0
- data/towers/beginner/level_003.rb +20 -0
- data/towers/beginner/level_004.rb +17 -0
- data/towers/beginner/level_005.rb +21 -0
- data/towers/beginner/level_006.rb +18 -0
- data/towers/beginner/level_007.rb +17 -0
- data/towers/beginner/level_008.rb +20 -0
- data/towers/beginner/level_009.rb +19 -0
- data/towers/intermediate/level_001.rb +17 -0
- data/towers/intermediate/level_002.rb +19 -0
- data/towers/intermediate/level_003.rb +22 -0
- data/towers/intermediate/level_004.rb +23 -0
- data/towers/intermediate/level_005.rb +18 -0
- data/towers/intermediate/level_006.rb +23 -0
- metadata +218 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class Space
|
|
3
|
+
def initialize(floor, x, y)
|
|
4
|
+
@floor, @x, @y = floor, x, y
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def wall?
|
|
8
|
+
@floor.out_of_bounds? @x, @y
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def warrior?
|
|
12
|
+
unit.kind_of? Units::Warrior
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def enemy?
|
|
16
|
+
unit && !warrior? && !captive?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def captive?
|
|
20
|
+
unit && unit.bound?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def empty?
|
|
24
|
+
unit.nil? && !wall?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def stairs?
|
|
28
|
+
@floor.stairs_location == location
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ticking?
|
|
32
|
+
unit.respond_to?(:bomb_time) && unit.bomb_time
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def unit
|
|
36
|
+
@floor.get(@x, @y)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def location
|
|
40
|
+
[@x, @y]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_map
|
|
44
|
+
if unit
|
|
45
|
+
unit.to_map
|
|
46
|
+
elsif stairs?
|
|
47
|
+
">"
|
|
48
|
+
else
|
|
49
|
+
" "
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_s
|
|
54
|
+
if unit
|
|
55
|
+
unit.to_s
|
|
56
|
+
elsif wall?
|
|
57
|
+
'wall'
|
|
58
|
+
else
|
|
59
|
+
'nothing'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class Turn
|
|
3
|
+
attr_reader :action
|
|
4
|
+
|
|
5
|
+
def initialize(abilities)
|
|
6
|
+
@action = nil
|
|
7
|
+
@senses = {}
|
|
8
|
+
|
|
9
|
+
abilities.each do |name, sense|
|
|
10
|
+
if name.to_s =~ /\!$/
|
|
11
|
+
add_action(name)
|
|
12
|
+
else
|
|
13
|
+
add_sense(name, sense)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def add_action(action)
|
|
21
|
+
instance_eval <<-EOS
|
|
22
|
+
def #{action}(*args)
|
|
23
|
+
raise "Only one action can be performed per turn." if @action
|
|
24
|
+
@action = [:#{action}, *args]
|
|
25
|
+
end
|
|
26
|
+
EOS
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_sense(name, sense)
|
|
30
|
+
instance_eval <<-EOS
|
|
31
|
+
def #{name}(*args)
|
|
32
|
+
@senses[:#{name}].perform(*args)
|
|
33
|
+
end
|
|
34
|
+
EOS
|
|
35
|
+
@senses[name] = sense
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class UI
|
|
3
|
+
class << self
|
|
4
|
+
attr_accessor :delay
|
|
5
|
+
|
|
6
|
+
def in_stream=(in_stream)
|
|
7
|
+
@in = in_stream
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def out_stream=(stream)
|
|
11
|
+
@out = stream
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def puts(msg)
|
|
15
|
+
@out.puts(msg) if @out
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def puts_with_delay(msg)
|
|
19
|
+
result = puts(msg)
|
|
20
|
+
sleep(@delay) if @delay
|
|
21
|
+
result
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def print(msg)
|
|
25
|
+
@out.print(msg) if @out
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def gets
|
|
29
|
+
@in ? @in.gets : ''
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def request(msg)
|
|
33
|
+
print(msg)
|
|
34
|
+
gets.chomp
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ask(msg)
|
|
38
|
+
request("#{msg} [yn] ") == 'y'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# REFACTORME
|
|
42
|
+
def choose(item, options)
|
|
43
|
+
if options.length == 1
|
|
44
|
+
response = options.first
|
|
45
|
+
else
|
|
46
|
+
options.each_with_index do |option, i|
|
|
47
|
+
if option.kind_of? Array
|
|
48
|
+
puts "[#{i+1}] #{option.last}"
|
|
49
|
+
else
|
|
50
|
+
puts "[#{i+1}] #{option}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
choice = request("Choose #{item} by typing the number: ")
|
|
54
|
+
response = options[choice.to_i-1]
|
|
55
|
+
end
|
|
56
|
+
if response.kind_of? Array
|
|
57
|
+
response.first
|
|
58
|
+
else
|
|
59
|
+
response
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
module Units
|
|
3
|
+
class Archer < Base
|
|
4
|
+
def initialize
|
|
5
|
+
add_abilities :shoot!, :look
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def play_turn(turn)
|
|
9
|
+
[:forward, :left, :right].each do |direction|
|
|
10
|
+
turn.look(direction).each do |space|
|
|
11
|
+
if space.warrior?
|
|
12
|
+
turn.shoot!(direction)
|
|
13
|
+
return
|
|
14
|
+
elsif !space.empty?
|
|
15
|
+
break
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def shoot_power
|
|
22
|
+
3
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def max_health
|
|
26
|
+
7
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_map
|
|
30
|
+
"a"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
module Units
|
|
3
|
+
class Base
|
|
4
|
+
attr_writer :health
|
|
5
|
+
attr_accessor :position
|
|
6
|
+
|
|
7
|
+
def attack_power
|
|
8
|
+
0
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def max_health
|
|
12
|
+
0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def earn_points(points)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def health
|
|
19
|
+
@health ||= max_health
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def take_damage(amount)
|
|
23
|
+
unbind if bound?
|
|
24
|
+
if health
|
|
25
|
+
self.health -= amount
|
|
26
|
+
say "takes #{amount} damage, #{health} health power left"
|
|
27
|
+
if health <= 0
|
|
28
|
+
@position = nil
|
|
29
|
+
say "dies"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def alive?
|
|
35
|
+
!position.nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def bound?
|
|
39
|
+
@bound
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def unbind
|
|
43
|
+
say "released from bonds"
|
|
44
|
+
@bound = false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def bind
|
|
48
|
+
@bound = true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def say(msg)
|
|
52
|
+
UI.puts_with_delay "#{name} #{msg}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def name
|
|
56
|
+
self.class.name.split('::').last.titleize
|
|
57
|
+
end
|
|
58
|
+
alias_method :to_s, :name
|
|
59
|
+
|
|
60
|
+
def add_abilities(*new_abilities)
|
|
61
|
+
new_abilities.each do |ability|
|
|
62
|
+
abilities[ability] = eval("Abilities::#{ability.to_s.sub('!', '').camelize}").new(self) # TODO use something similar to constantize here
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def next_turn
|
|
67
|
+
Turn.new(abilities)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def prepare_turn
|
|
71
|
+
@current_turn = next_turn
|
|
72
|
+
play_turn(@current_turn)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def perform_turn
|
|
76
|
+
if @current_turn.action && @position && !bound?
|
|
77
|
+
name, *args = @current_turn.action
|
|
78
|
+
abilities[name].perform(*args)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def play_turn(turn)
|
|
83
|
+
# to be overriden by subclass
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def abilities
|
|
87
|
+
@abilities ||= {}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def to_map
|
|
91
|
+
"?"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
module Units
|
|
3
|
+
class Captive < Base
|
|
4
|
+
attr_accessor :bomb_time
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
add_abilities :explode!
|
|
8
|
+
bind
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def max_health
|
|
12
|
+
1
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_map
|
|
16
|
+
"C"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def play_turn(turn)
|
|
20
|
+
if @bomb_time
|
|
21
|
+
@bomb_time -= 1
|
|
22
|
+
if @bomb_time.zero?
|
|
23
|
+
@bound = false # unbind so it can perform an action
|
|
24
|
+
turn.explode!
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
module Units
|
|
3
|
+
class Sludge < Base
|
|
4
|
+
def initialize
|
|
5
|
+
add_abilities :attack!, :feel
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def play_turn(turn)
|
|
9
|
+
[:forward, :left, :right, :backward].each do |direction|
|
|
10
|
+
if turn.feel(direction).warrior?
|
|
11
|
+
turn.attack!(direction)
|
|
12
|
+
return
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def attack_power
|
|
18
|
+
3
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def max_health
|
|
22
|
+
12
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_map
|
|
26
|
+
"s"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
module Units
|
|
3
|
+
class Warrior < Base
|
|
4
|
+
attr_writer :name
|
|
5
|
+
attr_reader :score
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@score = 0 # TODO make score dynamic
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def play_turn(turn)
|
|
12
|
+
player.play_turn(turn)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def player
|
|
16
|
+
@player ||= Player.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def earn_points(points)
|
|
20
|
+
@score += points
|
|
21
|
+
say "earns #{points} points"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def attack_power
|
|
25
|
+
5
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def shoot_power
|
|
29
|
+
3
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def max_health
|
|
33
|
+
20
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def name
|
|
37
|
+
if @name && !@name.empty?
|
|
38
|
+
@name
|
|
39
|
+
else
|
|
40
|
+
"Warrior"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_s
|
|
45
|
+
name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_map
|
|
49
|
+
"@"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def perform_turn
|
|
53
|
+
say "does nothing" if @current_turn.action.nil?
|
|
54
|
+
super
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|