rubywarrior 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +170 -0
- data/Rakefile +21 -0
- data/bin/rubywarrior +5 -0
- data/features/command_options.feature +46 -0
- data/features/levels.feature +51 -0
- data/features/profiles.feature +56 -0
- data/features/step_definitions/common_steps.rb +19 -0
- data/features/step_definitions/interaction_steps.rb +65 -0
- data/features/support/env.rb +12 -0
- data/features/support/mockio.rb +57 -0
- data/features/towers.feature +14 -0
- data/lib/ruby_warrior.rb +44 -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 +22 -0
- data/lib/ruby_warrior/core_additions.rb +25 -0
- data/lib/ruby_warrior/floor.rb +71 -0
- data/lib/ruby_warrior/game.rb +193 -0
- data/lib/ruby_warrior/level.rb +119 -0
- data/lib/ruby_warrior/level_loader.rb +56 -0
- data/lib/ruby_warrior/player_generator.rb +41 -0
- data/lib/ruby_warrior/position.rb +80 -0
- data/lib/ruby_warrior/profile.rb +104 -0
- data/lib/ruby_warrior/runner.rb +33 -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 +54 -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/spec/fixtures/short-tower/level_001.rb +15 -0
- data/spec/fixtures/short-tower/level_002.rb +15 -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 +119 -0
- data/spec/ruby_warrior/level_loader_spec.rb +54 -0
- data/spec/ruby_warrior/level_spec.rb +203 -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 +144 -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 +93 -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 +10 -0
- data/templates/README.erb +20 -0
- data/templates/player.rb +5 -0
- data/towers/beginner/level_001.rb +16 -0
- data/towers/beginner/level_002.rb +18 -0
- data/towers/beginner/level_003.rb +21 -0
- data/towers/beginner/level_004.rb +18 -0
- data/towers/beginner/level_005.rb +22 -0
- data/towers/beginner/level_006.rb +19 -0
- data/towers/beginner/level_007.rb +18 -0
- data/towers/beginner/level_008.rb +21 -0
- data/towers/beginner/level_009.rb +20 -0
- data/towers/intermediate/level_001.rb +18 -0
- data/towers/intermediate/level_002.rb +20 -0
- data/towers/intermediate/level_003.rb +23 -0
- data/towers/intermediate/level_004.rb +24 -0
- data/towers/intermediate/level_005.rb +19 -0
- data/towers/intermediate/level_006.rb +24 -0
- metadata +167 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
class MockIO
|
2
|
+
class Timeout < Exception
|
3
|
+
end
|
4
|
+
|
5
|
+
def initialize(receiver = nil)
|
6
|
+
@buffer = ""
|
7
|
+
@receiver = receiver || MockIO.new(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def gets
|
11
|
+
1000.times do |n|
|
12
|
+
sleep 0.01 if n > 800 # throttle if it seems to be taking a while
|
13
|
+
unless @buffer.empty?
|
14
|
+
content = @buffer
|
15
|
+
@buffer = ""
|
16
|
+
return content
|
17
|
+
end
|
18
|
+
end
|
19
|
+
raise Timeout, "MockIO Timeout: No content was received for gets."
|
20
|
+
end
|
21
|
+
|
22
|
+
def gets_until_include(phrase)
|
23
|
+
content = gets
|
24
|
+
while !content.include?(phrase)
|
25
|
+
begin
|
26
|
+
content += gets
|
27
|
+
rescue Timeout
|
28
|
+
raise "Unable to find \"#{phrase}\" in \"#{content}\""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
content
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO make this thread safe
|
35
|
+
def puts(str)
|
36
|
+
@receiver << "#{str}\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
def print(str)
|
40
|
+
@receiver << str.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def <<(str)
|
44
|
+
@buffer << str
|
45
|
+
end
|
46
|
+
|
47
|
+
def start
|
48
|
+
main_thread = Thread.current
|
49
|
+
Thread.new do
|
50
|
+
begin
|
51
|
+
yield(@receiver)
|
52
|
+
rescue Exception => e
|
53
|
+
main_thread.raise(e)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Feature: Manage towers
|
2
|
+
In order extend ruby warrior
|
3
|
+
As a developer
|
4
|
+
I want to manage towers
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given no profile at "tmp"
|
8
|
+
|
9
|
+
Scenario: Add a tower
|
10
|
+
When I copy fixture "short-tower" to "towers/short"
|
11
|
+
And I run rubywarrior
|
12
|
+
And I answer "y" to "create one?"
|
13
|
+
Then I should see "short"
|
14
|
+
|
data/lib/ruby_warrior.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'ruby_warrior/core_additions'
|
6
|
+
|
7
|
+
require 'ruby_warrior/runner'
|
8
|
+
require 'ruby_warrior/game'
|
9
|
+
require 'ruby_warrior/profile'
|
10
|
+
require 'ruby_warrior/ui'
|
11
|
+
require 'ruby_warrior/config'
|
12
|
+
require 'ruby_warrior/player_generator'
|
13
|
+
require 'ruby_warrior/level_loader'
|
14
|
+
require 'ruby_warrior/tower'
|
15
|
+
require 'ruby_warrior/level'
|
16
|
+
require 'ruby_warrior/turn'
|
17
|
+
require 'ruby_warrior/floor'
|
18
|
+
require 'ruby_warrior/space'
|
19
|
+
require 'ruby_warrior/position'
|
20
|
+
|
21
|
+
require 'ruby_warrior/units/base'
|
22
|
+
require 'ruby_warrior/units/warrior'
|
23
|
+
require 'ruby_warrior/units/sludge'
|
24
|
+
require 'ruby_warrior/units/archer'
|
25
|
+
require 'ruby_warrior/units/thick_sludge'
|
26
|
+
require 'ruby_warrior/units/captive'
|
27
|
+
require 'ruby_warrior/units/wizard'
|
28
|
+
|
29
|
+
require 'ruby_warrior/abilities/base'
|
30
|
+
require 'ruby_warrior/abilities/walk'
|
31
|
+
require 'ruby_warrior/abilities/attack'
|
32
|
+
require 'ruby_warrior/abilities/feel'
|
33
|
+
require 'ruby_warrior/abilities/rest'
|
34
|
+
require 'ruby_warrior/abilities/health'
|
35
|
+
require 'ruby_warrior/abilities/look'
|
36
|
+
require 'ruby_warrior/abilities/shoot'
|
37
|
+
require 'ruby_warrior/abilities/rescue'
|
38
|
+
require 'ruby_warrior/abilities/pivot'
|
39
|
+
require 'ruby_warrior/abilities/distance'
|
40
|
+
require 'ruby_warrior/abilities/bind'
|
41
|
+
require 'ruby_warrior/abilities/listen'
|
42
|
+
require 'ruby_warrior/abilities/direction_of_stairs'
|
43
|
+
require 'ruby_warrior/abilities/direction_of'
|
44
|
+
require 'ruby_warrior/abilities/explode'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Attack < Base
|
4
|
+
def description
|
5
|
+
"Attack the unit in given direction (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
receiver = unit(direction)
|
10
|
+
if receiver
|
11
|
+
@unit.say "attacks #{receiver}"
|
12
|
+
if direction == :backward
|
13
|
+
power = (@unit.attack_power/2.0).ceil
|
14
|
+
else
|
15
|
+
power = @unit.attack_power
|
16
|
+
end
|
17
|
+
damage(receiver, power)
|
18
|
+
else
|
19
|
+
@unit.say "attacks and hits nothing"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Base
|
4
|
+
DIRECTIONS = {
|
5
|
+
:forward => [1, 0],
|
6
|
+
:right => [0, 1],
|
7
|
+
:backward => [-1, 0],
|
8
|
+
:left => [0, -1]
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize(unit)
|
12
|
+
@unit = unit
|
13
|
+
end
|
14
|
+
|
15
|
+
def offset(direction, amount = 1)
|
16
|
+
DIRECTIONS[direction].map { |i| i*amount }
|
17
|
+
end
|
18
|
+
|
19
|
+
def space(direction, amount = 1)
|
20
|
+
@unit.position.relative_space(*offset(direction, amount))
|
21
|
+
end
|
22
|
+
|
23
|
+
def unit(direction, amount = 1)
|
24
|
+
space(direction, amount).unit
|
25
|
+
end
|
26
|
+
|
27
|
+
def damage(receiver, amount)
|
28
|
+
receiver.take_damage(amount)
|
29
|
+
@unit.earn_points(receiver.max_health) unless receiver.alive?
|
30
|
+
end
|
31
|
+
|
32
|
+
def description
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Bind < Base
|
4
|
+
def description
|
5
|
+
"Bind unit in given direction to keep him from moving (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
receiver = unit(direction)
|
10
|
+
if receiver
|
11
|
+
@unit.say "binds #{receiver}"
|
12
|
+
receiver.bind
|
13
|
+
else
|
14
|
+
@unit.say "binds nothing"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class DirectionOf < Base
|
4
|
+
def description
|
5
|
+
"Pass a Space as an argument, and the direction (:left, :right, :forward, :backward) to that space will be returned."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(space)
|
9
|
+
@unit.position.relative_direction_of(space)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class DirectionOfStairs < Base
|
4
|
+
def description
|
5
|
+
"Returns the direction (:left, :right, :forward, :backward) the stairs are from your location."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
@unit.position.relative_direction_of_stairs
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Explode < Base
|
4
|
+
def description
|
5
|
+
"Kills you. You probably don't want to do this intentionally."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
if @unit.position
|
10
|
+
@unit.say "explodes"
|
11
|
+
@unit.take_damage(@unit.health)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Listen < Base
|
4
|
+
def description
|
5
|
+
"Returns an array of all spaces which have units in them."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
@unit.position.floor.units.map do |unit|
|
10
|
+
unit.position.space unless unit == @unit
|
11
|
+
end.compact
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Look < Base
|
4
|
+
def description
|
5
|
+
"Returns an array of Spaces in given direction (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
[1, 2, 3].map do |amount|
|
10
|
+
space(direction, amount)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Pivot < Base
|
4
|
+
ROTATION_DIRECTIONS = [:forward, :right, :backward, :left]
|
5
|
+
|
6
|
+
def description
|
7
|
+
"Rotate :left, :right or :backward (default)"
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform(direction = :backward)
|
11
|
+
@unit.position.rotate(ROTATION_DIRECTIONS.index(direction))
|
12
|
+
@unit.say "pivots #{direction}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Rescue < Base
|
4
|
+
def description
|
5
|
+
"Rescue a captive from his chains (earning 20 points) in given direction (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
if space(direction).captive?
|
10
|
+
recipient = unit(direction)
|
11
|
+
@unit.say "unbinds #{recipient}"
|
12
|
+
recipient.unbind
|
13
|
+
if recipient.kind_of? Units::Captive
|
14
|
+
recipient.position = nil
|
15
|
+
@unit.earn_points(20)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
@unit.say "rescues nothing"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Rest < Base
|
4
|
+
def description
|
5
|
+
"Gain 10% of max health back, but do nothing more."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
if @unit.health < @unit.max_health
|
10
|
+
amount = (@unit.max_health*0.1).round
|
11
|
+
amount = @unit.max_health-@unit.health if (@unit.health + amount) > @unit.max_health
|
12
|
+
@unit.health += amount
|
13
|
+
@unit.say "receives #{amount} health from resting, up to #{@unit.health} health"
|
14
|
+
else
|
15
|
+
@unit.say "is already fit as a fiddle"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Shoot < Base
|
4
|
+
def description
|
5
|
+
"Shoot your bow & arrow in given direction (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
receiver = multi_unit(direction, 1..3).compact.first
|
10
|
+
if receiver
|
11
|
+
@unit.say "shoots #{receiver}"
|
12
|
+
damage(receiver, @unit.shoot_power)
|
13
|
+
else
|
14
|
+
@unit.say "shoots and hits nothing"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def multi_unit(direction, range)
|
19
|
+
range.map { |n| unit(direction, n) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
module Abilities
|
3
|
+
class Walk < Base
|
4
|
+
def description
|
5
|
+
"Move in given direction (forward by default)."
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(direction = :forward)
|
9
|
+
if @unit.position
|
10
|
+
@unit.say "walks #{direction}"
|
11
|
+
if space(direction).empty?
|
12
|
+
@unit.position.move(*offset(direction))
|
13
|
+
else
|
14
|
+
@unit.say "bumps into #{space(direction)}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|