dungeonsofheck 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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: []