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,160 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class Game
|
|
3
|
+
|
|
4
|
+
def start
|
|
5
|
+
UI.puts "Welcome to Ruby Warrior"
|
|
6
|
+
|
|
7
|
+
if File.exists?(Config.path_prefix + '/.profile')
|
|
8
|
+
@profile = Profile.load(Config.path_prefix + '/.profile')
|
|
9
|
+
else
|
|
10
|
+
make_game_directory unless File.exists?(Config.path_prefix + '/ruby-warrior')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
if profile.epic?
|
|
14
|
+
UI.delay /= 2 if UI.delay # speed up UI since we're going to be doing a lot here
|
|
15
|
+
profile.current_epic_score = 0
|
|
16
|
+
playing = true
|
|
17
|
+
while playing
|
|
18
|
+
@current_level = @next_level = nil
|
|
19
|
+
profile.level_number += 1
|
|
20
|
+
playing = play_current_level
|
|
21
|
+
end
|
|
22
|
+
profile.save # saves the score for epic mode
|
|
23
|
+
else
|
|
24
|
+
if current_level.number.zero?
|
|
25
|
+
prepare_next_level
|
|
26
|
+
UI.puts "First level has been generated. See the ruby-warrior directory for instructions."
|
|
27
|
+
else
|
|
28
|
+
play_current_level
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def make_game_directory
|
|
34
|
+
if UI.ask("No ruby-warrior directory found, would you like to create one?")
|
|
35
|
+
Dir.mkdir(Config.path_prefix + '/ruby-warrior')
|
|
36
|
+
else
|
|
37
|
+
UI.puts "Unable to continue without directory."
|
|
38
|
+
exit
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def play_current_level
|
|
43
|
+
continue = true
|
|
44
|
+
current_level.load_player
|
|
45
|
+
UI.puts "Starting Level #{current_level.number}"
|
|
46
|
+
current_level.play
|
|
47
|
+
if current_level.passed?
|
|
48
|
+
if next_level.exists?
|
|
49
|
+
UI.puts "Success! You have found the stairs."
|
|
50
|
+
else
|
|
51
|
+
UI.puts "CONGRATULATIONS! You have climbed to the top of the tower and rescue the fair maiden Ruby."
|
|
52
|
+
continue = false
|
|
53
|
+
end
|
|
54
|
+
current_level.tally_points
|
|
55
|
+
request_next_level unless profile.epic?
|
|
56
|
+
else
|
|
57
|
+
continue = false
|
|
58
|
+
UI.puts "Sorry, you failed the level. Change your script and try again."
|
|
59
|
+
if current_level.clue && UI.ask("Would you like to read the additional clues for this level?")
|
|
60
|
+
UI.puts current_level.clue
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
continue
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def request_next_level
|
|
67
|
+
if (next_level.exists? ? UI.ask("Would you like to continue on to the next level?") : UI.ask("Would you like to continue on to epic mode?"))
|
|
68
|
+
if next_level.exists?
|
|
69
|
+
prepare_next_level
|
|
70
|
+
UI.puts "See the ruby-warrior directory for the next level README."
|
|
71
|
+
else
|
|
72
|
+
prepare_epic_mode
|
|
73
|
+
UI.puts "Run rubywarrior again to play epic mode."
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
UI.puts "Staying on current level. Try to earn more points next time."
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def prepare_next_level
|
|
81
|
+
next_level.generate_player_files
|
|
82
|
+
profile.level_number += 1
|
|
83
|
+
profile.save # this saves score and new abilities too
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def prepare_epic_mode
|
|
87
|
+
profile.enable_epic_mode
|
|
88
|
+
profile.level_number = 0
|
|
89
|
+
profile.save # this saves score too
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# profiles
|
|
94
|
+
|
|
95
|
+
def profiles
|
|
96
|
+
profile_paths.map { |profile| Profile.load(profile) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def profile_paths
|
|
100
|
+
Dir[Config.path_prefix + '/ruby-warrior/**/.profile']
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def profile
|
|
104
|
+
@profile ||= choose_profile
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def new_profile
|
|
108
|
+
profile = Profile.new
|
|
109
|
+
profile.tower_path = UI.choose('tower', towers).path
|
|
110
|
+
profile.warrior_name = UI.request('Enter a name for your warrior: ')
|
|
111
|
+
profile
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# towers
|
|
116
|
+
|
|
117
|
+
def towers
|
|
118
|
+
tower_paths.map { |path| Tower.new(path) }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def tower_paths
|
|
122
|
+
Dir[File.expand_path(File.dirname(__FILE__) + '/../../towers/*')]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# levels
|
|
127
|
+
|
|
128
|
+
def current_level
|
|
129
|
+
@current_level ||= profile.current_level
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def next_level
|
|
133
|
+
@next_level ||= profile.next_level
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
def choose_profile # REFACTORME
|
|
140
|
+
profile = UI.choose('profile', profiles + [[:new, 'New Profile']])
|
|
141
|
+
if profile == :new
|
|
142
|
+
profile = new_profile
|
|
143
|
+
if profiles.any? { |p| p.player_path == profile.player_path }
|
|
144
|
+
if UI.ask("Are you sure you want to replace your existing profile for this tower?")
|
|
145
|
+
UI.puts("Replacing existing profile.")
|
|
146
|
+
profile
|
|
147
|
+
else
|
|
148
|
+
UI.puts("Not replacing profile.")
|
|
149
|
+
exit
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
profile
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
profile
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class Level
|
|
3
|
+
attr_reader :profile, :number
|
|
4
|
+
attr_accessor :description, :tip, :clue, :warrior, :floor, :time_bonus
|
|
5
|
+
|
|
6
|
+
def initialize(profile, number)
|
|
7
|
+
@profile = profile
|
|
8
|
+
@number = number
|
|
9
|
+
@time_bonus = 0
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def player_path
|
|
13
|
+
@profile.player_path
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def load_path
|
|
17
|
+
@profile.tower_path + "/level_" + @number.to_s.rjust(3, '0') + ".rb"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load_level
|
|
21
|
+
LevelLoader.new(self).instance_eval(File.read(load_path))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def load_player
|
|
25
|
+
$: << player_path
|
|
26
|
+
load 'player.rb'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def generate_player_files
|
|
30
|
+
load_level
|
|
31
|
+
PlayerGenerator.new(self).generate
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def play(turns = 1000)
|
|
35
|
+
load_level
|
|
36
|
+
turns.times do |n|
|
|
37
|
+
return if passed? || failed?
|
|
38
|
+
UI.puts "- turn #{n+1} -"
|
|
39
|
+
UI.print @floor.to_map
|
|
40
|
+
@floor.units.each { |unit| unit.prepare_turn }
|
|
41
|
+
@floor.units.each { |unit| unit.perform_turn }
|
|
42
|
+
yield if block_given?
|
|
43
|
+
@time_bonus -= 1 if @time_bonus > 0
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def tally_points
|
|
48
|
+
score = 0
|
|
49
|
+
|
|
50
|
+
UI.puts "Level Score: #{warrior.score}"
|
|
51
|
+
score += warrior.score
|
|
52
|
+
|
|
53
|
+
UI.puts "Time Bonus: #{time_bonus}"
|
|
54
|
+
score += @time_bonus
|
|
55
|
+
|
|
56
|
+
if floor.other_units.empty?
|
|
57
|
+
UI.puts "Clear Bonus: #{clear_bonus}"
|
|
58
|
+
score += clear_bonus
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if @profile.epic?
|
|
62
|
+
@profile.current_epic_score += score
|
|
63
|
+
UI.puts "Total Score: #{@profile.current_epic_score}"
|
|
64
|
+
else
|
|
65
|
+
@profile.score += score
|
|
66
|
+
@profile.abilities = warrior.abilities.keys
|
|
67
|
+
UI.puts "Total Score: #{@profile.score}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def clear_bonus
|
|
72
|
+
((warrior.score + time_bonus)*0.2).round
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def passed?
|
|
76
|
+
@floor.stairs_space.warrior?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def failed?
|
|
80
|
+
!@floor.units.include?(warrior)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def exists?
|
|
84
|
+
File.exist? load_path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def setup_warrior(warrior)
|
|
88
|
+
@warrior = warrior
|
|
89
|
+
@warrior.add_abilities(*profile.abilities)
|
|
90
|
+
@warrior.name = profile.warrior_name
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class LevelLoader
|
|
3
|
+
def initialize(level)
|
|
4
|
+
@floor = RubyWarrior::Floor.new
|
|
5
|
+
@level = level
|
|
6
|
+
@level.floor = @floor
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def description(desc)
|
|
10
|
+
@level.description = desc
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def tip(tip)
|
|
14
|
+
@level.tip = tip
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def clue(clue)
|
|
18
|
+
@level.clue = clue
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def time_bonus(bonus)
|
|
22
|
+
@level.time_bonus = bonus
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def size(width, height)
|
|
26
|
+
@floor.width = width
|
|
27
|
+
@floor.height = height
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def stairs(x, y)
|
|
31
|
+
@floor.place_stairs(x, y)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def unit(unit, x, y, facing = :north)
|
|
35
|
+
unit = unit_to_constant(unit).new unless unit.kind_of? Units::Base
|
|
36
|
+
@floor.add(unit, x, y, facing)
|
|
37
|
+
yield unit if block_given?
|
|
38
|
+
unit
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def warrior(*args, &block)
|
|
42
|
+
@level.setup_warrior unit(Units::Warrior.new, *args, &block)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def unit_to_constant(name)
|
|
48
|
+
camel = name.to_s.split('_').map { |s| s.capitalize }.join
|
|
49
|
+
eval("Units::#{camel}")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'erb'
|
|
4
|
+
|
|
5
|
+
module RubyWarrior
|
|
6
|
+
class PlayerGenerator
|
|
7
|
+
def initialize(level)
|
|
8
|
+
@level = level
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def level
|
|
12
|
+
@level
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def previous_level
|
|
16
|
+
@previous_level ||= Level.new(level.profile, level.number-1)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# TODO refactor and test this method
|
|
20
|
+
def generate
|
|
21
|
+
if level.number == 1
|
|
22
|
+
FileUtils.mkdir_p(level.player_path)
|
|
23
|
+
FileUtils.cp(templates_path + '/player.rb', level.player_path)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
File.open(level.player_path + '/README', 'w') do |f|
|
|
27
|
+
f.write read_template(templates_path + '/README.erb')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def templates_path
|
|
32
|
+
File.expand_path(File.dirname(__FILE__) + "/../../templates")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def read_template(path)
|
|
38
|
+
ERB.new(File.read(path), nil, '-').result(binding)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module RubyWarrior
|
|
2
|
+
class Position
|
|
3
|
+
attr_reader :floor
|
|
4
|
+
DIRECTIONS = [:north, :east, :south, :west]
|
|
5
|
+
RELATIVE_DIRECTIONS = [:forward, :right, :backward, :left]
|
|
6
|
+
|
|
7
|
+
def initialize(floor, x, y, direction = nil)
|
|
8
|
+
@floor = floor
|
|
9
|
+
@x = x
|
|
10
|
+
@y = y
|
|
11
|
+
@direction_index = DIRECTIONS.index(direction || :north)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def at?(x, y)
|
|
15
|
+
@x == x && @y == y
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def direction
|
|
19
|
+
DIRECTIONS[@direction_index]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def rotate(amount)
|
|
23
|
+
@direction_index += amount
|
|
24
|
+
@direction_index -= 4 while @direction_index > 3
|
|
25
|
+
@direction_index += 4 while @direction_index < 0
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def relative_space(forward, right = 0)
|
|
29
|
+
@floor.space(*translate_offset(forward, right))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def space
|
|
33
|
+
@floor.space(@x, @y)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def move(forward, right = 0)
|
|
37
|
+
@x, @y = *translate_offset(forward, right)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def distance_from_stairs
|
|
41
|
+
stairs_x, stairs_y = *@floor.stairs_location
|
|
42
|
+
(@x - stairs_x).abs + (@y - stairs_y).abs
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def relative_direction_of_stairs
|
|
46
|
+
relative_direction_of(@floor.stairs_space)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def relative_direction_of(space)
|
|
50
|
+
relative_direction(direction_of(space))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def direction_of(space)
|
|
54
|
+
space_x, space_y = *space.location
|
|
55
|
+
if (@x - space_x).abs > (@y - space_y).abs
|
|
56
|
+
space_x > @x ? :east : :west
|
|
57
|
+
else
|
|
58
|
+
space_y > @y ? :south : :north
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def relative_direction(direction)
|
|
63
|
+
offset = DIRECTIONS.index(direction) - @direction_index
|
|
64
|
+
offset -= 4 while offset > 3
|
|
65
|
+
offset += 4 while offset < 0
|
|
66
|
+
RELATIVE_DIRECTIONS[offset]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def translate_offset(forward, right)
|
|
72
|
+
case direction
|
|
73
|
+
when :north then [@x + right, @y - forward]
|
|
74
|
+
when :east then [@x + forward, @y + right]
|
|
75
|
+
when :south then [@x - right, @y + forward]
|
|
76
|
+
when :west then [@x - forward, @y - right]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
|
|
3
|
+
module RubyWarrior
|
|
4
|
+
class Profile
|
|
5
|
+
attr_accessor :score, :epic_score, :current_epic_score, :abilities, :level_number, :tower_path, :warrior_name, :player_path
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@tower_path = nil
|
|
9
|
+
@warrior_name = nil
|
|
10
|
+
@score = 0
|
|
11
|
+
@current_epic_score = 0
|
|
12
|
+
@epic_score = 0
|
|
13
|
+
@abilities = []
|
|
14
|
+
@level_number = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def encode
|
|
18
|
+
Base64.encode64(Marshal.dump(self))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def save
|
|
22
|
+
update_epic_score
|
|
23
|
+
@level_number = 0 if epic?
|
|
24
|
+
File.open(player_path + '/.profile', 'w') { |f| f.write(encode) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.decode(str)
|
|
28
|
+
Marshal.load(Base64.decode64(str))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.load(path)
|
|
32
|
+
player = decode(File.read(path))
|
|
33
|
+
player.player_path = File.dirname(path)
|
|
34
|
+
player
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def player_path
|
|
38
|
+
@player_path || Config.path_prefix + "/ruby-warrior/#{directory_name}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def directory_name
|
|
42
|
+
[warrior_name.downcase.gsub(/[^a-z0-9]+/, '-'), tower.name].join('-')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
if epic?
|
|
47
|
+
[warrior_name, tower.name, "first score #{score}", "epic score #{epic_score}"].join(' - ')
|
|
48
|
+
else
|
|
49
|
+
[warrior_name, tower.name, "level #{level_number}", "score #{score}"].join(' - ')
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def tower
|
|
54
|
+
Tower.new(@tower_path)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def current_level
|
|
58
|
+
Level.new(self, level_number)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def next_level
|
|
62
|
+
Level.new(self, level_number+1)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_abilities(*abilities)
|
|
66
|
+
@abilities += abilities
|
|
67
|
+
@abilities.uniq!
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def enable_epic_mode
|
|
71
|
+
@epic = true
|
|
72
|
+
@epic_score ||= 0
|
|
73
|
+
@current_epic_score ||= 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def epic?
|
|
77
|
+
@epic
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def update_epic_score
|
|
81
|
+
if @current_epic_score > @epic_score
|
|
82
|
+
@epic_score = @current_epic_score
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|