karnowski-ruby-warrior 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,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,41 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'ruby_warrior/core_additions'
|
4
|
+
|
5
|
+
require 'ruby_warrior/game'
|
6
|
+
require 'ruby_warrior/profile'
|
7
|
+
require 'ruby_warrior/ui'
|
8
|
+
require 'ruby_warrior/config'
|
9
|
+
require 'ruby_warrior/player_generator'
|
10
|
+
require 'ruby_warrior/level_loader'
|
11
|
+
require 'ruby_warrior/tower'
|
12
|
+
require 'ruby_warrior/level'
|
13
|
+
require 'ruby_warrior/turn'
|
14
|
+
require 'ruby_warrior/floor'
|
15
|
+
require 'ruby_warrior/space'
|
16
|
+
require 'ruby_warrior/position'
|
17
|
+
|
18
|
+
require 'ruby_warrior/units/base'
|
19
|
+
require 'ruby_warrior/units/warrior'
|
20
|
+
require 'ruby_warrior/units/sludge'
|
21
|
+
require 'ruby_warrior/units/archer'
|
22
|
+
require 'ruby_warrior/units/thick_sludge'
|
23
|
+
require 'ruby_warrior/units/captive'
|
24
|
+
require 'ruby_warrior/units/wizard'
|
25
|
+
|
26
|
+
require 'ruby_warrior/abilities/base'
|
27
|
+
require 'ruby_warrior/abilities/walk'
|
28
|
+
require 'ruby_warrior/abilities/attack'
|
29
|
+
require 'ruby_warrior/abilities/feel'
|
30
|
+
require 'ruby_warrior/abilities/rest'
|
31
|
+
require 'ruby_warrior/abilities/health'
|
32
|
+
require 'ruby_warrior/abilities/look'
|
33
|
+
require 'ruby_warrior/abilities/shoot'
|
34
|
+
require 'ruby_warrior/abilities/rescue'
|
35
|
+
require 'ruby_warrior/abilities/pivot'
|
36
|
+
require 'ruby_warrior/abilities/distance'
|
37
|
+
require 'ruby_warrior/abilities/bind'
|
38
|
+
require 'ruby_warrior/abilities/listen'
|
39
|
+
require 'ruby_warrior/abilities/direction_of_stairs'
|
40
|
+
require 'ruby_warrior/abilities/direction_of'
|
41
|
+
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
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class String
|
2
|
+
def camelize
|
3
|
+
gsub(/(?:^|_)(.)/) { $1.upcase }
|
4
|
+
end
|
5
|
+
|
6
|
+
def constantize
|
7
|
+
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
|
8
|
+
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
9
|
+
end
|
10
|
+
|
11
|
+
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
12
|
+
end
|
13
|
+
|
14
|
+
def underscore
|
15
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def humanize
|
19
|
+
gsub(/_/, " ").capitalize
|
20
|
+
end
|
21
|
+
|
22
|
+
def titleize
|
23
|
+
underscore.humanize.gsub(/\b('?[a-z])/) { $1.capitalize }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module RubyWarrior
|
2
|
+
class Floor
|
3
|
+
attr_accessor :width, :height, :grid
|
4
|
+
attr_reader :stairs_location
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@width = 0
|
8
|
+
@height = 0
|
9
|
+
@units = []
|
10
|
+
@stairs_location = [-1, -1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(unit, x, y, direction = nil)
|
14
|
+
@units << unit
|
15
|
+
unit.position = Position.new(self, x, y, direction)
|
16
|
+
end
|
17
|
+
|
18
|
+
def place_stairs(x, y)
|
19
|
+
@stairs_location = [x, y]
|
20
|
+
end
|
21
|
+
|
22
|
+
def stairs_space
|
23
|
+
space(*@stairs_location)
|
24
|
+
end
|
25
|
+
|
26
|
+
def units
|
27
|
+
@units.reject { |u| u.position.nil? }
|
28
|
+
end
|
29
|
+
|
30
|
+
def other_units
|
31
|
+
units.reject { |u| u.kind_of? Units::Warrior }
|
32
|
+
end
|
33
|
+
|
34
|
+
def get(x, y)
|
35
|
+
units.detect do |unit|
|
36
|
+
unit.position.at?(x, y)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def space(x, y)
|
41
|
+
Space.new(self, x, y)
|
42
|
+
end
|
43
|
+
|
44
|
+
def out_of_bounds?(x, y)
|
45
|
+
x < 0 || y < 0 || x > @width-1 || y > @height-1
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_map
|
49
|
+
rows = []
|
50
|
+
rows << " " + ("-" * @width)
|
51
|
+
@height.times do |y|
|
52
|
+
row = "|"
|
53
|
+
@width.times do |x|
|
54
|
+
row << space(x, y).to_map
|
55
|
+
end
|
56
|
+
row << "|"
|
57
|
+
rows << row
|
58
|
+
end
|
59
|
+
rows << " " + ("-" * @width)
|
60
|
+
rows.join("\n") + "\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
def unique_units
|
64
|
+
unique_units = []
|
65
|
+
units.each do |unit|
|
66
|
+
unique_units << unit unless unique_units.map { |u| u.class }.include?(unit.class)
|
67
|
+
end
|
68
|
+
unique_units
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|