dungeonsofheck 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +44 -0
- data/dungeonsofheck.gemspec +14 -0
- data/lib/Gemfile.lock +62 -0
- data/lib/actions.rb +97 -0
- data/lib/battle.rb +53 -0
- data/lib/doge.txt +35 -0
- data/lib/dungeonsofheck.rb +25 -0
- data/lib/main.rb +248 -0
- data/spec/actions_spec.rb +15 -0
- data/spec/main_spec.rb +23 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3384c1790589b6ee3953103b5c6f9ce2bda7d5314df8e2e641743420bd97737d
|
4
|
+
data.tar.gz: 6956c387947b7f6ed155ef488f47c307a398cccb350fc7ca04be2eab31eccb16
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8db36a71d96d214aeb799cc188213f333b49947e65d8efd62f82adfb660935f33a5fa31e3a9798812f5faa82fd8d108d3af76c069e526fce6a7bf9c1ea39dbdf
|
7
|
+
data.tar.gz: 5087028fcaca29848ef66f351f5be88f10ac14aec5d79886d725d403f651081e560c3c63e0599d7ac8506fa4e08839733b0eab5bea80484ac99b2abbe74937b0
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# DungeonsOfHeck
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/DungeonsOfHeck`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'DungeonsOfHeck'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install DungeonsOfHeck
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/DungeonsOfHeck. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/DungeonsOfHeck/blob/master/CODE_OF_CONDUCT.md).
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
41
|
+
|
42
|
+
## Code of Conduct
|
43
|
+
|
44
|
+
Everyone interacting in the DungeonsOfHeck project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/DungeonsOfHeck/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'dungeonsofheck'
|
3
|
+
s.version = '1.0'
|
4
|
+
s.license = 'MIT'
|
5
|
+
s.date = '2020-10-02'
|
6
|
+
s.summary = "Dungeons of Heck"
|
7
|
+
s.description = "A gem for playing the game Dungeons of Heck"
|
8
|
+
s.authors = ["Alex Berenger Pike"]
|
9
|
+
s.email = 'alex.pike.ap@outlook.com'
|
10
|
+
s.files = Dir['lib/*.*']
|
11
|
+
s.files += Dir['[A-Z]*'] + Dir['spec/*']
|
12
|
+
s.files.reject! { |fn| fn.include? "CVS" }
|
13
|
+
s.homepage = 'https://github.com/theRamenWithin/Assignments/tree/master/Term1/Assignment3'
|
14
|
+
end
|
data/lib/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
colorize (0.8.1)
|
5
|
+
diff-lcs (1.4.4)
|
6
|
+
pastel (0.8.0)
|
7
|
+
tty-color (~> 0.5)
|
8
|
+
rspec (3.9.0)
|
9
|
+
rspec-core (~> 3.9.0)
|
10
|
+
rspec-expectations (~> 3.9.0)
|
11
|
+
rspec-mocks (~> 3.9.0)
|
12
|
+
rspec-core (3.9.2)
|
13
|
+
rspec-support (~> 3.9.3)
|
14
|
+
rspec-expectations (3.9.2)
|
15
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
16
|
+
rspec-support (~> 3.9.0)
|
17
|
+
rspec-mocks (3.9.1)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.9.0)
|
20
|
+
rspec-support (3.9.3)
|
21
|
+
strings (0.2.0)
|
22
|
+
strings-ansi (~> 0.2)
|
23
|
+
unicode-display_width (~> 1.5)
|
24
|
+
unicode_utils (~> 1.4)
|
25
|
+
strings-ansi (0.2.0)
|
26
|
+
tty-box (0.6.0)
|
27
|
+
pastel (~> 0.8)
|
28
|
+
strings (~> 0.2.0)
|
29
|
+
tty-cursor (~> 0.7)
|
30
|
+
tty-color (0.5.2)
|
31
|
+
tty-cursor (0.7.1)
|
32
|
+
tty-font (0.5.0)
|
33
|
+
tty-prompt (0.22.0)
|
34
|
+
pastel (~> 0.8)
|
35
|
+
tty-reader (~> 0.8)
|
36
|
+
tty-reader (0.8.0)
|
37
|
+
tty-cursor (~> 0.7)
|
38
|
+
tty-screen (~> 0.8)
|
39
|
+
wisper (~> 2.0)
|
40
|
+
tty-screen (0.8.1)
|
41
|
+
tty-table (0.12.0)
|
42
|
+
pastel (~> 0.8)
|
43
|
+
strings (~> 0.2.0)
|
44
|
+
tty-screen (~> 0.8)
|
45
|
+
unicode-display_width (1.7.0)
|
46
|
+
unicode_utils (1.4.0)
|
47
|
+
wisper (2.0.1)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
x64-mingw32
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
colorize (~> 0.8.1)
|
55
|
+
rspec (~> 3.9)
|
56
|
+
tty-box (~> 0.6.0)
|
57
|
+
tty-font (~> 0.5.0)
|
58
|
+
tty-prompt (~> 0.22.0)
|
59
|
+
tty-table (~> 0.12.0)
|
60
|
+
|
61
|
+
BUNDLED WITH
|
62
|
+
2.1.4
|
data/lib/actions.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
module Action
|
2
|
+
|
3
|
+
# Method for moving between locations
|
4
|
+
def move
|
5
|
+
prompt.select("Where will you move to?".blue) do |menu|
|
6
|
+
Game::ROOM_ATTR[Game::PLAYER_ATTR[:player_location_id]][:move_locations].each do |move_to|
|
7
|
+
# If the location is open, list it as an option.
|
8
|
+
if move_to[:open?]
|
9
|
+
menu.choice "#{move_to[:name].capitalize}", -> {Game::PLAYER_ATTR[:player_location_id] = move_to[:id]}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
menu.choice "Cancel", -> {next}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def interact(interact_object)
|
17
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
18
|
+
|
19
|
+
# If the interactible has not been used, puts the use success message.
|
20
|
+
if !interact_object[:used?]
|
21
|
+
|
22
|
+
# If the object needs something to use, check inventory for anything with a matching item_id.
|
23
|
+
if !interact_object[:needs].nil?
|
24
|
+
# If there's a match, delete the item from the inventory and continue, else fail.
|
25
|
+
if Game::PLAYER_ATTR[:inventory].any? {|h| h[:item_id] == interact_object[:needs]}
|
26
|
+
Game::PLAYER_ATTR[:inventory].delete_at(Game::PLAYER_ATTR[:inventory].index { |v| v[:name] == Game::ITEM_LIST[interact_object[:needs]][:name] })
|
27
|
+
else
|
28
|
+
return puts interact_object[:use_text_fail]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Indicate that the object is now used and puts the successful use message
|
33
|
+
interact_object[:used?] = true
|
34
|
+
puts interact_object[:use_text_success]
|
35
|
+
|
36
|
+
# Unless the interactible gives no item, add the item to the player inventory.
|
37
|
+
unless interact_object[:contains].nil?
|
38
|
+
Game::PLAYER_ATTR[:inventory] << Game::ITEM_LIST[interact_object[:contains]]
|
39
|
+
puts "\n#{Game::PLAYER_ATTR[:inventory].last[:name].upcase.light_green} was added to inventory."
|
40
|
+
end
|
41
|
+
|
42
|
+
# If the interactible has an affect on the room, call used effect proc
|
43
|
+
unless interact_object[:use_effect].nil?
|
44
|
+
interact_object[:use_effect].call
|
45
|
+
end
|
46
|
+
|
47
|
+
# If the interactible has been used, put the used message
|
48
|
+
elsif interact_object[:used?]
|
49
|
+
puts interact_object[:used_text]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Method for using interactibles in a room if they exist
|
54
|
+
def use
|
55
|
+
inter = Game::ROOM_ATTR[Game::PLAYER_ATTR[:player_location_id]][:interactibles]
|
56
|
+
|
57
|
+
# Unless there's nothing to use, list print out thing to interact with.
|
58
|
+
unless inter.nil?
|
59
|
+
prompt.select("What will you use?") do |menu|
|
60
|
+
inter.each do |interact_object|
|
61
|
+
if interact_object[:accessible?]
|
62
|
+
menu.choice "#{interact_object[:name]}", -> {puts "#{interact_object[:use_text_look]}"; interact(interact_object)}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
puts "There is nothing around you that you can use."
|
68
|
+
end
|
69
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
70
|
+
end
|
71
|
+
|
72
|
+
# Method for displaying the contents of the player inventory
|
73
|
+
def bag
|
74
|
+
bag_contents
|
75
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
76
|
+
end
|
77
|
+
|
78
|
+
def bag_contents
|
79
|
+
if Game::PLAYER_ATTR[:inventory].length > 0
|
80
|
+
rows = Game::PLAYER_ATTR[:inventory].map { |v| [v[:name].light_green,v[:examine_text]] }
|
81
|
+
bag_table = TTY::Table.new(header: ["Item", "Description"], rows: rows)
|
82
|
+
puts bag_table.render(:unicode, multiline: true, padding: [1,0])
|
83
|
+
else
|
84
|
+
puts "\nYour bag is empty. You shake the bag in your mouth sadly."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Method for exiting to main menu
|
89
|
+
def exit_game
|
90
|
+
prompt.select("Are you sure you want to quit and return to the main menu? (progress will be lost)".red) do |menu|
|
91
|
+
menu.choice "Yes", -> {Game.new.main_menu}
|
92
|
+
menu.choice "No", -> {Game.new.game_menu}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
module_function :move, :interact, :use, :bag, :bag_contents, :exit_game
|
97
|
+
end
|
data/lib/battle.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Battle
|
2
|
+
|
3
|
+
def fight
|
4
|
+
# Shorter variables for monster attributes
|
5
|
+
mon = Game::MON_LIST[Game::ROOM_ATTR[Game::PLAYER_ATTR[:player_location_id]][:monster_id]]
|
6
|
+
|
7
|
+
# Monster intro text
|
8
|
+
puts mon[:monster_intro]
|
9
|
+
puts "\nFight to survive!"
|
10
|
+
|
11
|
+
# Main combat loop
|
12
|
+
while mon[:monster_hp] > 0
|
13
|
+
prompt.keypress("Press space or enter to attack!".red, keys: [:space, :return])
|
14
|
+
attack = rand(Game::PLAYER_ATTR[:player_attack])
|
15
|
+
mon[:monster_hp] -= attack
|
16
|
+
|
17
|
+
unless mon[:monster_hp] < 0
|
18
|
+
puts "\n#{mon[:name].upcase.red} - HP #{mon[:monster_hp]}/#{mon[:monster_hp_max]}"
|
19
|
+
else
|
20
|
+
puts "\n#{mon[:name].upcase.red} - HP 0/#{mon[:monster_hp_max]}"
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Using your #{'PAW'.light_green}, you boop the snoot of #{mon[:name].upcase.red} doing #{attack} damage."
|
24
|
+
|
25
|
+
if mon[:monster_hp] < 1
|
26
|
+
break
|
27
|
+
end
|
28
|
+
|
29
|
+
puts mon[:monster_attack_text]
|
30
|
+
puts "\nYou feel slightly demoralised."
|
31
|
+
end
|
32
|
+
|
33
|
+
#Victory announcement and set monster defeat
|
34
|
+
Game::ROOM_ATTR[Game::PLAYER_ATTR[:player_location_id]][:monster_defeat?] = true
|
35
|
+
puts mon[:monster_defeat_text]
|
36
|
+
puts "\n#{'Victory!'.blue}"
|
37
|
+
|
38
|
+
# If monster has loot, add it to player inventory with message.
|
39
|
+
unless mon[:loot].nil?
|
40
|
+
Game::PLAYER_ATTR[:inventory] << Game::ITEM_LIST[mon[:loot]]
|
41
|
+
puts "\n#{mon[:name].upcase.red} dropped #{Game::ITEM_LIST[mon[:loot]][:name].upcase.light_green}. You add it to your bag."
|
42
|
+
end
|
43
|
+
|
44
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
45
|
+
|
46
|
+
# If defeating the monster has an affect on the room, call the block
|
47
|
+
unless mon[:monster_defeat_effect].nil?
|
48
|
+
mon[:monster_defeat_effect].call
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module_function :fight
|
53
|
+
end
|
data/lib/doge.txt
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
.╔M╔,
|
2
|
+
││║║▒ ..╓╓
|
3
|
+
││╠║║░, (N║║║║▒⌂
|
4
|
+
││║║▒║▒╔ (NN╠╚║║▒▒▒
|
5
|
+
││╠║╢▒║║N, .╔N║╠╠║║║║╢▒▒░
|
6
|
+
║Ñ║╠╠▒║║║╠M╔╓╓, ╓#║▒▒╠║║║▒▒▒║╢▒▒
|
7
|
+
╔║╠ÑÑ┤┤┤┤┤┤Ñ╠╠╠╠╠╠╠╠╠║#MMM#M##║║▒▒║║║▒╢▒▒▒▒▒╢▒
|
8
|
+
.╓╙│││││┤┤╠╠╠║║╠╠╠╠╡┤┤┤┤┤Ñ╠╠║▒▒║▒▒▒║║╢▒▓▓▓▓▒▒╢▒▒
|
9
|
+
,╔∩│∩│∩∩│││┤Ñ╠╠║╠╠╠╠╠╠╠Ñ╠Ñ┤┤Ñ╠╠╠Ñ║▒▒▒▒║╠║▒▓▓▓▓▒▒║║Ñ
|
10
|
+
.(│∩│││∩∩∩∩∩∩│┤Ñ║║║╠╠║╠╠╠╠╠╠╠╠╠╠Ñ╠╠╠╠╠╠▒▒▒╢▓██▓▓▒╠║║▒
|
11
|
+
(∩∩∩⌠││∩│∩∩∩∩∩│╠╠║╠╠╠╠╠╚┤╚┤╠Ñ║Ñ╠╠╠╠ÑÑ╠╠Ñ╠║╢▓██▓▒▒▒║▒▒░
|
12
|
+
#▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓███████▓▓▓▓▓███████████████████████▒▒║▒∩
|
13
|
+
╫████████████▀╙█▌╙██▀▀▀███████████▀╙█▌╙████▀▀▀▀▀▀▀▀▀▀▀████▓▓µ
|
14
|
+
.╙▀██████████▀@▄▀║▄██┤┤┤██████████▀@▄▀▀▄██▀ÑÑ┤┤┤NN┤┤┤╠║▀███▀▀▒▄
|
15
|
+
└'`▀█████████▄██▄╫█▀▀││╠▀███████▀▀▄╜▀▄▐██▀╠┤┤┤ÑÑ┤┤┤┤Ñ╠╠║║▒▒║╠▀▀
|
16
|
+
╙▀▀▀▀▀▀▀▀▀▀▀▀▀▀W│││╠║╢██████▄▄█▌▄██▀Ñ╚┤┤┤┤┤┤┤┤┤┤┤╠╠╠║║╠╠╠∩
|
17
|
+
. :'└└∩│∩│∩∩∩│∩∩∩∩│││┤╠║╠███████████▌│∩└│││││││││││┤┤Ñ╠╠╠║╠╠,
|
18
|
+
:. .╓##▒▒▒░#┤∩│∩∩∩││││┤╠┤┤┤╠╠ÑÑ┤N╠┤∩│∩∩∩∩∩∩N││∩∩│││││┤┤╠╠╠╠╠N
|
19
|
+
∩:; #████████▓▓▒∩∩∩∩└││││┤│∩│││╚╚┤┤┤┤∩│∩∩∩∩∩∩└││∩∩│∩∩││││┤ÑÑ┤┤N,
|
20
|
+
:`7∩∩ (║███████████Ñ∩∩(∩∩││││∩│∩∩∩∩∩∩││││∩∩∩∩∩∩∩∩∩∩∩∩│││∩││┤N╠╠┤┤┤Γ
|
21
|
+
' (,:┐N║██████████▒Ñ∩∩∩N╔││NN∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩∩│││┤┤││┤╠║║╠╠ÑÑ╡Γ
|
22
|
+
∩'.:│N║▒▒███████▓▒║╡╙┤│∩││N┤∩∩∩│││∩∩∩∩∩∩∩∩∩∩∩∩││││┤│┤┤┤┤Ñ┤╠║║╠╠╠Ñ╡Γ
|
23
|
+
;::(││║▒▓▓▓█▓██▓▓▒╠▒╠ÑÑ┤Ñ╠┤┤┤∩N││N││∩││NNN││N│NN┤┤┤││││┤N╠║╠║╠╠╠╠╠
|
24
|
+
(::(∩│╙║▓██████▓▓▒▒▒╠║╠╠╠Ñ╠║║║║╡┤┤┤┤N┤┤┤┤┤│┤┤┤┤││││││││╚╠╠╠║╠╠║║╠
|
25
|
+
:''(∩╙▒▓█████████▓▒▒▒▒▒▓▓▓▓▓╠╠╠┤┤┤┤┤╚│││││┤│││∩∩│││││┤N╠╠╠╠║║║
|
26
|
+
`:(∩└└││Ñ▒▒▓█▓▀█▓████▒▒▒▒▒▒▒Ñ┤┤┤┤┤┤┤││N┤││││NN│││││NNN╠╠║╠║╠║▒
|
27
|
+
└::(∩│∩│Ñ║▒▒▒▒║╠╠║║╠╠║║╠╠╠┤┤┤┤Ñ┤┤Ñ┤┤┤┤│┤││││││┤┤│┤Ñ╠Ñ║║╠╠║║▒
|
28
|
+
`∩∩∩∩∩│∩∩│││┤│┤┤┤┤╠ÑÑ┤NNN╠┤Ñ╠╠┤┤┤ÑÑ┤┤┤│││∩∩││N┤┤╠╠╠╠╠╠║║╠▒╙
|
29
|
+
└∩∩∩∩∩∩││∩││││┤┤┤╠┤┤╠╠╠╠Ñ╠╠Ñ╠╠╠┤┤│││││││NNN││┤╠ÑÑ║║║║▒╙
|
30
|
+
││∩∩∩∩││∩│┤││││┤Ñ╠┤┤╠╠ÑÑÑ╠ÑÑÑ┤┤││││∩│││┤N┤┤┤Ñ┤┤Ñ╠║║┘
|
31
|
+
`│││││││││││┤┤┤┤┤┤Ñ╠ÑÑ╠┤┤Ñ╠╠╠┤┤│N∩││┤┤NÑÑ┤┤┤╠┤╚║╙
|
32
|
+
└│││┤││││││┤┤┤┤┤Ñ┤┤╠╠╡ÑÑ╠╠╠Ñ╠╠╠╠Ñ╠╠╠Ñ┤┤┤N╙└"
|
33
|
+
`└│┤┤┤NNNÑÑ┤┤Ñ╠╠╠╠╠╠╠╠║║╠║║║║╠╠Ñ┤Ñ╚┘"
|
34
|
+
`└└╚╠║║║║╠║║║║║║║║║╠╠╠╠╠╚Ñ╚└`
|
35
|
+
'└╙╚╚╚╚╚╚╚╙╙╙╙└'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Import local modules
|
2
|
+
require_relative 'main'
|
3
|
+
require_relative 'actions'
|
4
|
+
require_relative 'battle'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
# Start Game
|
9
|
+
if ARGV.empty?
|
10
|
+
new_game = Game.new
|
11
|
+
new_game.main_menu
|
12
|
+
elsif ARGV[0] == "-h" || ARGV[0] == "--help"
|
13
|
+
puts "--- Help ---"
|
14
|
+
puts "Usage:"
|
15
|
+
puts " To install this gem, run:\n"
|
16
|
+
puts " gem install ./dungeonsofheck-1.0.gem"
|
17
|
+
puts " irb"
|
18
|
+
puts " require 'dungeonsofheck'"
|
19
|
+
puts " OR"
|
20
|
+
puts " ruby ./lib/dungeonsofheck.rb"
|
21
|
+
puts "Options:"
|
22
|
+
puts " -h or --html # get help file"
|
23
|
+
puts "Example:"
|
24
|
+
puts " ruby ./lib/dungeonsofheck.rb -h"
|
25
|
+
end
|
data/lib/main.rb
ADDED
@@ -0,0 +1,248 @@
|
|
1
|
+
# Import gem modules
|
2
|
+
require 'tty-box'
|
3
|
+
require 'tty-font'
|
4
|
+
require 'tty-table'
|
5
|
+
require 'tty-prompt'
|
6
|
+
require 'colorize'
|
7
|
+
|
8
|
+
# Error handling classes for input validation
|
9
|
+
class NotValidName < StandardError
|
10
|
+
def initialize(msg="\nForgetful doge, surely you remember your own name? (Name can only contain letters and must be less than 8 characters)".light_blue)
|
11
|
+
super(msg)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class NotValidAge < StandardError
|
15
|
+
def initialize(msg="\nForgetful doge, surely you remember your own age? (Age can only contain numbers)".light_blue)
|
16
|
+
super(msg)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Declare methods for gem module functionality
|
21
|
+
def prompt
|
22
|
+
TTY::Prompt.new(symbols: {marker: "🐕"})
|
23
|
+
end
|
24
|
+
def font
|
25
|
+
TTY::Font.new(:doom)
|
26
|
+
end
|
27
|
+
|
28
|
+
class Game
|
29
|
+
|
30
|
+
# =========================
|
31
|
+
# Declare constants for attribute storage
|
32
|
+
# =========================
|
33
|
+
ROOM_ATTR = [
|
34
|
+
{location_id: 0,
|
35
|
+
location_name: "Entrance",
|
36
|
+
move_locations: [{name: "gate",
|
37
|
+
id: 1,
|
38
|
+
open?: true}],
|
39
|
+
intro_text: "The dirt road under your beans is cold and dusty. You stand before a tall, iron #{'GATE'.yellow} flanked by high, stone walls. Beside the gate, in the bushes, you spot what could be a #{'CHEST'.green}. Beyond the gate, you see a courtyard and an imposing castle in the distance.",
|
40
|
+
look_text: "The entrance feel lonely. A strong breeze kicks up the small stones and dirt from the path, making you squint. The #{'GATE'.yellow} is your only way forward. Beside it, you spot what could be a #{'CHEST'.green}.",
|
41
|
+
interactibles: [{name: "Chest",
|
42
|
+
needs: nil,
|
43
|
+
use_text_look: "\nHidden under some low shrubbery, the metal glint of a small chest catches your eye.",
|
44
|
+
use_text_success: "\nYour nails clack noisily against the #{'CHEST'.green} as you fumble it open and retreive a #{'LETTER'.light_green} from inside. Only now do you notice the stake rising from the ground and realise that you just raided the fallen off mailbox of the #{"HECK WIZARD".red}. Boy is he going to be mad.",
|
45
|
+
use_text_fail: "\nSomehow you failed to open the #{'CHEST'.green}, even though I didn't program that to be possible.",
|
46
|
+
used_text: "\nThe #{'BROKEN MAILBOX'.green} lies forlornly under the bush, empty and mailless.",
|
47
|
+
used?: false,
|
48
|
+
use_effect: nil,
|
49
|
+
accessible?: true,
|
50
|
+
contains: 0}],
|
51
|
+
monster?: false,
|
52
|
+
monster_defeat?: false,
|
53
|
+
visited?: false},
|
54
|
+
|
55
|
+
{location_id: 1,
|
56
|
+
location_name: "Courtyard",
|
57
|
+
move_locations: [{name: "Entrance",
|
58
|
+
id: 0,
|
59
|
+
open?: true},
|
60
|
+
|
61
|
+
{name: "crypt",
|
62
|
+
id: 2,
|
63
|
+
open?: false}],
|
64
|
+
intro_text: "You enter the medium sized, gravel covered courtyard via the gate. Dense hedges line the surrounding walls behind and to your side. The middle of the courtyard contains an #{'ALTAR'.green} with shallow pools at its four corners. Between you an the castle you realise is an expansive garden and cemetary. An #{'UNREASONABLY LARGE DOGE'.red} stands in front of the #{'CRYPT DOOR'.yellow} that seems to be your only way forward.",
|
65
|
+
look_text: "The sound of water tinkling in the pools around the #{'ALTAR'.green} might be calming if the #{'COURTYARD'.yellow} was not so desolute. The #{'UNREASONABLY LARGE DOGE'.red} continues to block the way to the #{'CRYPT DOOR'.green}.",
|
66
|
+
interactibles: [{name: "Crypt Door",
|
67
|
+
needs: 2,
|
68
|
+
use_text_look: "\nThe #{'UNREASONABLY LARGE DOGE'.red} was standing guard in front of the #{'CRYPT DOOR'.green} before you gave him a booping he will never forget. It stands tall in dark mahogony, embellished with iron trimming.",
|
69
|
+
use_text_success: "\nThe #{'KEY'.light_green} goes in after a few good slaps. Twisting it with your mouth, the locking mechanism clunks heavily and the #{'CRYPT DOOR'.green} swings in on your weight revealing a path to the #{'CRYPT'.yellow}.",
|
70
|
+
use_text_fail: "\nNo amount of pawing and whining at this door will convinced a human to open it for you. Some kind of key shaped hole is the only opening you can see.",
|
71
|
+
used_text: "\nAn overwhelming feeling of dread washes over you. The #{'CRYPT'.yellow} beckons.",
|
72
|
+
used?: false,
|
73
|
+
use_effect: proc {Game::ROOM_ATTR[1][:move_locations][1][:open?] = true},
|
74
|
+
accessible?: false,
|
75
|
+
contains: nil},
|
76
|
+
|
77
|
+
{name: "Altar",
|
78
|
+
needs: 1,
|
79
|
+
use_text_look: "\nThe #{'ALTAR'.green} is a marbled white, stone slab in the center of the courtyard. You jump up with your front paws on the surface and snoot peeking over the top and see a bone shaped recess in the middle of the #{'ALTAR'.green}.",
|
80
|
+
use_text_success: "\nYou drop the #{'CRYSTAL BONE'.light_green} into the #{'CRYSTAL BONE'.light_green} shaped slot in the #{'ALTAR'.green} and give it a good few tippy tap whacks until it rotates just right, fixing itself to the slot. You hear one face of the #{'ALTAR'.green} open with a thud, revealing a small chamber housing a #{'KEY'.light_green}.",
|
81
|
+
use_text_fail: "\nPerhaps something goes into the slot.",
|
82
|
+
used_text: "\nThere is nothing more to do here except maybe salivated over the #{'CRYSTAL BONE'.light_green}, even though you know it's too hard to chew.",
|
83
|
+
used?: false,
|
84
|
+
use_effect: nil,
|
85
|
+
accessible?: true,
|
86
|
+
contains: 2}],
|
87
|
+
monster?: true,
|
88
|
+
monster_id: 0,
|
89
|
+
monster_defeat?: false,
|
90
|
+
visited?: false},
|
91
|
+
|
92
|
+
{location_id: 2,
|
93
|
+
location_name: "Crypt",
|
94
|
+
move_locations: [{name: "Courtyard",
|
95
|
+
id: 1,
|
96
|
+
open?: true}],
|
97
|
+
intro_text: "You descend into the spooky crypt. It smells like dank and not in a good way. The stairs lead to a chamber lit by torches that just light themselves I guess. You no have time to think about the mechanics of a centralised, automatic torch refueling and ignition system because in the middle of the chamber you spot a #{'NOISY HOOVER'.red}!",
|
98
|
+
look_text: "The #{'NOISY HOOVER'.red} dominates the unnaturally clean chamber with its stillness. Perhaps it is asleep? Either way, you must strike to save the land!",
|
99
|
+
interactibles: nil,
|
100
|
+
monster?: true,
|
101
|
+
monster_id: 1,
|
102
|
+
monster_defeat?: false,
|
103
|
+
visited?: false}
|
104
|
+
]
|
105
|
+
|
106
|
+
PLAYER_ATTR = {player_name: "",
|
107
|
+
player_age: 0,
|
108
|
+
player_location_id: nil,
|
109
|
+
player_attack: 1..4,
|
110
|
+
inventory: []}
|
111
|
+
|
112
|
+
ITEM_LIST = [
|
113
|
+
{name: "Letter",
|
114
|
+
item_id: 0,
|
115
|
+
examine_text: "\"FINAL NOTICE OF NON-PAYMENT!\" reads the letter. The rest is chewed up and illegiable. \nProbably by some other doge or maybe cat. Oh heck."},
|
116
|
+
|
117
|
+
{name: "Crystal Bone",
|
118
|
+
item_id: 1,
|
119
|
+
examine_text: "A heckin' huge sparkly, omnious bone that's far too made of crystal to chew on."},
|
120
|
+
|
121
|
+
{name: "Key",
|
122
|
+
item_id: 2,
|
123
|
+
examine_text: "A perfectly normal bone key with a not at all spooky skull motif in the handle. This is \nfine."}
|
124
|
+
]
|
125
|
+
|
126
|
+
MON_LIST = [
|
127
|
+
{name: "unreasonably large doge",
|
128
|
+
monster_hp: 10,
|
129
|
+
monster_hp_max: 10,
|
130
|
+
monster_intro: "\nAn #{'UNREASONABLY LARGE DOGE'.red} blocks your path. He's just standing there with a dumb look on his face while being too big!",
|
131
|
+
monster_attack_text: "\nThe #{'UNREASONABLY LARGE DOGE'.red} stands over you imposingly and drools on you a little.",
|
132
|
+
monster_defeat_text: "\nThe #{'UNREASONABLY LARGE DOGE'.red} finally notices your attacks, licks your face and goes to take a nap in the corner, revealing the #{'CRYPT DOOR'.green} behind it.",
|
133
|
+
monster_defeat_effect: proc {Game::ROOM_ATTR[1][:interactibles][0][:accessible?] = true},
|
134
|
+
loot: 1},
|
135
|
+
|
136
|
+
{name: "noisy hoover",
|
137
|
+
monster_hp: 20,
|
138
|
+
monster_hp_max: 20,
|
139
|
+
monster_intro: "\nThe #{'NOISY HOOVER'.red} springs to life, whirring and undulating. You know it will not stop until everything is clean!",
|
140
|
+
monster_attack_text: "\nThe #{'NOISY HOOVER'.red} cleans the floor back and forth in front of you, evily.",
|
141
|
+
monster_defeat_text: "\nThe #{'NOISY HOOVER'.red} splutters and then explodes dramatically. Do those things even have gasoline tanks? W-Wow, that's a lot of fire. Better get the heck out of here!",
|
142
|
+
monster_defeat_effect: Proc.new {Game.final},
|
143
|
+
loot: nil}
|
144
|
+
]
|
145
|
+
|
146
|
+
# =========================
|
147
|
+
# Final text sequence and end of game
|
148
|
+
# =========================
|
149
|
+
def self.final
|
150
|
+
box = TTY::Box.frame(width: 100, height: 15, align: :center, padding: 3, border: :thick,
|
151
|
+
title: {top_left: "|Dungeons of Heck|", bottom_right: "|Final|"}) do
|
152
|
+
"You, #{PLAYER_ATTR[:player_name].upcase.yellow}, flee the flaming #{'CRYPT'.green} as smoke billows out from the entrance and between the ancient brickwork. With suprising speed, you seen the #{"HECK WIZARD".red} is giving chase and boy is he mad! \nLike the wind, out the #{'GATE'.green} you shoot and down the road. \nThe #{"HECK WIZARD".red} chases you for a little bit but turns around when he hears the fire engine coming down the road from the other direction. \nOne day you may return but for now you think you better lay low and content yourself with having rid the land of one more #{'NOISY HOOVER'.red}."
|
153
|
+
end
|
154
|
+
system('clear') || system('cls')
|
155
|
+
puts box
|
156
|
+
prompt.keypress("Press space or enter to fulfill your destiny!".green, keys: [:space, :return])
|
157
|
+
exit
|
158
|
+
end
|
159
|
+
|
160
|
+
# =========================
|
161
|
+
# Method for game menu loop
|
162
|
+
# =========================
|
163
|
+
def game_menu
|
164
|
+
system('clear') || system('cls')
|
165
|
+
box = TTY::Box.frame(width: 100, height: 13, align: :center, padding: [3,0], border: :thick,
|
166
|
+
title: {top_left: "|Dungeons of Heck|", bottom_right: "|Location: #{ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:location_name]}|"}) do
|
167
|
+
if ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:visited?]
|
168
|
+
ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:look_text]
|
169
|
+
else
|
170
|
+
ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:intro_text]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
puts box
|
174
|
+
ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:visited?] = true
|
175
|
+
|
176
|
+
prompt.select("Choose your FATE".red) do |menu|
|
177
|
+
if ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:monster?] && !ROOM_ATTR[PLAYER_ATTR[:player_location_id]][:monster_defeat?]
|
178
|
+
menu.choice "Fight!", -> {Battle::fight; game_menu}
|
179
|
+
end
|
180
|
+
menu.choice "Move", -> {Action::move; game_menu}
|
181
|
+
menu.choice "Use", -> {Action::use; game_menu}
|
182
|
+
menu.choice "Inventory", -> {Action::bag; game_menu}
|
183
|
+
menu.choice "Quit", -> {Action::exit_game}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# =========================
|
188
|
+
# Method for getting the player name and introducting the player to the game before starting the game_menu loop
|
189
|
+
# =========================
|
190
|
+
def introduction
|
191
|
+
puts "\nHumble doge, what is your true name?".light_blue
|
192
|
+
begin
|
193
|
+
PLAYER_ATTR[:player_name] = gets.chomp.strip.upcase
|
194
|
+
raise NotValidName if PLAYER_ATTR[:player_name].match?(/[^a-zA-Z]/) || PLAYER_ATTR[:player_name].length > 7 || PLAYER_ATTR[:player_name].length < 1 # Name must be letters and less than 8 characters
|
195
|
+
rescue NotValidName => e
|
196
|
+
puts e.message
|
197
|
+
retry
|
198
|
+
end
|
199
|
+
|
200
|
+
puts "\nHumble doge, what is your true age?".light_blue
|
201
|
+
begin
|
202
|
+
PLAYER_ATTR[:player_age] = Integer(gets) rescue 0
|
203
|
+
raise NotValidAge unless PLAYER_ATTR[:player_age] > 0
|
204
|
+
rescue NotValidAge => e
|
205
|
+
puts e.message
|
206
|
+
retry
|
207
|
+
end
|
208
|
+
|
209
|
+
if PLAYER_ATTR[:player_age] > 15
|
210
|
+
puts "\nWow, that's heckin' old for a doge but if you say so.".light_blue
|
211
|
+
else
|
212
|
+
puts "\n#{PLAYER_ATTR[:player_age]} is a fine age for a doge adventurer such as yourself.".light_blue
|
213
|
+
end
|
214
|
+
|
215
|
+
puts "\nMighty ".light_blue + "#{PLAYER_ATTR[:player_name].upcase.yellow}" + ", this is your tale.".light_blue
|
216
|
+
|
217
|
+
box = TTY::Box.frame(width: 100, height: 15, align: :center, padding: 3, border: :thick,
|
218
|
+
title: {top_left: "|Dungeons of Heck|", bottom_right: "|Introduction|"}) do
|
219
|
+
"The cold wind blows harshly against your snoot. You lick it to keep it moist and glistening as you take in your surroundings. \nYou are #{PLAYER_ATTR[:player_name].upcase.yellow} and you are a #{'GOOD BOY'.green}. \nYou have travelled following rumours and tales of a heckin' evil place where #{'BAD DOGES'.red} and \n#{'NOISY APPLIANCES'.red} are said to lurk. You have tasked yourself with destroying heckin' bad things across the land and now you have arrived outside the grounds of an imposing castle said to be built upon the most heckin' place of all, the #{'DUNGEONS OF HECK'.red}."
|
220
|
+
end
|
221
|
+
|
222
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
223
|
+
system('clear') || system('cls')
|
224
|
+
puts box
|
225
|
+
|
226
|
+
prompt.keypress("Press space or enter to continue".green, keys: [:space, :return])
|
227
|
+
PLAYER_ATTR[:player_location_id] = 0
|
228
|
+
game_menu
|
229
|
+
end
|
230
|
+
|
231
|
+
# =========================
|
232
|
+
# Method for the main menu when starting the game
|
233
|
+
# =========================
|
234
|
+
def main_menu
|
235
|
+
system('clear') || system('cls')
|
236
|
+
puts font.write("DUNGEONS OF HECK").red
|
237
|
+
|
238
|
+
# acsii = File.open('doge.txt').read
|
239
|
+
# acsii.each_line { |line| puts line }
|
240
|
+
|
241
|
+
# puts ''
|
242
|
+
prompt.select("Choose your FATE".red) do |menu|
|
243
|
+
menu.choice "Start", -> {introduction}
|
244
|
+
menu.choice "Quit", -> {exit}
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative '../lib/main'
|
2
|
+
require_relative '../lib/actions'
|
3
|
+
|
4
|
+
describe 'bag contents' do
|
5
|
+
it 'should puts text to indicate that the bag is not empty' do
|
6
|
+
Game::PLAYER_ATTR[:inventory] = [{name: "Name", examine_text: "Examine"}]
|
7
|
+
expect{Action::bag_contents}.to output("┌────┬───────────┐\n│ │ │\n│Item│Description│\n│ │ │\n├────┼───────────┤\n│ │ │\n│\e[0;92;49mName\e[0m│Examine │\n│ │ │\n└────┴───────────┘\n").to_stdout
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should puts text to indicate that the bag is empty' do
|
11
|
+
Game::PLAYER_ATTR[:inventory] = []
|
12
|
+
expect {Action::bag_contents}.to output("\nYour bag is empty. You shake the bag in your mouth sadly.\n").to_stdout
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/main_spec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../lib/main'
|
2
|
+
|
3
|
+
describe 'introduction name' do
|
4
|
+
it 'should raise an error for invalid input' do
|
5
|
+
Game::PLAYER_ATTR[:player_name] = "123"
|
6
|
+
expect {raise NotValidName if Game::PLAYER_ATTR[:player_name].match?(/[^a-zA-Z]/) || Game::PLAYER_ATTR[:player_name].length > 7}.to raise_error(NotValidName)
|
7
|
+
end
|
8
|
+
it 'should not raise an error for valid input' do
|
9
|
+
Game::PLAYER_ATTR[:player_name] = "ALEX"
|
10
|
+
expect {raise NotValidName if Game::PLAYER_ATTR[:player_name].match?(/[^a-zA-Z]/) || Game::PLAYER_ATTR[:player_name].length > 7}.to_not raise_error(NotValidName)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'introduction age' do
|
15
|
+
it 'should raise an error for invalid input' do
|
16
|
+
Game::PLAYER_ATTR[:player_age] = Integer("ALEX") rescue 0
|
17
|
+
expect {raise NotValidAge unless Game::PLAYER_ATTR[:player_age] > 0}.to raise_error(NotValidAge)
|
18
|
+
end
|
19
|
+
it 'should not raise an error for valid input' do
|
20
|
+
Game::PLAYER_ATTR[:player_age] = Integer(123) rescue 0
|
21
|
+
expect {raise NotValidAge unless Game::PLAYER_ATTR[:player_age] > 0}.to_not raise_error(NotValidAge)
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dungeonsofheck
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Berenger Pike
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-02 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A gem for playing the game Dungeons of Heck
|
14
|
+
email: alex.pike.ap@outlook.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- dungeonsofheck.gemspec
|
21
|
+
- lib/Gemfile.lock
|
22
|
+
- lib/actions.rb
|
23
|
+
- lib/battle.rb
|
24
|
+
- lib/doge.txt
|
25
|
+
- lib/dungeonsofheck.rb
|
26
|
+
- lib/main.rb
|
27
|
+
- spec/actions_spec.rb
|
28
|
+
- spec/main_spec.rb
|
29
|
+
homepage: https://github.com/theRamenWithin/Assignments/tree/master/Term1/Assignment3
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.0.3
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Dungeons of Heck
|
52
|
+
test_files: []
|