gemwarrior 0.2.0
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.
- 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
|