gemwarrior 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +1 -0
- data/bin/gemwarrior +29 -0
- data/gemwarrior.gemspec +33 -0
- data/lib/gemwarrior.rb +9 -0
- data/lib/gemwarrior/constants.rb +155 -0
- data/lib/gemwarrior/creature.rb +47 -0
- data/lib/gemwarrior/evaluator.rb +128 -0
- data/lib/gemwarrior/game.rb +42 -0
- data/lib/gemwarrior/inventory.rb +61 -0
- data/lib/gemwarrior/item.rb +28 -0
- data/lib/gemwarrior/location.rb +101 -0
- data/lib/gemwarrior/monster.rb +48 -0
- data/lib/gemwarrior/player.rb +185 -0
- data/lib/gemwarrior/repl.rb +92 -0
- data/lib/gemwarrior/version.rb +6 -0
- data/lib/gemwarrior/world.rb +269 -0
- data/spec/rubywarrior_spec.rb +11 -0
- data/spec/spec_helper.rb +2 -0
- metadata +158 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# lib/gemwarrior/game.rb
|
2
|
+
# Main launching point for Gem Warrior
|
3
|
+
|
4
|
+
require_relative 'constants'
|
5
|
+
require_relative 'world'
|
6
|
+
require_relative 'player'
|
7
|
+
|
8
|
+
require_relative 'repl'
|
9
|
+
require_relative 'evaluator'
|
10
|
+
|
11
|
+
module Gemwarrior
|
12
|
+
class Game
|
13
|
+
include AttributePools
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
# create new world and player
|
17
|
+
@world = World.new
|
18
|
+
@player = Player.new(
|
19
|
+
PLYR_LEVEL_DEFAULT,
|
20
|
+
PLYR_XP_DEFAULT,
|
21
|
+
PLYR_HP_CUR_DEFAULT,
|
22
|
+
PLYR_HP_MAX_DEFAULT,
|
23
|
+
PLYR_STAM_CUR_DEFAULT,
|
24
|
+
PLYR_STAM_MAX_DEFAULT,
|
25
|
+
PLYR_ATK_LO_DEFAULT,
|
26
|
+
PLYR_ATK_HI_DEFAULT,
|
27
|
+
Inventory.new,
|
28
|
+
PLYR_ROX_DEFAULT,
|
29
|
+
@world.loc_by_id(0)
|
30
|
+
)
|
31
|
+
@world.player = @player
|
32
|
+
|
33
|
+
# create the console
|
34
|
+
@eval = Evaluator.new(@world)
|
35
|
+
@repl = Repl.new(@world, @eval)
|
36
|
+
|
37
|
+
# enter Jool!
|
38
|
+
@repl.start('look')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# lib/gemwarrior/inventory.rb
|
2
|
+
# Collection of items a creature possesses
|
3
|
+
|
4
|
+
module Gemwarrior
|
5
|
+
class Inventory
|
6
|
+
include Errors
|
7
|
+
|
8
|
+
def initialize(inventory = [])
|
9
|
+
@inventory = inventory
|
10
|
+
end
|
11
|
+
|
12
|
+
def list_contents
|
13
|
+
contents_text = "You check your inventory"
|
14
|
+
if @inventory.empty?
|
15
|
+
return contents_text << ERROR_INVENTORY_EMPTY
|
16
|
+
else
|
17
|
+
@item_names = []
|
18
|
+
@inventory.each do |i|
|
19
|
+
@item_names.push(i.name)
|
20
|
+
end
|
21
|
+
return contents_text << ": #{@inventory.map(&:name).join ', '}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def describe_item(item_name)
|
26
|
+
if @inventory.map(&:name).include?(item_name)
|
27
|
+
@inventory.each do |i|
|
28
|
+
if i.name.eql?(item_name)
|
29
|
+
return "#{i.description}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
else
|
33
|
+
ERROR_ITEM_INVENTORY_INVALID
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_item(cur_loc, item_name)
|
38
|
+
cur_loc.items.each do |i|
|
39
|
+
if i.name.eql?(item_name)
|
40
|
+
if i.takeable
|
41
|
+
@inventory.push(i)
|
42
|
+
cur_loc.remove_item_from_location(item_name)
|
43
|
+
return "Added #{item_name} to your increasing collection of bits of tid.\n"
|
44
|
+
else
|
45
|
+
ERROR_TAKE_ITEM_UNTAKEABLE
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
ERROR_TAKE_ITEM_INVALID
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_item(item_name)
|
53
|
+
if inventory.include?(item_name)
|
54
|
+
@inventory.delete(item_name)
|
55
|
+
puts "#{item} has been thrown on the ground, but far out of reach, and you're much too lazy to go get it now, so it's as good as gone.\n"
|
56
|
+
else
|
57
|
+
puts ERROR_INVENTORY_REMOVE_INVALID
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# lib/gemwarrior/item.rb
|
2
|
+
# Item base class
|
3
|
+
|
4
|
+
require_relative 'constants'
|
5
|
+
|
6
|
+
module Gemwarrior
|
7
|
+
class Item
|
8
|
+
include Entities::Items
|
9
|
+
|
10
|
+
attr_reader :id, :name, :description, :takeable
|
11
|
+
|
12
|
+
def initialize(
|
13
|
+
id,
|
14
|
+
name = ITEM_NAME_DEFAULT,
|
15
|
+
description = ITEM_DESC_DEFAULT,
|
16
|
+
takeable
|
17
|
+
)
|
18
|
+
@id = id
|
19
|
+
@name = name
|
20
|
+
@description = description
|
21
|
+
@takeable = takeable
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_takeable?
|
25
|
+
@takeable
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# lib/gemwarrior/location.rb
|
2
|
+
# Place in the game
|
3
|
+
|
4
|
+
require 'matrext'
|
5
|
+
|
6
|
+
require_relative 'constants'
|
7
|
+
|
8
|
+
module Gemwarrior
|
9
|
+
class Location
|
10
|
+
include Errors
|
11
|
+
|
12
|
+
attr_reader :id, :name, :description, :locs_connected, :items
|
13
|
+
|
14
|
+
def initialize(id, name, description, locs_connected, danger_level, items, monsters_available)
|
15
|
+
@id = id
|
16
|
+
@name = name
|
17
|
+
@description = description
|
18
|
+
@locs_connected = locs_connected
|
19
|
+
@danger_level = danger_level
|
20
|
+
@items = items
|
21
|
+
@monsters_available = monsters_available
|
22
|
+
@monsters_abounding = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def describe
|
26
|
+
desc_text = ""
|
27
|
+
desc_text << "[ #{@name} ]\n"
|
28
|
+
desc_text << @description
|
29
|
+
populate_monsters
|
30
|
+
unless list_items.nil?
|
31
|
+
desc_text << list_items
|
32
|
+
end
|
33
|
+
unless list_monsters.nil?
|
34
|
+
desc_text << list_monsters
|
35
|
+
end
|
36
|
+
return desc_text
|
37
|
+
end
|
38
|
+
|
39
|
+
def describe_item(item_name)
|
40
|
+
@item_names = []
|
41
|
+
@items.each do |i|
|
42
|
+
@item_names.push(i.name)
|
43
|
+
end
|
44
|
+
|
45
|
+
if @item_names.include?(item_name)
|
46
|
+
@items.each do |i|
|
47
|
+
if i.name.eql?(item_name)
|
48
|
+
puts "#{i.description}"
|
49
|
+
return
|
50
|
+
end
|
51
|
+
end
|
52
|
+
else
|
53
|
+
puts ERROR_ITEM_LOC_INVALID
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def list_items
|
58
|
+
return "\n >> Shiny object(s): #{@items.map(&:name).join(', ')}" if @items.length > 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def list_monsters
|
62
|
+
return "\n >> Monster(s) abound: #{@monsters_abounding.map(&:name).join(', ')}" if @monsters_abounding.length > 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def remove_item_from_location(item_name)
|
66
|
+
@items.each do |i|
|
67
|
+
if i.name.eql?(item_name)
|
68
|
+
@items.delete_at(@items.find_index(item_name).to_i)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_monster?
|
74
|
+
found = false
|
75
|
+
unless @danger_level.eql?(:none)
|
76
|
+
max = DANGER_LEVEL[@danger_level]
|
77
|
+
trigger_values = 0..max
|
78
|
+
actual_value = rand(1..100)
|
79
|
+
|
80
|
+
if trigger_values.include?(actual_value)
|
81
|
+
found = true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return found
|
85
|
+
end
|
86
|
+
|
87
|
+
def populate_monsters
|
88
|
+
if has_monster?
|
89
|
+
@monsters_abounding = []
|
90
|
+
return @monsters_abounding.push(@monsters_available[rand(0..@monsters_available.length-1)])
|
91
|
+
else
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_loc_to_the?(direction)
|
97
|
+
@locs_connected[direction.to_sym]
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# lib/gemwarrior/monster.rb
|
2
|
+
# Monster creature
|
3
|
+
|
4
|
+
require_relative 'constants'
|
5
|
+
require_relative 'inventory'
|
6
|
+
require_relative 'creature'
|
7
|
+
|
8
|
+
module Gemwarrior
|
9
|
+
class Monster < Creature
|
10
|
+
include Entities::Monsters
|
11
|
+
|
12
|
+
attr_reader :name
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
id,
|
16
|
+
name = MOB_NAME_DEFAULT,
|
17
|
+
description = MOB_DESC_FAULT,
|
18
|
+
face = '',
|
19
|
+
hands ='',
|
20
|
+
mood = '',
|
21
|
+
level = '',
|
22
|
+
hp_cur = 5,
|
23
|
+
hp_max = 5,
|
24
|
+
atk_lo = 1,
|
25
|
+
atk_hi = 2,
|
26
|
+
inventory = Inventory.new,
|
27
|
+
rox = 1
|
28
|
+
)
|
29
|
+
@id = id
|
30
|
+
@name = name
|
31
|
+
@description = description
|
32
|
+
@face = face
|
33
|
+
@hands = hands
|
34
|
+
@mood = mood
|
35
|
+
|
36
|
+
@level = rand(level)
|
37
|
+
@hp_cur = hp_cur
|
38
|
+
@hp_max = hp_max
|
39
|
+
|
40
|
+
@atk_lo = atk_lo
|
41
|
+
@atk_hi = atk_hi
|
42
|
+
|
43
|
+
@inventory = inventory
|
44
|
+
@rox = rox
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# lib/gemwarrior/player.rb
|
2
|
+
# Player creature
|
3
|
+
|
4
|
+
require_relative 'constants'
|
5
|
+
require_relative 'inventory'
|
6
|
+
require_relative 'creature'
|
7
|
+
|
8
|
+
module Gemwarrior
|
9
|
+
class Player < Creature
|
10
|
+
private
|
11
|
+
|
12
|
+
def print_traveling_text
|
13
|
+
loc = Thread.new do
|
14
|
+
print "*** "
|
15
|
+
print "#{Matrext::process({ :phrase => "traveling...", :sl => true, :speed => :fast })}"
|
16
|
+
print " ***\n"
|
17
|
+
end
|
18
|
+
loc.join
|
19
|
+
end
|
20
|
+
|
21
|
+
def print_char_pic
|
22
|
+
char_pic = ""
|
23
|
+
char_pic << "**********\n"
|
24
|
+
char_pic << "* () *\n"
|
25
|
+
char_pic << "* \\-||-/ *\n"
|
26
|
+
char_pic << "* -- *\n"
|
27
|
+
char_pic << "* || *\n"
|
28
|
+
char_pic << "* _||_ *\n"
|
29
|
+
char_pic << "**********\n"
|
30
|
+
puts char_pic
|
31
|
+
end
|
32
|
+
|
33
|
+
include AttributePools
|
34
|
+
include Errors
|
35
|
+
|
36
|
+
def generate_name
|
37
|
+
name = []
|
38
|
+
letter_max = rand(5..10)
|
39
|
+
name[0] = CHAR_UPPER_POOL[rand(0..25)]
|
40
|
+
name[1] = CHAR_LOWER_VOWEL_POOL[rand(0..5)]
|
41
|
+
2.upto(letter_max) do |i|
|
42
|
+
name[i] = CHAR_LOWER_POOL[rand(0..25)]
|
43
|
+
end
|
44
|
+
return name.join
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_desc
|
48
|
+
PLYR_DESC_DEFAULT
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_face
|
52
|
+
FACE_DESC[rand(0..FACE_DESC.length-1)]
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_hands
|
56
|
+
HANDS_DESC[rand(0..HANDS_DESC.length-1)]
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_mood
|
60
|
+
MOOD_DESC[rand(0..MOOD_DESC.length-1)]
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_player_identity
|
64
|
+
@name = generate_name
|
65
|
+
@description = generate_desc
|
66
|
+
@face = generate_face
|
67
|
+
@hands = generate_hands
|
68
|
+
@mood = generate_mood
|
69
|
+
end
|
70
|
+
|
71
|
+
public
|
72
|
+
|
73
|
+
attr_reader :level, :xp, :cur_loc, :hp_cur, :hp_max, :stam_cur, :stam_max, :inventory
|
74
|
+
attr_accessor :name
|
75
|
+
|
76
|
+
def initialize(
|
77
|
+
level = PLYR_LEVEL_DEFAULT,
|
78
|
+
xp = PLYR_XP_DEFAULT,
|
79
|
+
hp_cur = PLYR_HP_CUR_DEFAULT,
|
80
|
+
hp_max = PLYR_HP_MAX_DEFAULT,
|
81
|
+
stam_cur = PLYR_STAM_CUR_DEFAULT,
|
82
|
+
stam_max = PLYR_STAM_MAX_DEFAULT,
|
83
|
+
atk_lo = PLYR_ATK_LO_DEFAULT,
|
84
|
+
atk_hi = PLYR_ATK_HI_DEFAULT,
|
85
|
+
inventory = Inventory.new,
|
86
|
+
rox = PLYR_ROX_DEFAULT,
|
87
|
+
cur_loc
|
88
|
+
)
|
89
|
+
# generates name, desc, face, hands, mood text
|
90
|
+
generate_player_identity
|
91
|
+
|
92
|
+
@level = level
|
93
|
+
@xp = xp
|
94
|
+
|
95
|
+
@hp_cur = hp_cur
|
96
|
+
@hp_max = hp_max
|
97
|
+
@stam_cur = stam_cur
|
98
|
+
@stam_max = stam_max
|
99
|
+
|
100
|
+
@atk_lo = atk_lo
|
101
|
+
@atk_hi = atk_hi
|
102
|
+
|
103
|
+
@inventory = inventory
|
104
|
+
@rox = rox
|
105
|
+
|
106
|
+
@cur_loc = cur_loc
|
107
|
+
end
|
108
|
+
|
109
|
+
def check_self
|
110
|
+
print_char_pic
|
111
|
+
return "You check yourself. Currently breathing, wearing clothing, and with a few specific characteristics: face is #{@face}, hands are #{@hands}, and general mood is #{@mood}.\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
def rest
|
115
|
+
hours = rand(1..23)
|
116
|
+
minutes = rand(1..59)
|
117
|
+
seconds = rand(1..59)
|
118
|
+
|
119
|
+
hours_text = hours == 1 ? "hour" : "hours"
|
120
|
+
mins_text = minutes == 1 ? "minute" : "minutes"
|
121
|
+
secs_text = seconds == 1 ? "second" : "seconds"
|
122
|
+
|
123
|
+
return "You lie down somewhere quasi-flat and after a few moments, due to extreme exhaustion, you fall into a deep slumber. Approximately #{hours} #{hours_text}, #{minutes} #{mins_text}, and #{seconds} #{secs_text} later, you wake up with a start, look around you, notice nothing in particular, and get back up, ready to go again."
|
124
|
+
end
|
125
|
+
|
126
|
+
def stamina_dec
|
127
|
+
@stam_cur = @stam_cur - 1
|
128
|
+
end
|
129
|
+
|
130
|
+
def modify_name
|
131
|
+
print "Enter new name: "
|
132
|
+
name = gets.chomp!
|
133
|
+
if name.length < 3 || name.length > 10
|
134
|
+
return "'#{name}' is an invalid length. Make it between 3 and 10 characters, please."
|
135
|
+
else
|
136
|
+
new_name = ""
|
137
|
+
new_name << name[0].upcase
|
138
|
+
new_name << name[1..name.length-1].downcase
|
139
|
+
@name = new_name
|
140
|
+
return "New name, '#{new_name}', accepted."
|
141
|
+
end
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
|
145
|
+
def list_inventory
|
146
|
+
@inventory.list_contents
|
147
|
+
end
|
148
|
+
|
149
|
+
def loc_by_id(locations, id)
|
150
|
+
locations.each do |loc|
|
151
|
+
if loc.id.to_i.equal? id
|
152
|
+
return loc
|
153
|
+
end
|
154
|
+
end
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def can_move?(direction)
|
159
|
+
@cur_loc.has_loc_to_the?(direction)
|
160
|
+
end
|
161
|
+
|
162
|
+
def go(locations, direction)
|
163
|
+
case direction
|
164
|
+
when "n"
|
165
|
+
direction = "north"
|
166
|
+
when "e"
|
167
|
+
direction = "east"
|
168
|
+
when "s"
|
169
|
+
direction = "south"
|
170
|
+
when "w"
|
171
|
+
direction = "west"
|
172
|
+
end
|
173
|
+
unless direction.nil?
|
174
|
+
if can_move?(direction)
|
175
|
+
new_loc_id = @cur_loc.locs_connected[direction.to_sym]
|
176
|
+
@cur_loc = loc_by_id(locations, new_loc_id)
|
177
|
+
print_traveling_text
|
178
|
+
@cur_loc.describe
|
179
|
+
else
|
180
|
+
ERROR_GO_DIR_INVALID
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|