├── .gitignore
├── .markdownlint.json
├── .rspec
├── .travis.yml
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
└── gemwarrior
├── data
├── default_world.yaml
├── fantasy_names.yaml
├── minimal1.yaml
├── minimal2.yaml
└── minimal3.yaml
├── gemwarrior.gemspec
├── lib
└── gemwarrior
│ ├── arena.rb
│ ├── battle.rb
│ ├── entities
│ ├── armor.rb
│ ├── armor
│ │ ├── iron_helmet.rb
│ │ └── leather_jerkin.rb
│ ├── creature.rb
│ ├── creatures
│ │ ├── cow.rb
│ │ ├── goat.rb
│ │ └── pig.rb
│ ├── entity.rb
│ ├── item.rb
│ ├── items
│ │ ├── apple.rb
│ │ ├── arena_door.rb
│ │ ├── bed.rb
│ │ ├── bookcase.rb
│ │ ├── bullet.rb
│ │ ├── chest.rb
│ │ ├── couch.rb
│ │ ├── cup.rb
│ │ ├── dehumidifier.rb
│ │ ├── feather.rb
│ │ ├── floor_tile.rb
│ │ ├── flower.rb
│ │ ├── herb.rb
│ │ ├── hut.rb
│ │ ├── keystone.rb
│ │ ├── ladder.rb
│ │ ├── letter.rb
│ │ ├── locker.rb
│ │ ├── locker_corner.rb
│ │ ├── map.rb
│ │ ├── massive_door.rb
│ │ ├── pedestal.rb
│ │ ├── pond.rb
│ │ ├── red_key.rb
│ │ ├── rope.rb
│ │ ├── sand_jewel.rb
│ │ ├── shovel.rb
│ │ ├── small_hole.rb
│ │ ├── snowman.rb
│ │ ├── sparkly_thing.rb
│ │ ├── stonemite.rb
│ │ ├── tent.rb
│ │ ├── throne.rb
│ │ ├── tree.rb
│ │ └── waterfall.rb
│ ├── location.rb
│ ├── monster.rb
│ ├── monsters
│ │ ├── alexandrat.rb
│ │ ├── amberoo.rb
│ │ ├── amethystle.rb
│ │ ├── apatiger.rb
│ │ ├── aquamarine.rb
│ │ ├── bloodstorm.rb
│ │ ├── bosses
│ │ │ ├── emerald.rb
│ │ │ ├── garynetty.rb
│ │ │ └── jaspern.rb
│ │ ├── citrinaga.rb
│ │ ├── coraliz.rb
│ │ ├── cubicat.rb
│ │ └── diaman.rb
│ ├── people
│ │ ├── arena_master.rb
│ │ ├── drunk_man.rb
│ │ ├── queen_ruby.rb
│ │ ├── rockney.rb
│ │ ├── shifty_woman.rb
│ │ ├── thin_man.rb
│ │ └── ware_hawker.rb
│ ├── person.rb
│ ├── player.rb
│ ├── weapon.rb
│ └── weapons
│ │ ├── dagger.rb
│ │ ├── gun.rb
│ │ ├── mace.rb
│ │ ├── opalaser.rb
│ │ ├── spear.rb
│ │ ├── stalactite.rb
│ │ └── stone.rb
│ ├── evaluator.rb
│ ├── game.rb
│ ├── game_assets.rb
│ ├── game_options.rb
│ ├── inventory.rb
│ ├── misc
│ ├── animation.rb
│ ├── audio.rb
│ ├── audio_cues.rb
│ ├── bloops_cues.rb
│ ├── formatting.rb
│ ├── hr.rb
│ ├── musical_notes.rb
│ ├── name_generator.rb
│ ├── player_levels.rb
│ ├── timer.rb
│ └── wordlist.rb
│ ├── repl.rb
│ ├── version.rb
│ └── world.rb
├── spec
├── gemwarrior_spec.rb
└── spec_helper.rb
└── tests
├── compare_versions.rb
├── getch_test.rb
├── hooch.rb
├── item_hashes.rb
├── json_api_call.rb
├── module_hashes.rb
├── test-class
└── test-class.rb
├── test-feep
└── test-feep.rb
├── test-save-load
├── save-load.rb
└── save.conf
└── test-singleton
├── game.rb
└── game_options.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | .gemwarrior
2 | .bundle/
3 | .yardoc
4 | Gemfile.lock
5 | *.gct
6 | *.gem
7 | !bin/gemwarrior
8 | _yardoc/
9 | assets/
10 | coverage/*
11 | doc/
12 | img/
13 | pkg/
14 | spec/reports/
15 | tmp/
16 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "MD033": false,
3 | "MD040": false,
4 | "MD041": false
5 | }
6 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --format documentation
2 | --color
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 2.2.1
4 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | gemspec
3 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Michael Chadwick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | /-+-+-+ +-+-+-+-+-+-+-\
3 | |G|E|M| |W|A|R|R|I|O|R|
4 | \-+-+-+ +-+-+-+-+-+-+-/
5 | ```
6 |
7 | logo courtesy of [ascii generator](http://www.network-science.de/ascii/)
8 |
9 | [](http://badge.fury.io/rb/gemwarrior)
10 |
11 | **Gem Warrior** is a text adventure that takes place in the land of **Jool**,
12 | where randomized fortune is just as likely as *mayhem*.
13 |
14 | You take up the mantle of **1.upto(rand(5..10)) {print rand(65..90).chr}**,
15 | a gifted young acolyte who has been tasked by the queen herself, **Ruby**,
16 | to venture off into the unknown to recapture a **Shiny Thingtm**
17 | that holds great power within its crystallized boundaries. Unfortunately, it
18 | was stolen recently by a crazed madperson named **Emerald**, bent on using
19 | its frightening power for **Evil**. You are **Good**, obviously, and the
20 | rightful caretaker of such power, but he will not give it up willingly, and
21 | has cursed all the creatures of the land into doing his bidding, which is
22 | largely tearing you limb from limb.
23 |
24 | Start in your poor, super lame cottage, where you live alone, subsisting off
25 | the sale of polished rocks you scavenge all day for in the neighboring caves.
26 | Once tasked with your quest, travel throughout the land of Jool, eventually
27 | reaching the sky tower that Emerald resides in with his stolen goods,
28 | laughing to himself, occasionally.
29 |
30 | As you travel you will discover sights and sounds of the land, all of which
31 | are new to you because you don't really get out much. Visit towns with
32 | merchants willing to trade coin for wares they bought off of other adventurers
33 | who didn't last the previous attempts at thwartion. Sleep in a tent (or on the
34 | ground, if that's all that's available) to regain your enumerated status
35 | points, which are conveniently located in your peripheral vision (i.e. the
36 | console window). Eventually, if you're skilled, you just might reach the place
37 | known as **Emerald's Sky Tower**, figure out how to part him from his
38 | **ShinyThingtm**, and then do what is "right".
39 |
40 | ## PLAY
41 |
42 | ### How to Get to Jool
43 |
44 | 1. `ruby -v` should return `ruby 2.something`; else install [Ruby](https://www.ruby-lang.org)
45 | 2. `gem -v` should return `2.something`; else install [RubyGems](https://rubygems.org)
46 | 3. `(sudo) gem install gemwarrior`
47 | 4. `gemwarrior`
48 |
49 | Run the commands above and you'll be whisked away to Jool, ready to start or
50 | continue your quest to defeat Emerald and take back the coveted Shiny Thing(tm)
51 | that you will bring back to Queen Ruby (or will you...?).
52 |
53 | ### Main Commands
54 |
55 | `> character` - character check for visual identity
56 | `> inventory [object]` - check your inventory (or an individual item within)
57 | `> rest` - take a load off and replenish hp
58 | `> look [object]` - look at current location and its items and monsters
59 | `> take [object]` - take an item from a location
60 | `> use [object]` - use an item from your inventory or current location
61 | `> drop [object]` - drop an item from your inventory
62 | `> equip [object]` - designate an item in your inventory your weapon
63 | `> unequip [object]` - stop using an item in your inventory as your weapon
64 | `> go [direction]` - go in a direction, if possible
65 | (north|east|south|west work as shortcuts)
66 | `> attack [monster]` - attack a monster
67 | `> change [attribute]` - change some things about yourself
68 | `> help` - display available commands
69 | `> version` - display current game version
70 | `> quit` - quit this nonsense w/ prompt
71 | `> quit!` - quit this nonsense w/o prompt
72 |
73 | ## CONTRIBUTE
74 |
75 | 1. `git clone https://github.com/michaelchadwick/gemwarrior.git`
76 | 2. `cd /path/to/gemwarrior`
77 | 3. `vi /file/you/want/to/change.rb`
78 | 4. `gem build`
79 | 5. `gem install --local /path/to/gemwarrior/pkg/gemwarrior.VERSION.gem`
80 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rspec/core/rake_task'
2 | require 'bundler/gem_tasks'
3 |
4 | # Default directory to look in is `/specs`
5 | # Run with `rake spec`
6 | RSpec::Core::RakeTask.new(:spec) do |task|
7 | task.rspec_opts = ['--color', '--format', 'documentation']
8 | end
9 |
10 | task :deploy do |t|
11 | sh "git push origin master"
12 | sh "rake build"
13 |
14 | file = Dir.glob("pkg/*").max_by {|f| File.mtime(f)}
15 |
16 | sh "gem push #{file}"
17 | end
18 |
19 | task :default => :spec
20 |
--------------------------------------------------------------------------------
/bin/gemwarrior:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'optparse'
4 | require 'os'
5 | require 'fileutils'
6 |
7 | require_relative '../lib/gemwarrior/game'
8 | require_relative '../lib/gemwarrior/game_options'
9 | require_relative '../lib/gemwarrior/version'
10 |
11 | include Gemwarrior
12 |
13 | GW_NAME = 'Gem Warrior'
14 | GW_HOME_PATH = "#{Dir.home}/.gemwarrior"
15 | GW_SAVE_FILE_YAML_PATH = "#{GW_HOME_PATH}/gw_sav.yaml"
16 | GW_SAVE_FILE_BIN_PATH = "#{GW_HOME_PATH}/gw_sav.dat"
17 | GW_SAVE_FILE_MODE_DEFAULT = 'Y' # YAML
18 | GW_OPTS_FILE_PATH = "#{GW_HOME_PATH}/gw_opts"
19 | GW_LOG_FILE_PATH = "#{GW_HOME_PATH}/gw_log"
20 | GW_WRAP_WIDTH_DEFAULT = 80
21 |
22 | def print_error(error)
23 | case error
24 | when OptionParser::InvalidOption
25 | puts "#{GW_NAME}: illegal option #{error.args.join(' ')}"
26 | else
27 | puts "An unexpected error occurred while running #{GW_NAME}:"
28 | puts " #{error}\n"
29 | end
30 | end
31 |
32 | def init_config(world)
33 | Dir.mkdir(GW_HOME_PATH) unless Dir.exist?(GW_HOME_PATH)
34 |
35 | log_file_path = GW_LOG_FILE_PATH
36 | options_file_path = GW_OPTS_FILE_PATH
37 | save_file_mode_default = GW_SAVE_FILE_MODE_DEFAULT
38 | save_file_bin_path = GW_SAVE_FILE_BIN_PATH
39 | save_file_yaml_path = GW_SAVE_FILE_YAML_PATH
40 | sound_system_default = OS.windows? ? 'win32-sound' : 'bloops'
41 | world_yaml_path = File.expand_path("../../data/#{world}.yaml", __FILE__)
42 | world_bin_path = File.expand_path("../../data/#{world}.bin", __FILE__)
43 | wrap_width = GW_WRAP_WIDTH_DEFAULT
44 |
45 | GameOptions.add 'log_file_path', log_file_path
46 | GameOptions.add 'options_file_path', options_file_path
47 | GameOptions.add 'save_file_bin_path', save_file_bin_path
48 | GameOptions.add 'save_file_mode', save_file_mode_default
49 | GameOptions.add 'save_file_yaml_path', save_file_yaml_path
50 | GameOptions.add 'sound_system', sound_system_default
51 | GameOptions.add 'world_bin_path', world_bin_path
52 | GameOptions.add 'world_yaml_path', world_yaml_path
53 | GameOptions.add 'wrap_width', wrap_width
54 | end
55 |
56 | def read_options_file
57 | if !File.exist?(GW_OPTS_FILE_PATH)
58 | FileUtils.mkdir(GW_HOME_PATH)
59 | File.write(GW_OPTS_FILE_PATH, "")
60 | end
61 |
62 | options = {}
63 |
64 | File.open(GW_OPTS_FILE_PATH).readlines.each do |line|
65 | kv = line.chomp.split(':')
66 | options[kv[0].to_sym] = kv[1]
67 | end
68 |
69 | # check for null
70 | return options[:sound_enabled] ? options : nil
71 | end
72 |
73 | def parse_options_cli
74 | # default options
75 | options = {
76 | beast_mode: false,
77 | debug_mode: false,
78 | extra_command: nil,
79 | fight_completion: false,
80 | god_mode: false,
81 | new_skip: false,
82 | resume_skip: false,
83 | sound_enabled: false,
84 | sound_system: 'bloops',
85 | sound_volume: 0.3,
86 | use_wordnik: false,
87 | world_name: 'default_world'
88 | }
89 |
90 | # options file has next precedence
91 | unless (opts_file = read_options_file).nil?
92 | options[:fight_completion] = (opts_file[:fight_completion].eql?('false') ? false : true) if opts_file[:fight_completion]
93 |
94 | options[:sound_enabled] = (opts_file[:sound_enabled].eql?('false') ? false : true) if opts_file[:sound_enabled]
95 |
96 | options[:sound_system] = (opts_file[:sound_system]) if opts_file[:sound_system]
97 |
98 | options[:sound_volume] = (opts_file[:sound_volume].to_f) if opts_file[:sound_volume]
99 |
100 | options[:use_wordnik] = (opts_file[:use_wordnik].eql?('false') ? false : true) if opts_file[:use_wordnik]
101 |
102 | opts_file[:world_name] = (opts_file[:world_name]) if opts_file[:world_name]
103 | end
104 |
105 | # command line has next precedence
106 | optparse = OptionParser.new do |opts|
107 | opts.on('-b', '--beast', 'Enable debug[beastmode]') do
108 | options[:beast_mode] = true
109 | end
110 |
111 | opts.on('-d', '--debug', 'Enable debug commands in-game') do
112 | options[:debug_mode] = true
113 | end
114 |
115 | opts.on('-f', '--fight-completion', 'Fighting without specifying an enemy will attack first one it finds') do
116 | options[:fight_completion] = false
117 | end
118 |
119 | opts.on('-g', '--god', 'Enable debug[godmode]') do
120 | options[:god_mode] = true
121 | end
122 |
123 | opts.on('-k', '--wordnik', 'Enable Wordnik to generate more diverse, dynamic descriptors of entities') do
124 | options[:use_wordnik] = true
125 | end
126 |
127 | opts.on('-n', '--new', 'Immediately start a new game, skipping main menu') do
128 | options[:new_skip] = true
129 | end
130 |
131 | opts.on('-r', '--resume', 'Immediately resume the saved game, skipping main menu') do
132 | options[:resume_skip] = true
133 | end
134 |
135 | opts.on('-s', '--sound', 'Enable sound (experimental)') do
136 | options[:sound_enabled] = true
137 | end
138 |
139 | opts.on('-v', '--version', 'Display version number and exit') do
140 | puts "#{GW_NAME} v#{Gemwarrior::VERSION}"
141 | exit
142 | end
143 |
144 | opts.on('-w', '--world WORLD_NAME', String, 'Build Gemwarrior with alternate world data file') do |world_name|
145 | options[:world_name] = world_name
146 | end
147 |
148 | opts.on('-x', '--xtra COMMAND,PARAMS', String, 'Run a command, with optional params, immediately upon beginning the game') do |xc|
149 | options[:extra_command] = xc.gsub(',',' ')
150 | end
151 | end
152 |
153 | optparse.parse!()
154 |
155 | return options
156 | end
157 |
158 | begin
159 | options = parse_options_cli
160 |
161 | init_config(options[:world_name])
162 |
163 | Gemwarrior::Game.new(options)
164 | rescue => e
165 | print_error(e)
166 | puts ("#{self.class} - #{e.class}: #{e.message}" + e.backtrace).join("\n")
167 | exit(false)
168 | end
169 |
--------------------------------------------------------------------------------
/data/minimal1.yaml:
--------------------------------------------------------------------------------
1 | --- !ruby/object:Gemwarrior::World
2 | locations:
3 | - !ruby/object:Gemwarrior::Location
4 | name: home
5 | name_display: Home
6 | visited: true
7 | description: The little, unimportant, decrepit shack that you live in. What the place lacks in decisive magnanimity is made up for in cozy squalidness. Your bed covers much of the northern corner. Your beloved family chest sits at the foot of the bed.
8 | coords: &2
9 | :x: 5
10 | :y: 0
11 | :z: 0
12 | paths:
13 | :north: true
14 | :east: true
15 | :south: false
16 | :west: true
17 | danger_level: :none
18 | monster_level_range:
19 | items:
20 | - !ruby/object:Gemwarrior::Bed
21 | equipped: false
22 | consumable: false
23 | used: false
24 | used_again: false
25 | number_of_uses:
26 | name: bed
27 | name_display: Bed
28 | description: The place where you sleep when you are not adventuring.
29 | takeable: false
30 | talkable: false
31 | useable: true
32 | equippable: false
33 | monsters_abounding: []
34 | bosses_abounding: []
35 | checked_for_monsters: false
36 | player: !ruby/object:Gemwarrior::Player
37 | name: Player
38 | description: |-
39 | Picked to do battle against a wizened madman for a shiny something or other for world-saving purposes.
40 | face: facey
41 | hands: handsy
42 | mood: moody
43 | level: 1
44 | xp: 0
45 | hp_cur: 30
46 | hp_max: 30
47 | atk_lo: 1
48 | atk_hi: 2
49 | defense: 1
50 | dexterity: 3
51 | inventory: !ruby/object:Gemwarrior::Inventory
52 | armor:
53 | items: []
54 | weapon:
55 | rox: 0
56 | cur_coords: *2
57 | special_abilities: []
58 | monsters_killed: 0
59 | bosses_killed: 0
60 | items_taken: 0
61 | movements_made: 0
62 | rests_taken: 0
63 | deaths: 0
64 | emerald_beaten: false
65 | shifty_jeweled: false
66 | shifty_to_jewel: false
67 | duration:
68 |
--------------------------------------------------------------------------------
/data/minimal2.yaml:
--------------------------------------------------------------------------------
1 | --- !ruby/object:Gemwarrior::World
2 | locations:
3 | - !ruby/object:Gemwarrior::Location
4 | name: home
5 | name_display: Home
6 | visited: true
7 | description: The little, unimportant, decrepit shack that you live in. What the place lacks in decisive magnanimity is made up for in cozy squalidness. Your bed covers much of the northern corner. Your beloved family chest sits at the foot of the bed.
8 | coords: &2
9 | :x: 5
10 | :y: 0
11 | :z: 0
12 | paths:
13 | :north: true
14 | :east: true
15 | :south: false
16 | :west: true
17 | danger_level: :none
18 | monster_level_range:
19 | monsters_abounding: []
20 | bosses_abounding: []
21 | checked_for_monsters: false
22 | emerald_beaten: false
23 | shifty_jeweled: false
24 | shifty_to_jewel: false
25 | duration:
26 |
--------------------------------------------------------------------------------
/data/minimal3.yaml:
--------------------------------------------------------------------------------
1 | --- !ruby/object:Gemwarrior::World
2 |
--------------------------------------------------------------------------------
/gemwarrior.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 |
5 | require 'gemwarrior/version'
6 |
7 | source_uri = 'https://github.com/michaelchadwick/gemwarrior'
8 | rubygem_uri = 'http://rubygems.org/gems/gemwarrior'
9 |
10 | Gem::Specification.new do |spec|
11 | spec.name = 'gemwarrior'
12 | spec.summary = 'RubyGem text adventure'
13 | spec.version = Gemwarrior::VERSION
14 | spec.platform = Gem::Platform::RUBY
15 | spec.authors = ['Michael Chadwick']
16 | spec.email = ['mike@neb.host']
17 | spec.homepage = rubygem_uri
18 | spec.license = 'MIT'
19 | spec.description = 'A fun text adventure in the form of a RubyGem!'
20 |
21 | spec.files = `git ls-files`.split("\n")
22 | spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23 | spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
24 | spec.require_paths = ['lib']
25 |
26 | spec.metadata = {
27 | "documentation_uri" => source_uri,
28 | "homepage_uri" => source_uri,
29 | "source_code_uri" => source_uri
30 | }
31 | spec.required_ruby_version = '>= 2.0'
32 | spec.post_install_message = "Type 'gemwarrior' to start adventuring!"
33 |
34 | ## required deps
35 | spec.add_runtime_dependency 'clocker', '~> 0.1.6'
36 | spec.add_runtime_dependency 'colorize', '~> 1.0'
37 | spec.add_runtime_dependency 'gems', '~> 1.2'
38 | spec.add_runtime_dependency 'http', '~> 5.1'
39 | spec.add_runtime_dependency 'json', '~> 2.6'
40 | spec.add_runtime_dependency 'matrext', '~> 1.0'
41 | spec.add_runtime_dependency 'os', '~> 0.9', '>= 0.9.6'
42 | spec.add_runtime_dependency 'psych', '~> 5.1'
43 | ## optional sound systems
44 | # spec.add_runtime_dependency 'bloopsaphone', '>= 0.4'
45 | # spec.add_runtime_dependency 'feep', '~> 0.1.3'
46 | # spec.add_runtime_dependency 'win32-sound', '~> 0.6.0'
47 |
48 | ## development deps
49 | spec.add_development_dependency 'awesome_print', '~> 1.9'
50 | spec.add_development_dependency 'bundler', '~> 2.4'
51 | spec.add_development_dependency 'bundler-audit', '~> 0.9'
52 | spec.add_development_dependency 'guard', '~> 2.18'
53 | spec.add_development_dependency 'guard-rspec', '~> 4.7'
54 | spec.add_development_dependency 'pry-byebug', '~> 3.10'
55 | spec.add_development_dependency 'rake', '~> 13.0'
56 | spec.add_development_dependency 'rspec', '~> 3.12.0'
57 | spec.add_development_dependency 'rspec-nc', '~> 0.3'
58 | spec.add_development_dependency 'rubocop', '~> 1.50'
59 | end
60 |
--------------------------------------------------------------------------------
/lib/gemwarrior/arena.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/arena.rb
2 | # Arena series of battles
3 |
4 | require_relative 'battle'
5 |
6 | module Gemwarrior
7 | class Arena
8 | # CONSTANTS
9 | BONUS_ROX_MULTIPLIER = 25
10 | BONUS_XP_MULTIPLIER = 10
11 |
12 | attr_accessor :world, :player
13 |
14 | def initialize(options)
15 | self.world = options.fetch(:world)
16 | self.player = options.fetch(:player)
17 | end
18 |
19 | def start
20 | print_arena_intro
21 |
22 | arena_monsters_vanquished = 0
23 |
24 | loop do
25 | monster = generate_monster
26 | battle = Battle.new(world: world, player: player, monster: monster)
27 | result = battle.start(is_arena: true)
28 |
29 | return 'death' if result.eql?('death')
30 |
31 | arena_monsters_vanquished += 1
32 |
33 | print ' Do you wish to continue fighting in the Arena? (y/n) '
34 | answer = gets.chomp.downcase
35 |
36 | case answer
37 | when 'y', 'yes'
38 | puts
39 | next
40 | else
41 | bonus_rox = arena_monsters_vanquished * BONUS_ROX_MULTIPLIER
42 | bonus_xp = arena_monsters_vanquished * BONUS_XP_MULTIPLIER
43 | player.rox = player.rox + bonus_rox
44 | player.xp = player.xp + bonus_xp
45 | puts
46 | puts ' You decided you\'ve had enough of the exhausting Arena for one day and exit the main stage.'
47 | puts " You defeated #{arena_monsters_vanquished} monsters!"
48 | puts " You have gained #{bonus_rox} rox and #{bonus_xp} XP!"
49 |
50 | return print_arena_outro
51 | end
52 | end
53 | end
54 |
55 | private
56 |
57 | def generate_monster
58 | random_monster = nil
59 |
60 | loop do
61 | random_monster = GameMonsters.data[rand(0..GameMonsters.data.length - 1)].clone
62 |
63 | break unless random_monster.is_boss
64 | end
65 |
66 | random_monster.clone
67 | end
68 |
69 | def print_arena_intro
70 | puts '**************************'.colorize(:red)
71 | puts '* YOU ENTER THE ARENA!!! *'.colorize(:red)
72 | puts '**************************'.colorize(:red)
73 | end
74 |
75 | def print_arena_outro
76 | puts '**************************'.colorize(:red)
77 | puts '* YOU LEAVE THE ARENA!!! *'.colorize(:red)
78 | puts '**************************'.colorize(:red)
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/armor.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/armor.rb
2 | # Entity::Item::Armor base class
3 |
4 | require_relative 'item'
5 |
6 | module Gemwarrior
7 | class Armor < Item
8 | attr_accessor :defense
9 |
10 | def initialize
11 | super
12 |
13 | self.equippable = true
14 | self.defense = 0
15 | self.is_armor = true
16 | end
17 |
18 | def use(world)
19 | 'Save the donning of this piece of armor for battle.'
20 | end
21 |
22 | def describe_detailed
23 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
24 | desc_text << "(#{name})\n".colorize(:green)
25 | desc_text << "#{description}\n".colorize(:white)
26 | desc_text << "ARMOR? #{is_armor}\n".colorize(:white)
27 | desc_text << "DEFENSE: #{defense}\n".colorize(:white)
28 | desc_text << "TAKEABLE? #{takeable}\n".colorize(:white)
29 | desc_text << "USEABLE? #{useable}\n".colorize(:white)
30 | desc_text << "TALKABLE? #{talkable}\n".colorize(:white)
31 | desc_text << "CONSUMABLE? #{consumable}\n".colorize(:white)
32 | desc_text << "EQUIPPABLE? #{equippable}\n".colorize(:white)
33 | desc_text << "EQUIPPED? #{equipped}\n".colorize(:white)
34 | desc_text << "USED? #{used}\n".colorize(:white)
35 | desc_text << "USED AGAIN? #{used_again}\n".colorize(:white)
36 | desc_text << "USES LEFT? #{number_of_uses}\n".colorize(:white) unless number_of_uses.nil?
37 | desc_text
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/armor/iron_helmet.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/armor/iron_helmet.rb
2 | # Entity::Item::Armor::IronHelmet
3 |
4 | require_relative '../armor'
5 |
6 | module Gemwarrior
7 | class IronHelmet < Armor
8 | def initialize
9 | super
10 |
11 | self.name = 'iron_helmet'
12 | self.name_display = 'Iron Helmet'
13 | self.description = 'The noggin is better off when encased in a heavy, yet safe, bowl-shaped carapace made of solid iron.'
14 | self.defense = 3
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/armor/leather_jerkin.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/armor/leather_jerkin.rb
2 | # Entity::Item::Armor::LeatherJerkin
3 |
4 | require_relative '../armor'
5 |
6 | module Gemwarrior
7 | class LeatherJerkin < Armor
8 | def initialize
9 | super
10 |
11 | self.name = 'leather_jerkin'
12 | self.name_display = 'Leather Jerkin'
13 | self.description = 'Brownish-black in color and fairly form-fitting, this jerkin will soften any blow a bit, at least.'
14 | self.defense = 2
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/creature.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/creature.rb
2 | # Entity::Creature base class
3 |
4 | require_relative 'entity'
5 |
6 | module Gemwarrior
7 | class Creature < Entity
8 | attr_accessor :face,
9 | :hands,
10 | :mood,
11 | :level,
12 | :xp,
13 | :hp_cur,
14 | :hp_max,
15 | :atk_lo,
16 | :atk_hi,
17 | :defense,
18 | :dexterity,
19 | :inventory,
20 | :rox
21 |
22 | attr_reader :use,
23 | :speak
24 |
25 | def initialize
26 | super
27 |
28 | self.name = 'creature'
29 | self.name_display = Formatting::upstyle(name)
30 | self.description = 'A creature.'
31 | self.face = 'face-y'
32 | self.hands = 'handsy'
33 | self.mood = 'moody'
34 | self.level = 1
35 | self.xp = 0
36 | self.hp_cur = 10
37 | self.hp_max = 10
38 | self.atk_lo = 1
39 | self.atk_hi = 1
40 | self.defense = 1
41 | self.dexterity = 1
42 | self.inventory = Inventory.new
43 | self.rox = 0
44 | self.talkable = true
45 | self.used = false
46 | end
47 |
48 | def use(world)
49 | 'That creature does not seem to want to talk to you right now.'
50 | end
51 |
52 | def describe
53 | desc_text = "#{description}".colorize(:white)
54 | desc_text << "\n"
55 | desc_text << "The creature has several distinguishing features, as well: face is #{face.colorize(:yellow)}, hands are #{hands.colorize(:yellow)}, and mood is, generally, #{mood.colorize(:yellow)}."
56 | desc_text
57 | end
58 |
59 | def describe_detailed
60 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
61 | desc_text << "(#{name})\n".colorize(:green)
62 | desc_text << "#{description}\n".colorize(:white)
63 | desc_text << "FACE : #{face}\n".colorize(:white)
64 | desc_text << "HANDS : #{hands}\n".colorize(:white)
65 | desc_text << "MOOD : #{mood}\n".colorize(:white)
66 | desc_text << "LEVEL : #{level}\n".colorize(:white)
67 | desc_text << "XP : #{xp}\n".colorize(:white)
68 | desc_text << "HP : #{hp_cur}/#{hp_max}\n".colorize(:white)
69 | desc_text << "ATK_RANGE : #{atk_lo}-#{atk_hi}\n".colorize(:white)
70 | desc_text << "DEFENSE : #{defense}\n".colorize(:white)
71 | desc_text << "DEXTERITY : #{dexterity}\n".colorize(:white)
72 | desc_text << "ROX : #{rox}\n".colorize(:white)
73 | desc_text << "INVENTORY : #{inventory.contents}\n".colorize(:white)
74 | desc_text
75 | end
76 |
77 | def speak(s, no_end_quote = false, no_line_feed = false)
78 | text = ">> \"#{s}"
79 | text += "\"" unless no_end_quote
80 | text += "\n" unless no_line_feed
81 | text = text.colorize(:yellow)
82 | if no_line_feed
83 | print text
84 | else
85 | print text.gsub(/(.{1,#{GameOptions.data['wrap_width']}})(\s+|\Z)/, "\\1\n")
86 | end
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/creatures/cow.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/creatures/cow.rb
2 | # Entity::Creature::Cow
3 |
4 | require_relative '../creature'
5 |
6 | module Gemwarrior
7 | class Cow < Creature
8 | def initialize
9 | super
10 |
11 | self.name = 'cow'
12 | self.name_display = 'Cow'
13 | self.description = 'Grazing on some fake grass, unperturbed, this black and white herd animal looks bored.'
14 | self.face = 'blank'
15 | self.hands = 'stampy'
16 | self.mood = 'reserved'
17 | end
18 |
19 | def use(world)
20 | puts '>> "Moo."'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/creatures/goat.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/goat.rb
2 | # Entity::Creature::Goat
3 |
4 | require_relative '../creature'
5 |
6 | module Gemwarrior
7 | class Goat < Creature
8 | def initialize
9 | super
10 |
11 | self.name = 'goat'
12 | self.name_display = 'Goat'
13 | self.description = 'The scruff is strong with this one as it chews through what appears to be a recent mystery novel most likely thrown into the pen by a passerby.'
14 | self.face = 'busy'
15 | self.hands = 'hoofy'
16 | self.mood = 'content'
17 | end
18 |
19 | def use(world)
20 | puts '>> "Baa."'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/creatures/pig.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/pig.rb
2 | # Entity::Creature::Pig
3 |
4 | require_relative '../creature'
5 |
6 | module Gemwarrior
7 | class Pig < Creature
8 | def initialize
9 | super
10 |
11 | self.name = 'pig'
12 | self.name_display = 'Pig'
13 | self.description = 'Dirty, eating slop, but still kind of cute. Yep, this is a pig.'
14 | self.face = 'messy'
15 | self.hands = 'muddy'
16 | self.mood = 'restless'
17 | end
18 |
19 | def use(world)
20 | puts '>> "Oink."'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/entity.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/entity.rb
2 | # Base class for a describable object
3 |
4 | require_relative '../game_options'
5 | require_relative '../misc/formatting'
6 | require_relative '../misc/animation'
7 |
8 | module Gemwarrior
9 | class Entity
10 | attr_accessor :name,
11 | :name_display,
12 | :description,
13 | :takeable,
14 | :useable,
15 | :useable_battle,
16 | :talkable,
17 | :consumable,
18 | :equippable,
19 | :equipped,
20 | :used,
21 | :used_again,
22 | :number_of_uses
23 |
24 | attr_reader :describe,
25 | :describe_detailed,
26 | :display_shopping_cart
27 |
28 | def initialize
29 | self.name = 'entity'
30 | self.name_display = Formatting::upstyle(name)
31 | self.description = 'An entity.'
32 | self.useable = true
33 | self.useable_battle = false
34 | self.talkable = false
35 | self.consumable = false
36 | self.takeable = true
37 | self.equippable = false
38 | self.equipped = false
39 | self.used = false
40 | self.used_again = false
41 | self.number_of_uses = nil
42 | end
43 |
44 | def use(world)
45 | 'That does not appear to be useable.'
46 | end
47 |
48 | def describe(world)
49 | desc_text = "#{description}".colorize(:white)
50 | desc_text
51 | end
52 |
53 | def describe_detailed(world)
54 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
55 | desc_text << "(#{name})\n".colorize(:green)
56 | desc_text << "#{description}\n".colorize(:white)
57 | desc_text << "TAKEABLE? #{takeable}\n".colorize(:white)
58 | desc_text << "USEABLE? #{useable}\n".colorize(:white)
59 | desc_text << "TALKABLE? #{talkable}\n".colorize(:white)
60 | desc_text << "CONSUMABLE? #{consumable}\n".colorize(:white)
61 | desc_text << "EQUIPPABLE? #{equippable}\n".colorize(:white)
62 | desc_text << "EQUIPPED? #{equipped}\n".colorize(:white)
63 | desc_text << "USED? #{used}\n".colorize(:white)
64 | desc_text << "USED AGAIN? #{used_again}\n".colorize(:white)
65 | desc_text << "USES LEFT? #{number_of_uses}\n".colorize(:white) unless number_of_uses.nil?
66 | desc_text
67 | end
68 |
69 | def display_shopping_cart(cart)
70 | puts "ITEMS SELECTED: #{cart.map(&:name).join(', ')}"
71 | end
72 |
73 | def puts(s = '', width = GameOptions.data['wrap_width'])
74 | super s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n") unless s.nil?
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/item.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/item.rb
2 | # Entity::Item base class
3 |
4 | require_relative 'entity'
5 |
6 | module Gemwarrior
7 | class Item < Entity
8 | attr_accessor :is_armor,
9 | :is_weapon
10 |
11 | attr_reader :use
12 |
13 | def initialize
14 | super
15 |
16 | self.is_armor = false
17 | self.is_weapon = false
18 | end
19 |
20 | def use(world)
21 | 'That item does not do anything...yet.'
22 | end
23 |
24 | def describe_detailed(world)
25 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
26 | desc_text << "(#{name})\n".colorize(:green)
27 | desc_text << "#{description}\n".colorize(:white)
28 | desc_text << "ARMOR? #{is_armor}\n".colorize(:white)
29 | desc_text << "WEAPON? #{is_weapon}\n".colorize(:white)
30 | desc_text << "TAKEABLE? #{takeable}\n".colorize(:white)
31 | desc_text << "USEABLE? #{useable}\n".colorize(:white)
32 | desc_text << "TALKABLE? #{talkable}\n".colorize(:white)
33 | desc_text << "CONSUMABLE? #{consumable}\n".colorize(:white)
34 | desc_text << "EQUIPPABLE? #{equippable}\n".colorize(:white)
35 | desc_text << "EQUIPPED? #{equipped}\n".colorize(:white)
36 | desc_text << "USED? #{used}\n".colorize(:white)
37 | desc_text << "USED AGAIN? #{used_again}\n".colorize(:white)
38 | desc_text << "USES LEFT? #{number_of_uses}\n".colorize(:white) unless number_of_uses.nil?
39 | desc_text
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/apple.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/apple.rb
2 | # Entity::Item::Apple
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Apple < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'apple'
12 | self.name_display = 'Apple'
13 | self.description = 'Reddish-orangeish in color, this fruit looks sweet, but it is heavy and feels more like a rock you would sooner not bite into.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | if !self.used
19 | puts 'You attempt to consume the apple, but stop midway through your first bite. Something tells you this is not a good idea, and you stop.'
20 | puts
21 | self.used = true
22 | else
23 | puts 'Remembering the odd feeling you got the last time you attempted to use the apple, you refrain.'
24 | { type: nil, data: nil }
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/arena_door.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/arena_door.rb
2 | # Entity::Item::ArenaDoor
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class ArenaDoor < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'arena_door'
12 | self.name_display = 'Arena Door'
13 | self.description = 'The Arena is massive, with its numerous columns and stone walls stretching to the sky, but its entrance door is no slouch, keeping apace. Made of reinforced granite and impossible to break down, it nevertheless opens for you while battles are in session.'
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/bed.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/bed.rb
2 | # Entity::Item::Bed
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Bed < Item
8 | # CONSTANTS
9 | USE_TEXT = '** ZZZZZ **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'bed'
15 | self.name_display = 'Bed'
16 | self.description = 'The place where you sleep when you are not adventuring.'
17 | end
18 |
19 | def use(world)
20 | if world.player.at_full_hp?
21 | puts 'You feel perfectly healthy and decide not to actually use the bed. Besides, the trail of fire ants currently leading up to and around the furniture seem somehow uninviting.'
22 | { type: nil, data: nil }
23 | else
24 | Animation.run(phrase: USE_TEXT)
25 | puts 'You unmake the bed, get under the covers, close your eyes, and begin to think about all the things you need to do today. You realize sleep is not one of them and quickly get back up, remake the bed, and get on about your day.'
26 | puts '>> You regain all of your hit points.'.colorize(:green)
27 | { type: 'rest', data: world.player.hp_max-world.player.hp_cur }
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/bookcase.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/bookcase.rb
2 | # Entity::Item::Bookcase
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Bookcase < Item
8 | # CONSTANTS
9 | OPEN_TEXT = '** BRRRRRNNNGG **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'bookcase'
15 | self.name_display = 'Bookcase'
16 | self.description = 'This oaken monstrosity has six shelves, each about 3 feet high. Mathing, you determine it to be "huge", featuring many books within it.'
17 | end
18 |
19 | def use(world)
20 | forest_southwest = world.location_by_name('forest-southwest')
21 |
22 | if forest_southwest.paths[:west].eql? false
23 | if !self.used
24 | puts 'Many books look interesting, including one specific volume entitled "Use Me Again to Attempt Unlocking the Way", by Not Very Subtle.'
25 | puts
26 | self.used = true
27 | else
28 | puts 'You pull out the tome entitled "Use Me Again to Attempt Unlocking the Way".'
29 | STDIN.getc
30 | puts 'Opening the book, you see a question on the inside cover:'
31 | puts '>> "What do you get when an underground excavator is named after a famous "weird" guy?"'
32 | print '? '
33 | answer = gets.chomp.downcase
34 |
35 | case answer
36 | when 'mineral'
37 | Audio.play_synth(:uncover_secret)
38 | forest_southwest.paths[:west] = true
39 | puts
40 | Animation.run(phrase: OPEN_TEXT)
41 | puts
42 | puts 'After you shout out your answer to the book\'s question to no one in particular, you manage to see a clearing in the forest to the west that was presumably not there before. Huh.'
43 | STDIN.getc
44 |
45 | puts 'Before getting back to your travels, however, you notice the book\'s back cover warns: "The path westward is a difficult one and has "ended" many an adventurer. Take care before venturing forth."'
46 | else
47 | puts 'For some reason, you blurt out an answer to the unhearing trees, feel embarrassed, and put the book back in the bookcase.'
48 | end
49 | end
50 |
51 | { type: nil, data: nil }
52 | else
53 | puts 'You pull out a book here and there, glancing at their weathered pages and scuffed bindings. Nothing really interests you and it is back to staring at the forest.'
54 | end
55 |
56 | { type: nil, data: nil }
57 | end
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/bullet.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/bullet.rb
2 | # Entity::Item::Bullet
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Bullet < Item
8 | # CONSTANTS
9 | USE_TEXT = '** ZZZZZ **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'bullet'
15 | self.name_display = 'Bullet'
16 | self.description = 'Gunpowder packed into a small metallic tube, ready to be fired from...something.'
17 | self.takeable = true
18 | end
19 |
20 | def use(world)
21 | puts 'You could throw this at a monster, but somehow the force of it would be less than desired.'
22 | { type: nil, data: nil }
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/chest.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/chest.rb
2 | # Entity::Item::Chest
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Chest < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'chest'
12 | self.name_display = 'Chest'
13 | self.description = 'Well-crafted with solid oak, this family chest has intricate inlays all around the front and sides. It\'s the one thing from home you took with you when you left.'
14 | end
15 |
16 | def use(world)
17 | home = world.location_by_name('home')
18 | open_description = 'You open the chest and find little inside but some dust and faded memories of your childhood.'
19 |
20 | if self.used
21 | if home.contains_item?('leather_jerkin')
22 | open_description += ' The old sword fighting garment is still in there, too.'
23 | end
24 | puts open_description
25 |
26 | { type: nil, data: nil }
27 | else
28 | open_description += ' That, and a slightly dirty, but still useful garment you remember using while taking those sword fighting lessons as a small boy.'
29 |
30 | puts open_description
31 |
32 | home.items.push(LeatherJerkin.new)
33 |
34 | self.used = true
35 |
36 | { type: nil, data: nil }
37 | end
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/couch.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/couch.rb
2 | # Entity::Item::Couch
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Couch < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'couch'
12 | self.name_display = 'Couch'
13 | self.description = 'Ever wanted to sit on a cloud? Now is your chance.'
14 | end
15 |
16 | def use(world)
17 | if world.player.at_full_hp?
18 | puts 'You "sit" on the impossibly soft surface of the furniture, but even after a few minutes of this seemingly heavenly hedonism you don\'t feel significantly better and decide to get up again.'
19 | { type: nil, data: nil }
20 | else
21 | puts 'Your body comes to rest somewhere below the surface of the cloudy apparatus, almost as if it were floating *amongst* the couch. The feeling is heavenly, and you actually feel somewhat better after getting back up.'
22 | puts '>> You regain a few hit points.'.colorize(:green)
23 | { type: 'rest', data: 4 }
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/cup.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/cup.rb
2 | # Entity::Item::Cup
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Cup < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'cup'
12 | self.name_display = 'Cup'
13 | self.description = 'A nice stone mug, perfect for putting things into and then using to carry such things from place to place.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'Nothing in the cup at the moment, so not very usable.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/dehumidifier.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/dehumidifier.rb
2 | # Entity::Item::Dehumidifier
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Dehumidifier < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'dehumidifier'
12 | self.name_display = 'Dehumidifier'
13 | self.description = 'Humidity stands approximately zero chance of surviving when in its presence.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'Despite your figeting, the lack of humidity remains the same.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/feather.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/feather.rb
2 | # Entity::Item::Feather
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Feather < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'feather'
12 | self.name_display = 'Feather'
13 | self.description = 'A blue and green feather. It is soft and tender, unlike the craven bird that probably shed it.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'Soft to the touch, you wonder what it could be used before besides temporary comfort.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/floor_tile.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/floor_tile.rb
2 | # Entity::Item::FloorTile
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class FloorTile < Item
8 | # CONSTANTS
9 | MOVE_TEXT = '** SHOOOOOM **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'floor_tile'
15 | self.name_display = 'Floor Tile'
16 | self.description = 'One of the floor tiles, rough-hewn but immaculate, looks...off. Pressable, even.'
17 | end
18 |
19 | def use(world)
20 | puts 'You slowly lower your foot onto the tile, and then gently depress it, through the floor. Your whole body begins to feel light, lifeless. You black out.'
21 | puts
22 |
23 | # stats
24 | world.player.movements_made += 1
25 |
26 | Animation.run(phrase: MOVE_TEXT)
27 |
28 | { type: 'move', data: 'Rock Piles' }
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/flower.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/flower.rb
2 | # Item::Flower
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Flower < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'flower'
12 | self.name_display = 'Flower'
13 | self.description = 'Petals the color of clear sky and a stem of bright white. A most curious plant.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'You inhale the flower, metaphorically. Smells nice.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/herb.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/herb.rb
2 | # Entity::Item::Herb
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Herb < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'herb'
12 | self.name_display = 'Herb'
13 | self.description = 'Green and leafy, this wild herb looks edible.'
14 | self.takeable = true
15 | self.consumable = true
16 | self.useable_battle = true
17 | end
18 |
19 | def use(world)
20 | puts 'You place the entire, smallish plant in your mouth, testing its texture. The mysterious herb is easily chewable, and you are able to swallow it without much effort. Slight tingles travel up and down your spine.'
21 | if world.player.at_full_hp?
22 | puts '>> The herb has no medicinal effect, as you already feel perfectly healthy, but it was kind of tasty.'
23 | { type: nil, data: nil }
24 | else
25 | hp_healed = rand(3..5)
26 | puts ">> You regain #{hp_healed} hit points.".colorize(:green)
27 | { type: 'health', data: hp_healed }
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/hut.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/hut.rb
2 | # Entity::Item::Hut
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Hut < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'hut'
12 | self.name_display = 'Hut'
13 | self.description = 'A simple thatched hut, sitting in the middle of the plains. Nothing about it seems odd, except its existence among the otherwise featureless landscape.'
14 | end
15 |
16 | def use(world)
17 | puts 'You peer inside, but it is completely vacant at the moment, leaving you marginally disappointed.'
18 |
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/keystone.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/keystone.rb
2 | # Entity::Item::Keystone
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Keystone < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'keystone'
12 | self.name_display = 'Keystone'
13 | self.description = 'Certainly greater than the sum of its parts, this smallish stone glows faintly and feels slick to the touch.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'The keystone glows a bit brighter when you grasp it tightly.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/ladder.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/ladder.rb
2 | # Entity::Item::Ladder
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Ladder < Item
8 | # CONSTANTS
9 | USE_TEXT = '** THUMP **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'ladder'
15 | self.name_display = 'Ladder'
16 | self.description = 'Rickety and crudely-fashioned, this ladder descends down into the dropoff, hopefully heading towards something...anything.'
17 | end
18 |
19 | def use(world)
20 | puts 'You grab onto the shaky, rough-hewn, wooden ladder with all your might and start to descend, being extra careful not to loose your grip, which with every moment becomes shakier and shakier.'
21 | puts
22 |
23 | # stats
24 | world.player.movements_made += 1
25 |
26 | Animation.run(phrase: USE_TEXT)
27 |
28 | puts 'The last couple of steps are more slippery than you anticipated, so you end up fumbling them, falling a few feet onto the hard ground below. When you regain your composure, you notice your conveyance for descending is now far above you and it is, unfortunately, your closest known exit.'
29 | puts
30 |
31 | { type: 'move_dangerous', data: 'metal_tunnel-south_entrance' }
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/letter.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/letter.rb
2 | # Entity::Item::Letter
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Letter < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'letter'
12 | self.name_display = 'Letter'
13 | self.description = 'A single page of thin paper, folded at the middle, with some excellent penmanship impressed upon it.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | if self.used
19 | print 'Do you want to read the letter again? (y/n) '
20 | answer = gets.chomp.downcase
21 |
22 | case answer
23 | when 'y', 'yes'
24 | print "\n"
25 | print_letter(world)
26 | else
27 | { type: nil, data: nil }
28 | end
29 | else
30 | self.used = true
31 | print_letter(world)
32 | { type: 'xp', data: 3 }
33 | end
34 | end
35 |
36 | private
37 |
38 | def print_letter(world)
39 | puts 'The words of the queen echo in your head as you read the royal note sent to you again:'
40 | puts
41 | Animation.run(phrase: " Dear #{world.player.name},", speed: :insane)
42 | puts
43 | Animation.run(phrase: ' Oh, my! Jool is in trouble! The evil wizard/sorceror/conjuror/rocksmith/wily ', speed: :insane)
44 | Animation.run(phrase: " Emerald has absconded with our ShinyThing(tm)! It is vital that you, #{world.player.name}, ", speed: :insane)
45 | Animation.run(phrase: ' go to his tower in the sky in order to retrieve it before he does something', speed: :insane)
46 | Animation.run(phrase: ' terrible with it!', speed: :insane)
47 | puts
48 | Animation.run(phrase: ' Remember that one time you came to the castle, trying to sell stones you', speed: :insane)
49 | Animation.run(phrase: ' pilfered from a nearby cave? Remember how I laughed and told you to leave', speed: :insane)
50 | Animation.run(phrase: ' at once or I\'d have the royal guard take your head off? Ha!', speed: :insane)
51 | puts
52 | Animation.run(phrase: ' What a fool I was to cast such a special person out, as a mysterious stranger', speed: :insane)
53 | Animation.run(phrase: " in the night told me, before mysteriously disappearing, that you, #{world.player.name},", speed: :insane)
54 | Animation.run(phrase: ' are actually the only one who can save us (for some reason, but that\'s', speed: :insane)
55 | Animation.run(phrase: ' mysterious strangers for you, right?)!', speed: :insane)
56 | puts
57 | Animation.run(phrase: ' Please, I beg of you, save Jool from the potential terror that Emerald could', speed: :insane)
58 | Animation.run(phrase: " possibly wreak on all of us before it is too late! If you do, you, #{world.player.name},", speed: :insane)
59 | Animation.run(phrase: ' will be rewarded handsomely!', speed: :insane)
60 | puts
61 | Animation.run(phrase: ' Sincerely,', speed: :insane);
62 | Animation.run(phrase: ' Queen Ruby', speed: :insane);
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/locker.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/locker.rb
2 | # Entity::Item::Locker
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Locker < Item
8 | attr_accessor :locked
9 |
10 | def initialize
11 | super
12 |
13 | self.name = 'locker'
14 | self.name_display = 'Locker'
15 | self.description = 'A small, locked locker with a lock on it. You will need to unlock it to gain access to its insides.'
16 | self.takeable = false
17 | self.locked = true
18 | end
19 |
20 | def use(world)
21 | cur_location = world.location_by_coords(world.player.cur_coords)
22 | locker = cur_location.get_item_ref('locker')
23 |
24 | if locker.locked
25 | puts 'You pull on the lock, hoping it will unlock and leave the locker unlocked, but it is no good. You will need something else to unlock this locked locker.'
26 |
27 | return { type: nil, data: nil }
28 | else
29 | if self.used
30 | puts 'The locker is open and you can see a shiny gem inside.'
31 |
32 | return { type: nil, data: nil }
33 | else
34 | self.used = true
35 | puts 'You open the unlocked locker and look inside. Thereabouts, is a shiny gem of some sort.'
36 | cur_location.add_item('sand_jewel')
37 |
38 | return { type: nil, data: nil }
39 | end
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/locker_corner.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/locker_corner.rb
2 | # Entity::Item::LockerCorner
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class LockerCorner < Item
8 | attr_accessor :locked
9 |
10 | def initialize
11 | super
12 |
13 | self.name = 'locker_corner'
14 | self.name_display = 'Locker (Corner)'
15 | self.description = 'The top corner of what appears to be a small locker is slightly sticking up from the sand floor.'
16 | self.takeable = false
17 | self.useable = true
18 | end
19 |
20 | def use(world)
21 | puts 'Pulling with all your might on the corner of the locker doesn\'t get it it budge one inch. Some other method is going to be needed.'
22 |
23 | { type: nil, data: nil }
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/map.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/map.rb
2 | # Entity::Item::Map
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Map < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'map'
12 | self.name_display = 'Map'
13 | self.description = 'The land of Jool is contained on this piece of canvas, in a useful, if not very detailed, manner.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'You unfold the piece of worn canvas and study the markings upon it, always making sure to update it with new places you find.'
19 |
20 | { type: 'action', data: 'map' }
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/massive_door.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/massive_door.rb
2 | # Entity::Item::MassiveDoor
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class MassiveDoor < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'massive_door'
12 | self.name_display = 'Massive Door'
13 | self.description = 'Translucent, but not transparent, this door constructed of condensed water vapor is like nothing you have ever seen. It has no keyhole, but it does have a stone-shaped depression floating centrally within it.'
14 | end
15 |
16 | def use(world)
17 | puts 'You attempt to open the seriously massive door that separates you from Emerald himself.'
18 | if world.player.inventory.contains_item?('keystone')
19 | Audio.play_synth(:uncover_secret)
20 | puts 'The keystone in your inventory glows as you approach the incredibly titanic-sized door, so you naturally pull it out and thrust it into the stone-shaped depression within the cloudy obstruction. The door "opens" in a way and you can now pass through.'
21 | { type: 'move', data: 'Sky Tower (Throne Room)' }
22 | else
23 | puts 'Your hand just goes right through the astonishingly gigantic door, but the rest of your body does not. A moment later, your hand is shoved backwards by some unknown force, and you remain where you were before your unsuccessful attempt.'
24 | { type: nil, data: nil }
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/pedestal.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/pedestal.rb
2 | # Entity::Item::Pedestal
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Pedestal < Item
8 | # CONSTANTS
9 | USE_TEXT = '** WHOOOOOSH **'
10 |
11 | attr_accessor :switches
12 |
13 | def initialize
14 | super
15 |
16 | self.name = 'pedestal'
17 | self.name_display = 'Pedestal'
18 | self.description = 'A pedestal about 4 feet in height rises up from the ground, with six switches arranged vertically above a large gem affixed to the top. The switches each have a word next to them in some language that looks familiar yet strange. Each letter is made of some kind of ink crudely splashed on stone, and each can be moved to arrange them in a different fashion than they are now. The large gem glitters with utter brilliance.'
19 | self.switches = init_switches
20 | end
21 |
22 | def init_switches
23 | self.switches = [
24 | ['iolita', jumble('iolita'), nil],
25 | ['rockney', jumble('rockney'), nil],
26 | ['emerald', jumble('emerald'), nil],
27 | ['ruby', jumble('ruby'), nil],
28 | ['amberoo', jumble('amberoo'), nil],
29 | ['alexandrat', jumble('alexandrat'), nil]
30 | ]
31 |
32 | self.switches = self.switches.sort_by { rand }
33 | end
34 |
35 | def use(world)
36 | puts 'You look at the pedestal and its switches. The raised gem beckons you to push it and, deductively, you believe that pressing it will do something. However, those switches probably have something to do with the result.'
37 |
38 | loop do
39 | print_switches(self.switches)
40 |
41 | puts
42 | puts 'You can rearrange the letters in the words themselves, and you can push the large gem. What do you do?'
43 | puts
44 | puts '>> 1 Rearrange the letters in switch 1\'s word'
45 | puts '>> 2 Rearrange the letters in switch 2\'s word'
46 | puts '>> 3 Rearrange the letters in switch 3\'s word'
47 | puts '>> 4 Rearrange the letters in switch 4\'s word'
48 | puts '>> 5 Rearrange the letters in switch 5\'s word'
49 | puts '>> 6 Rearrange the letters in switch 6\'s word'
50 | puts '>> 7 Push the large gem into the pedestal'
51 | puts '>> 8 Stop this nonsense'
52 | puts
53 |
54 | print '> '
55 | choice = gets.chomp!
56 |
57 | case choice
58 | when '1'
59 | switch1 = switches[0][2].nil? ? switches[0][1] : switches[0][2]
60 | puts "Switch 1: #{switch1}"
61 | puts 'What should the switch\'s word be set to?'
62 | switches[0][2] = get_new_word(switch1)
63 | when '2'
64 | switch2 = switches[1][2].nil? ? switches[1][1] : switches[1][2]
65 | puts "Switch 2: #{switch2}"
66 | puts 'What should the switch\'s word be set to?'
67 | switches[1][2] = get_new_word(switch2)
68 | when '3'
69 | switch3 = switches[2][2].nil? ? switches[2][1] : switches[2][2]
70 | puts "Switch 3: #{switch3}"
71 | puts 'What should the switch\'s word be set to?'
72 | switches[2][2] = get_new_word(switch3)
73 | when '4'
74 | switch4 = switches[3][2].nil? ? switches[3][1] : switches[3][2]
75 | puts "Switch 4: #{switch4}"
76 | puts 'What should the switch\'s word be set to?'
77 | switches[3][2] = get_new_word(switch4)
78 | when '5'
79 | switch5 = switches[4][2].nil? ? switches[4][1] : switches[4][2]
80 | puts "Switch 5: #{switch5}"
81 | puts 'What should the switch\'s word be set to?'
82 | switches[4][2] = get_new_word(switch5)
83 | when '6'
84 | switch6 = switches[5][2].nil? ? switches[5][1] : switches[5][2]
85 | puts "Switch 6: #{switch6}"
86 | puts 'What should the switch\'s word be set to?'
87 | switches[5][2] = get_new_word(switch6)
88 | when '7'
89 | pedestal_configured = true
90 |
91 | for i in 0..switches.length-1 do
92 | pedestal_configured = false unless switches[i][0].downcase.eql? switches[i][2].downcase
93 | end
94 |
95 | if pedestal_configured
96 | Audio.play_synth(:uncover_secret)
97 | puts 'You push the large gem into the pedestal and it descends without a hitch, almost as if it were meant to be. The pedestal begins to violently shake and a strong gust of wind picks you up off the ground. You feel completely taken aback and unsettled, but you have no choice: you are being whisked away somewhere into the sky, destination unknown.'.colorize(:yellow)
98 |
99 | # stats
100 | world.player.movements_made += 1
101 |
102 | Animation.run(phrase: USE_TEXT)
103 | return { type: 'move', data: 'Sky Tower (Entryway)' }
104 | else
105 | puts 'You attempt to push the large gem, but it puts up quite the resistance, and nothing much else happens. Your attention once again returns to the pedestal and its switches.'.colorize(:red)
106 | end
107 | when '8'
108 | puts 'You step away from the mysterious pedestal.'
109 | return { type: nil, data: nil }
110 | else
111 | next
112 | end
113 | end
114 | end
115 |
116 | private
117 |
118 | def print_switches(switches)
119 | puts
120 |
121 | switch1 = switches[0][2].nil? ? switches[0][1] : switches[0][2]
122 | puts "Switch 1: #{switch1}"
123 |
124 | switch2 = switches[1][2].nil? ? switches[1][1] : switches[1][2]
125 | puts "Switch 2: #{switch2}"
126 |
127 | switch3 = switches[2][2].nil? ? switches[2][1] : switches[2][2]
128 | puts "Switch 3: #{switch3}"
129 |
130 | switch4 = switches[3][2].nil? ? switches[3][1] : switches[3][2]
131 | puts "Switch 4: #{switch4}"
132 |
133 | switch5 = switches[4][2].nil? ? switches[4][1] : switches[4][2]
134 | puts "Switch 5: #{switch5}"
135 |
136 | switch6 = switches[5][2].nil? ? switches[5][1] : switches[5][2]
137 | puts "Switch 6: #{switch6}"
138 | end
139 |
140 | def jumble(word)
141 | word.split(//).sort_by { rand }.join('')
142 | end
143 |
144 | def get_new_word(switch)
145 | new_word = gets.chomp!
146 | if switch.downcase.split(//).sort == new_word.downcase.split(//).sort
147 | return new_word
148 | else
149 | puts 'Those letters are not in the original word, sorry.'.colorize(:red)
150 | return nil
151 | end
152 | end
153 | end
154 | end
155 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/pond.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/pond.rb
2 | # Entity::Item::Pond
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Pond < Item
8 | # CONTACTS
9 | NEEDED_ITEMS = ['dehumidifier', 'feather', 'gun', 'stalactite']
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'pond'
15 | self.name_display = 'Pond'
16 | self.description = 'This tiny pool of water self-ripples every minute or so. Small, floating insects buzz around merrily. A small plaque lays at the foot, reading: "If the right objects curious doth possess, touch the water\'s surface and you\'ll get redress."'
17 | end
18 |
19 | def use(world)
20 | puts 'You gently place your fingers on the pond\'s rippling surface.'
21 |
22 | if (NEEDED_ITEMS - world.player.inventory.items.map(&:name)).empty?
23 | Audio.play_synth(:uncover_secret)
24 | puts 'The pond water explodes with a force that knocks you back onto the ground. When you come to, you notice the depression in the ground where the pond once was now has a new curious object!'
25 | self.description = 'A barren depression in the ground is all that is left of the pond.'
26 | return { type: 'item', data: 'Opalaser' }
27 | else
28 | puts 'You graze your fingers within the pond for a moment, feeling the coolness. You feel zen.'
29 | return { type: nil, data: nil }
30 | end
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/red_key.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/red_key.rb
2 | # Entity::Item::RedKey
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class RedKey < Item
8 | attr_accessor :locked
9 |
10 | def initialize
11 | super
12 |
13 | self.name = 'red_key'
14 | self.name_display = 'Red Key'
15 | self.description = 'Redder than an embarrassed tomato in front of a moderate fire, but still very capable of being a key.'
16 | end
17 |
18 | def describe(world)
19 | super
20 |
21 | cur_location = world.location_by_coords(world.player.cur_coords)
22 | if cur_location.name.eql?('pain_quarry-west')
23 | return desc_text += ' The key "glows" quite intently.'.colorize(:red)
24 | elsif cur_location.name.include?('pain_quarry')
25 | return desc_text += ' The key "glows" almost so brightly you have to shield your eyes.'.colorize(:red)
26 | else
27 | return desc_text += ' The key lightly "glows".'.colorize(:red)
28 | end
29 | end
30 |
31 | def describe_detailed(world)
32 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
33 | desc_text << "(#{name})\n".colorize(:green)
34 | desc_text << "#{description}\n".colorize(:white)
35 |
36 | cur_location = world.location_by_coords(world.player.cur_coords)
37 | if cur_location.name.include?('pain_quarry')
38 | desc_text += "The key O==> *glows* quite intently.\n".colorize(:red)
39 | elsif cur_location.name.eql?('pain_quarry-west')
40 | desc_text += "The key O==> *shines* almost so brightly you have to shield your eyes.\n".colorize(:red)
41 | else
42 | desc_text += "The key O==> lightly *shimmers*.\n".colorize(:red)
43 | end
44 |
45 | desc_text << "TAKEABLE? #{takeable}\n".colorize(:white)
46 | desc_text << "USEABLE? #{useable}\n".colorize(:white)
47 | desc_text << "TALKABLE? #{talkable}\n".colorize(:white)
48 | desc_text << "CONSUMABLE? #{consumable}\n".colorize(:white)
49 | desc_text << "EQUIPPABLE? #{equippable}\n".colorize(:white)
50 | desc_text << "EQUIPPED? #{equipped}\n".colorize(:white)
51 | desc_text << "USED? #{used}\n".colorize(:white)
52 | desc_text << "USED AGAIN? #{used_again}\n".colorize(:white)
53 | desc_text << "USES LEFT? #{number_of_uses}\n".colorize(:white) unless number_of_uses.nil?
54 | desc_text
55 | end
56 |
57 | def use(world)
58 | cur_location = world.location_by_coords(world.player.cur_coords)
59 |
60 | if cur_location.contains_item?('locker')
61 | locker = cur_location.get_item_ref('locker')
62 | if locker.locked
63 | puts 'You place the reddish key into the lock on the locker. Moments later, after a quick turn, the locked locker is no longer locked.'
64 |
65 | locker.locked = false
66 | locker.description = 'A small, unlocked locker with a lock on it. You have unlocked it with a reddish key you found.'
67 | { type: nil, data: nil }
68 | else
69 | puts 'You place the reddish key into the lock on the locker. Moments later, after a quick turn, the locked locker is once again quite locked.'
70 |
71 | locker.locked = true
72 | locker.description = 'A small, locked locker with a lock on it. You will need to unlock it to gain access to its insides.'
73 | { type: nil, data: nil }
74 | end
75 | else
76 | puts 'You try to put the key into one of its natural habitats, but can\'t find anything suitable.'
77 |
78 | { type: nil, data: nil }
79 | end
80 | end
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/rope.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/rope.rb
2 | # Entity::Item::Rope
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Rope < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'rope'
12 | self.name_display = 'Rope'
13 | self.description = 'For some reason, a sturdy rope hangs down from a small opening in the metal tunnel\'s ceiling. It appears to hold your weight when taut.'
14 | end
15 |
16 | def use(world)
17 | puts 'You hold on to the rope with both hands and begin to climb upwards towards the small opening in the ceiling.'
18 | puts
19 |
20 | puts 'After a few minutes you pull yourself up onto a field of pure driven snow. Without warning, the rope and opening in the floor vanish.'
21 | puts
22 |
23 | # stats
24 | world.player.movements_made += 1
25 |
26 | { type: 'move', data: 'Snow Fields (Southeast)' }
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/sand_jewel.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/sand_jewel.rb
2 | # Entity::Item::SandJewel
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class SandJewel < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'sand_jewel'
12 | self.name_display = 'Sand Jewel'
13 | self.description = 'As blue (or is it violet? or brown?) as it is brittle, this shiny rock feels warm to the touch.'
14 | end
15 |
16 | def use(world)
17 | puts 'You lift the sand jewel to the sky; rays of sunlight refract through it and nearly blind you.'
18 | { type: nil, data: nil }
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/shovel.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/shovel.rb
2 | # Entity::Item::Shovel
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Shovel < Item
8 | # CONSTANTS
9 | DIG_NOISE = '*DIG*'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'shovel'
15 | self.name_display = 'Shovel'
16 | self.description = 'You can really "dig" this tool, despite its well-worn appearance.'
17 | end
18 |
19 | def use(world)
20 | cur_location = world.location_by_coords(world.player.cur_coords)
21 |
22 | if cur_location.name.eql?('pain_quarry-west') and cur_location.contains_item?('locker_corner')
23 | puts 'You bolster yourself and then begin the tedious job of digging the locker out of its several-inch-deep prison of sand with your trusty shovel.'
24 | puts
25 |
26 | Animation.run(phrase: DIG_NOISE)
27 | Animation.run(phrase: DIG_NOISE)
28 | Animation.run(phrase: DIG_NOISE)
29 | Animation.run(phrase: DIG_NOISE)
30 | Animation.run(phrase: DIG_NOISE)
31 | Animation.run(phrase: DIG_NOISE)
32 | Animation.run(phrase: DIG_NOISE)
33 | Animation.run(phrase: DIG_NOISE)
34 |
35 | puts
36 | puts 'You drop the head of the shovel into the ground, lean on it for a moment, and wipe the sweat from your brow. This quarry is really causing you considerable pain.'
37 | STDIN.getc
38 |
39 | Animation.run(phrase: DIG_NOISE)
40 | Animation.run(phrase: DIG_NOISE)
41 | Animation.run(phrase: DIG_NOISE)
42 | Animation.run(phrase: DIG_NOISE)
43 | Animation.run(phrase: DIG_NOISE)
44 | Animation.run(phrase: DIG_NOISE)
45 | Animation.run(phrase: DIG_NOISE)
46 | Animation.run(phrase: DIG_NOISE)
47 |
48 | puts
49 | puts 'After what feels like several hours, you finally unearth the locker from the ground, open it, and place it next to its previous location.'
50 |
51 | cur_location.add_item('locker')
52 | cur_location.remove_item('locker_corner')
53 |
54 | { type: 'dmg', data: rand(1..2) }
55 | else
56 | puts 'You grip the shovel by its handle and thrust it, head-first, into the sky. Huzzah!'
57 |
58 | { type: nil, data: nil }
59 | end
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/small_hole.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/small_hole.rb
2 | # Entity::Item::SmallHole
3 |
4 | require_relative '../person'
5 |
6 | module Gemwarrior
7 | class SmallHole < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'small_hole'
12 | self.name_display = 'Small Hole'
13 | self.description = 'Amongst the rubble of the alcove, a small hole, barely big enough for a rodent, exists in an absently-minded way near the bottom of the wall.'
14 | end
15 |
16 | def use(world)
17 | if !self.used
18 | self.used = true
19 |
20 | Audio.play_synth(:uncover_secret)
21 | puts 'You lower yourself to the ground and attempt to peer in the hole in the wall. Just as you begin to think this is a fruitless endeavor, a pair of bright, beady eyes manifest, and an unexpectedly low voice speaks:'
22 | Person.new.speak('Hello. I\'m Rockney, of Rockney\'s Hole in the Wall. Pleasure!')
23 |
24 | tunnel_alcove = world.location_by_name('tunnel_alcove')
25 | tunnel_alcove.items.push(Rockney.new)
26 | puts world.describe(tunnel_alcove)
27 | else
28 | puts 'Rockney appears to still be in the small hole, patiently waiting for you.'
29 | end
30 |
31 | { type: nil, data: nil }
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/snowman.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/snowman.rb
2 | # Entity::Item::Snowman
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Snowman < Item
8 | # CONSTANTS
9 | USE_TEXT = '** FOOOOSH **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'snowman'
15 | self.name_display = 'Snowman'
16 | self.description = 'Standing solemnly in the snow, a man of snow solemnly stands.'
17 | end
18 |
19 | def use(world)
20 | puts 'You go to touch the snowy softness of the snowman when it magically comes to life! The frozen homunculus grabs you by the wrist and tosses you to the ground, only to follow this up by jumping onto you with its full, freezing, force. Your body, and mind, go numb.'
21 | puts
22 |
23 | Animation.run(phrase: USE_TEXT)
24 |
25 | { type: 'move_dangerous', data: 'Home' }
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/sparkly_thing.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/sparklything.rb
2 | # Entity::Item::SparklyThing
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class SparklyThing < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'sparkly_thing'
12 | self.name_display = 'SparklyThing(tm)'
13 | self.description = 'The sparkling that this thing does is unimaginably brilliant.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'Everything, and I mean *everything*, begins to sparkle. Huh.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/stonemite.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/stonemite.rb
2 | # Entity::Item::Stonemite
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Stonemite < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'stonemite'
12 | self.name_display = 'Stonemite'
13 | self.description = 'Stubby cave debris that is neat to look at, as it is off-grey and sparkly, but the size makes it unusable as anything but skipping on a lake.'
14 | self.takeable = true
15 | end
16 |
17 | def use(world)
18 | puts 'You turn the stonemite over and over in your hand. It continues to be a small rock of little import.'
19 | { type: nil, data: nil }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/tent.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/tent.rb
2 | # Entity::Item::Tent
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Tent < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'tent'
12 | self.name_display = 'Tent'
13 | self.description = 'A magical, two-room suite pops up when you flick this otherwise folded piece of canvas just right, perfect for a night\'s rest.'
14 | self.takeable = true
15 | self.number_of_uses = 5
16 | end
17 |
18 | def use(world)
19 | { type: 'tent', data: self.number_of_uses }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/throne.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/throne.rb
2 | # Entity::Item::Throne
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Throne < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'throne'
12 | self.name_display = 'Throne'
13 | self.description = 'Made of what appears to be unfulfilled desires and latent, flawed happiness, the well-crafted seat still looks kinda comfy. The wizard Emerald sits in it, glaring at you.'
14 | end
15 |
16 | def use(world)
17 | puts 'Your words fall on deaf chairs. Emerald continues to stare at you.'
18 | { type: nil, data: nil }
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/tree.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/tree.rb
2 | # Entity::Item::Tree
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Tree < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'tree'
12 | self.name_display = 'Tree'
13 | self.description = 'A mighty representation of nature, older than your father\'s father\'s second great-uncle.'
14 | end
15 |
16 | def use(world)
17 | if self.used_again
18 | puts 'The tree, its trunk, and the hole in its side all seem fairly unremarkable to you now.'
19 |
20 | return { type: nil, data: nil }
21 | elsif self.used
22 | self.used_again = true
23 |
24 | Audio.play_synth(:uncover_secret)
25 |
26 | puts 'Looking further into the small opening in the trunk your eye catches the light glinting off a few small metallic objects.'
27 |
28 | cur_loc = world.location_by_name('forest-southeast')
29 | cur_loc.items.push(Bullet.new)
30 | cur_loc.items.push(Bullet.new)
31 | cur_loc.items.push(Bullet.new)
32 |
33 | return { type: nil, data: nil }
34 | else
35 | self.used = true
36 |
37 | puts 'Taking a passing glance into the only hole in the tree big enough for anything to exist inside, you don\'t quite see anything of value.'
38 |
39 | { type: nil, data: nil }
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/items/waterfall.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/items/waterfall.rb
2 | # Entity::Item::Waterfall
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Waterfall < Item
8 | def initialize
9 | super
10 |
11 | self.name = 'waterfall'
12 | self.name_display = 'Waterfall'
13 | self.description = 'Gallons of murky, sparkling water fall downward from an unknown spot in the sky, ending in a pool on the ground, yet never overflowing.'
14 | end
15 |
16 | def use(world)
17 | puts 'You stretch out your hand and touch the waterfall. It stings you with its cold and forceful gushing. Your hand is now wet and rougher than before. In time, it will dry.'
18 |
19 | dmg = rand(0..1)
20 |
21 | puts '>> You lose a hit point.'.colorize(:red) if dmg > 0
22 |
23 | { type: 'dmg', data: dmg }
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/location.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/location.rb
2 | # Entity::Location
3 | # Place in the game
4 |
5 | require_relative 'entity'
6 | require_relative '../game_options'
7 |
8 | module Gemwarrior
9 | class Location < Entity
10 | # CONSTANTS
11 | DANGER_LEVEL = { none: 0, low: 15, moderate: 30, high: 55, assured: 100 }
12 | ERROR_ITEM_ADD_INVALID = 'That item cannot be added to the location\'s inventory.'
13 | ERROR_ITEM_REMOVE_INVALID = 'That item cannot be removed as it does not exist here.'
14 | ERROR_ITEM_REF_INVALID = 'That item cannot be accessed.'
15 | ERROR_SPAWN_NAME_INVALID = 'That monster does not exist in the game, and cannot be spawned.'
16 |
17 | attr_accessor :coords,
18 | :paths,
19 | :danger_level,
20 | :monster_level_range,
21 | :items,
22 | :monsters_abounding,
23 | :bosses_abounding,
24 | :checked_for_monsters,
25 | :visited
26 |
27 | def initialize(options)
28 | self.name = options.fetch(:name)
29 | self.description = options.fetch(:description)
30 | self.coords = options.fetch(:coords)
31 | self.paths = options.fetch(:paths)
32 | self.danger_level = options.fetch(:danger_level)
33 | self.monster_level_range = options.fetch(:monster_level_range)
34 | self.items = options.fetch(:items)
35 | self.monsters_abounding = options.fetch(:monsters_abounding)
36 | self.bosses_abounding = options.fetch(:bosses_abounding)
37 | self.checked_for_monsters = false
38 | self.visited = false
39 | end
40 |
41 | def describe
42 | desc_text = name.ljust(30).upcase.colorize(:green)
43 | desc_text << coords.values.to_a.to_s.colorize(:white)
44 | desc_text << " DL[#{danger_level.to_s.ljust(8)}] ".colorize(:white) if GameOptions.data['debug_mode']
45 | desc_text << " MLR[#{monster_level_range.to_s.ljust(6)}] ".colorize(:white) if GameOptions.data['debug_mode']
46 | desc_text << "\n"
47 | desc_text << "#{description}".colorize(:white)
48 | desc_text
49 | end
50 |
51 | def describe_detailed
52 | desc_text = "#{name_display.ljust(36).colorize(:yellow)} #{coords.values.to_a.to_s.colorize(:white)}\n"
53 | desc_text << "(#{name})\n".colorize(:green)
54 | desc_text << "#{description}\n".colorize(:white)
55 | desc_text << "DANGER_LEVEL : #{danger_level}\n".colorize(:white)
56 | desc_text << "MONSTER_LEVEL_RANGE: #{monster_level_range}\n".colorize(:white)
57 | desc_text
58 | end
59 |
60 | def contains_item?(item_name)
61 | self.items.map{|i| i.name.downcase}.include?(item_name.downcase)
62 | end
63 |
64 | def has_any_monsters?
65 | monsters_abounding.length > 0
66 | end
67 |
68 | def has_monster?(monster_name)
69 | monsters_abounding.map{|m| m.name.downcase}.include?(monster_name.downcase)
70 | end
71 |
72 | def has_boss?(boss_name)
73 | bosses_abounding.map{|b| b.name.downcase}.include?(boss_name.downcase)
74 | end
75 |
76 | def get_item_ref(item_name)
77 | all_items = GameItems.data | GameWeapons.data | GameArmor.data
78 | all_items.each do |game_item|
79 | if game_item.name.eql?(item_name)
80 | item_ref = self.items.find{ |i| i.name.downcase == item_name.downcase }
81 | return item_ref
82 | end
83 | end
84 | return ERROR_ITEM_REF_INVALID
85 | end
86 |
87 | def add_item(item_name_to_add)
88 | all_items = GameItems.data | GameWeapons.data | GameArmor.data
89 | all_items.each do |game_item|
90 | if game_item.name.eql?(item_name_to_add)
91 | self.items.push(game_item)
92 | return
93 | end
94 | end
95 | return ERROR_ITEM_ADD_INVALID
96 | end
97 |
98 | def remove_item(item_name)
99 | if contains_item?(item_name)
100 | self.items.delete_at(items.index(items.find { |i| i.name.downcase == item_name.downcase }))
101 | else
102 | ERROR_ITEM_REMOVE_INVALID
103 | end
104 | end
105 |
106 | def remove_monster(name)
107 | monsters_abounding.reject! { |monster| monster.name == name }
108 | bosses_abounding.reject! { |boss| boss.name == name }
109 | end
110 |
111 | def has_loc_to_the?(direction)
112 | case direction
113 | when 'n'
114 | direction = 'north'
115 | when 'e'
116 | direction = 'east'
117 | when 's'
118 | direction = 'south'
119 | when 'w'
120 | direction = 'west'
121 | end
122 | paths[direction.to_sym]
123 | end
124 |
125 | def monster_by_name(monster_name)
126 | monsters_list = monsters_abounding | bosses_abounding
127 |
128 | monsters_list.each do |m|
129 | if m.name.downcase.eql?(monster_name.downcase)
130 | return m.clone
131 | end
132 | end
133 | end
134 |
135 | def checked_for_monsters?
136 | checked_for_monsters
137 | end
138 |
139 | def should_spawn_monster?
140 | found = false
141 | unless danger_level.eql?(:none)
142 | max = DANGER_LEVEL[danger_level]
143 | trigger_values = 0..max
144 | actual_value = rand(1..100)
145 |
146 | if trigger_values.include?(actual_value)
147 | found = true
148 | end
149 | end
150 | return found
151 | end
152 |
153 | def list_items
154 | if items.empty?
155 | []
156 | else
157 | # build hash out of location's items
158 | item_hash = {}
159 | self.items.map(&:name).each do |i|
160 | i_sym = i.to_sym
161 | if item_hash.keys.include? i_sym
162 | item_hash[i_sym] += 1
163 | else
164 | item_hash[i_sym] = 1
165 | end
166 | end
167 |
168 | # one item? return single element array
169 | if item_hash.length == 1
170 | i = item_hash.keys
171 | q = item_hash.values.join.to_i
172 | return q > 1 ? ["#{q} #{i}s"] : i
173 | # multiple items? build an array of strings
174 | else
175 | item_arr = []
176 | item_hash.each do |i, q|
177 | if q > 1
178 | item_arr.push("#{i.to_s.colorize(:yellow)}#{'s'.colorize(:yellow)} x#{q}")
179 | else
180 | item_arr.push(i)
181 | end
182 | end
183 |
184 | return item_arr
185 | end
186 | end
187 | end
188 |
189 | def list_monsters
190 | monsters_abounding.length > 0 ? monsters_abounding.map(&:name) : []
191 | end
192 |
193 | def list_bosses
194 | bosses_abounding.length > 0 ? bosses_abounding.map(&:name_display) : []
195 | end
196 |
197 | def list_paths
198 | valid_paths = []
199 | self.paths.each do |key, value|
200 | if value
201 | valid_paths.push(key.to_s)
202 | end
203 | end
204 | return valid_paths
205 | end
206 |
207 | def list_actionable_words
208 | actionable_words = []
209 | actionable_words.push(monsters_abounding.map(&:name)) unless monsters_abounding.empty?
210 | actionable_words.push(bosses_abounding.map(&:name)) unless bosses_abounding.empty?
211 | actionable_words.push(items.map(&:name)) unless items.empty?
212 | actionable_words.join(', ')
213 | end
214 |
215 | def populate_monsters(monsters_available = nil, spawn = false, monster_type = nil)
216 | # debug spawn
217 | if spawn
218 | random_monster = nil
219 |
220 | # debug spawn random monster
221 | if monster_type.nil?
222 | loop do
223 | random_monster = monsters_available[rand(0..monsters_available.length-1)].clone
224 |
225 | monsters_abounding.push(random_monster)
226 | break
227 | end
228 | # debug spawn w/ monster_type
229 | else
230 | monster_type_to_spawn = monsters_available.find { |m| m.name.downcase == monster_type.downcase }
231 | if monster_type_to_spawn.nil?
232 | puts ERROR_SPAWN_NAME_INVALID.colorize(:red)
233 | puts
234 | else
235 | monsters_abounding.push(monster_type_to_spawn)
236 | end
237 | end
238 | # normal location spawn
239 | elsif should_spawn_monster?
240 | self.checked_for_monsters = true
241 | self.monsters_abounding = []
242 | random_monster = nil
243 |
244 | # get random non-boss monster
245 | loop do
246 | random_monster = monsters_available[rand(0..monsters_available.length-1)].clone
247 |
248 | if !random_monster.is_boss && self.monster_level_range.include?(random_monster.level)
249 | monsters_abounding.push(random_monster)
250 | break
251 | end
252 | end
253 | else
254 | return nil
255 | end
256 | end
257 | end
258 | end
259 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monster.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monster.rb
2 | # Entity::Creature::Monster
3 |
4 | require_relative 'creature'
5 | require_relative 'items/herb'
6 | require_relative 'items/bullet'
7 |
8 | module Gemwarrior
9 | class Monster < Creature
10 | ITEM_POOL = [Herb.new, Bullet.new]
11 |
12 | attr_accessor :battlecry,
13 | :is_boss,
14 | :is_dead
15 |
16 | def initialize
17 | super
18 |
19 | self.inventory = Inventory.new
20 | self.useable = true
21 | self.talkable = true
22 | self.is_dead = false
23 | 3.times do
24 | if [true, false].sample
25 | self.inventory.add_item(ITEM_POOL[rand(0..ITEM_POOL.length-1)])
26 | end
27 | end
28 | end
29 |
30 | def describe_detailed
31 | desc_text = "\"#{name_display}\"".colorize(:yellow)
32 | desc_text << '(BOSS)'.ljust(13).colorize(:yellow) if is_boss
33 | desc_text << "\n"
34 | desc_text << "(#{name})\n".colorize(:green)
35 | desc_text << "#{description}\n".colorize(:white)
36 | desc_text << "FACE : #{face}\n".colorize(:white)
37 | desc_text << "HANDS: #{hands}\n".colorize(:white)
38 | desc_text << "MOOD : #{mood}\n".colorize(:white)
39 | desc_text << "LVL : #{level}\n".colorize(:white)
40 | desc_text << "HP : #{hp_cur}/#{hp_max}\n".colorize(:white)
41 | desc_text << "ATK : #{atk_lo}-#{atk_hi}\n".colorize(:white)
42 | desc_text << "DEF : #{defense}\n".colorize(:white)
43 | desc_text << "DEX : #{dexterity}\n".colorize(:white)
44 | desc_text << "ROX : #{rox}\n".colorize(:white)
45 | desc_text << "XP : #{xp}\n".colorize(:white)
46 | desc_text << "INV : #{inventory.contents}\n".colorize(:white)
47 | desc_text << "DEAD? #{is_dead}\n".colorize(:white)
48 | desc_text << "TALK? #{talkable}\n".colorize(:white)
49 | desc_text << "USE? #{useable}\n".colorize(:white)
50 | desc_text
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/alexandrat.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/alexandrat.rb
2 | # Entity::Creature::Monster::Alexandrat
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Alexandrat < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'alexandrat'
12 | self.name_display = 'Alexandrat'
13 | self.description = 'Tiny, but fierce, color-changing rodent.'
14 | self.battlecry = 'Bitey, bitey!'
15 | self.face = 'ugly'
16 | self.hands = 'gnarled'
17 | self.mood = 'unchipper'
18 |
19 | self.level = rand(1..2)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 1.5).floor)
23 | self.atk_hi = rand((level * 1.5).floor..(level * 2))
24 | self.defense = rand(1..2)
25 | self.dexterity = rand(1..3)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/amberoo.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/amberoo.rb
2 | # Entity::Creature::Monster::Amberoo
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Amberoo < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'amberoo'
12 | self.name_display = 'Amberoo'
13 | self.description = 'Fossilized and jumping around like an adorably dangerous threat from the past.'
14 | self.battlecry = 'I\'m hoppin\' mad!'
15 | self.face = 'punchy'
16 | self.hands = 'balled'
17 | self.mood = 'jumpy'
18 |
19 | self.level = rand(1..2)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 2))
23 | self.atk_hi = rand((level * 2)..(level * 2.5).floor)
24 | self.defense = rand(2..3)
25 | self.dexterity = rand(2..4)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/amethystle.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/amethystle.rb
2 | # Entity::Creature::Monster::Amethystle
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Amethystle < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'amethystle'
12 | self.name_display = 'Amethystle'
13 | self.description = 'Sober and contemplative, it moves with purplish tentacles swaying in the breeze.'
14 | self.battlecry = 'You\'ve found yourself in quite the thorny issue!'
15 | self.face = 'sharp'
16 | self.hands = 'loose'
17 | self.mood = 'mesmerizing'
18 |
19 | self.level = rand(2..3)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 1.5).floor)
23 | self.atk_hi = rand((level * 1.5).floor..(level * 2.5).floor)
24 | self.defense = rand(2..4)
25 | self.dexterity = rand(1..2)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/apatiger.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/apatiger.rb
2 | # Entity::Creature::Monster::Apatiger
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Apatiger < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'apatiger'
12 | self.name_display = 'Apatiger'
13 | self.description = 'Apathetic about most everything as it lazes around, save for eating you.'
14 | self.battlecry = 'Gggggggggrrrrrrrrrrrrrrrrooooooooooowwwwwwwwwwwwlllllllll!'
15 | self.face = 'calloused'
16 | self.hands = 'soft'
17 | self.mood = 'apathetic'
18 |
19 | self.level = rand(4..5)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 1.5).floor)
23 | self.atk_hi = rand((level * 1.5).floor..(level * 2.5).floor)
24 | self.defense = rand(4..7)
25 | self.dexterity = rand(3..7)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/aquamarine.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/aquamarine.rb
2 | # Entity::Creature::Monster::Aquamarine
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Aquamarine < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'aquamarine'
12 | self.name_display = 'Aquamarine'
13 | self.description = 'It is but one of the few, the proud, the underwater.'
14 | self.battlecry = 'Attention! You are about to get smashed!'
15 | self.face = 'strained'
16 | self.hands = 'hairy'
17 | self.mood = 'tempered'
18 |
19 | self.level = rand(3..4)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 1.5).floor)
23 | self.atk_hi = rand((level * 1.5).floor..(level * 2.5).floor)
24 | self.defense = rand(3..5)
25 | self.dexterity = rand(4..6)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/bloodstorm.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/bloodstorm.rb
2 | # Entity::Creature::Monster::Bloodstorm
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Bloodstorm < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'bloodstorm'
12 | self.name_display = 'Bloodstorm'
13 | self.description = 'A literal swirling, maniacal vortex of human hemoglobin.'
14 | self.battlecry = '/swirls'
15 | self.face = 'bloody'
16 | self.hands = 'bloody'
17 | self.mood = 'boiling'
18 |
19 | self.level = rand(5..6)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 1.5).floor)
23 | self.atk_hi = rand((level * 1.5).floor..(level * 3).floor)
24 | self.defense = rand(6..7)
25 | self.dexterity = rand(5..7)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/bosses/emerald.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/bosses/emerald.rb
2 | # Entity::Creature::Monster::Emerald (BOSS)
3 |
4 | require_relative '../../monster'
5 | require_relative '../../items/sparkly_thing'
6 |
7 | module Gemwarrior
8 | class Emerald < Monster
9 | # CONSTANTS
10 | MOVE_TEXT = '** WHOOOOOOSH **'
11 |
12 | def initialize
13 | super
14 |
15 | self.name = 'emerald'
16 | self.name_display = 'Emerald'
17 | self.description = 'A wily, beefy, tower of a man, Emerald looks to be a champion of both wisdom, from what you\'ve heard, AND strength, from what you plainly see. He sports a constant glint in his eyes as he faces you, dead-on.'
18 | self.battlecry = 'You\'ve come for the SparklyThing(tm), I see. Well, you cannot have it, because it is mine, and I will wield it to my own desire! Oh, you think you are good and I am evil? To that I say: Ha ha ha ha ha! Prepare yourself fool: today your whole life crumbles!'
19 | self.face = 'gleaming'
20 | self.hands = 'tantalizing'
21 | self.mood = 'enraged'
22 |
23 | self.level = 15
24 | self.hp_cur = rand((level * 8)..(level * 9))
25 | self.hp_max = hp_cur
26 | self.atk_lo = rand((level * 2)..(level * 2.5).floor)
27 | self.atk_hi = rand((level * 2.5).floor..(level * 3).floor)
28 | self.defense = rand(10..12)
29 | self.dexterity = rand(12..14)
30 |
31 | self.inventory = Inventory.new(items = [SparklyThing.new])
32 | self.rox = rand((level * 9)..(level * 11))
33 | self.xp = rand((level * 13)..(level * 15))
34 |
35 | self.is_boss = true
36 | end
37 |
38 | def initiate_ending(world)
39 | # fanfare!
40 | Audio.play_synth(:win_game)
41 |
42 | # get reference to throne room, emerald monster, and throne item
43 | throne_room = world.location_by_coords(world.location_coords_by_name('Sky Tower (Throne Room)'))
44 | emerald = throne_room.bosses_abounding[0]
45 | throne = throne_room.items.each { |i| i.name == 'throne' }[0]
46 |
47 | # emerald is dead, so room and items change
48 | emerald.is_dead = true
49 | emerald.face = 'sullen'
50 | emerald.hands = 'limp'
51 | emerald.mood = 'blank'
52 | emerald.hp_cur = 0
53 | emerald.rox = 0
54 | emerald.description = 'Emerald slumps over in his chair, completely lifeless. The color has drained from his eyes and a pallor has been cast over his face. His reign is no more.'
55 | throne_room.description = 'Emerald\'s throne room feels much less imposing now that you have defeated him in mortal combat. Who knew?'
56 | throne_room.danger_level = :none
57 | throne_room.monster_level_range = nil
58 | throne_room.monsters_abounding = []
59 | throne.description = 'The grim spectacle of Emerald\'s dead body drooping blankly in his chosen seat really brings down the market value of it, you guess.'
60 |
61 | # world knows you beat emerald
62 | world.emerald_beaten = true
63 |
64 | # remove sparkly_thing from emerald
65 | emerald.inventory.remove_item('sparkly_thing')
66 | # give player sparkly_thing
67 | world.player.inventory.items.push(SparklyThing.new)
68 |
69 | # ending text
70 | puts '<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>'
71 | puts "You beat #{name}! You win! You receive the #{"SparklyThing(tm)".colorize(:magenta)} and become the true #{"Gem Warrior".colorize(:yellow)}!"
72 | puts '<^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^><^>'
73 | STDIN.getc
74 |
75 | puts 'Suddenly, an icy feeling shoots up your back. You feel lighter than air. Blackness takes over.'
76 | STDIN.getc
77 |
78 | # onto the queen
79 | Animation.run(phrase: MOVE_TEXT)
80 | puts
81 |
82 | return { type: 'move', data: 'Queen Room'}
83 | end
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/bosses/garynetty.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/bosses/garynetty.rb
2 | # Entity::Creature::Monster::Garrynetty (BOSS)
3 |
4 | require_relative '../../monster'
5 | require_relative '../../items/tent'
6 |
7 | module Gemwarrior
8 | class Garynetty < Monster
9 | def initialize
10 | super
11 |
12 | self.name = 'garynetty'
13 | self.name_display = 'Garynetty'
14 | self.description = 'Conservative, yet odd, the Garynetty is not messing around.'
15 | self.battlecry = '...?!'
16 | self.face = 'irregular'
17 | self.hands = 'sharp'
18 | self.mood = 'abrasive'
19 |
20 | self.level = rand(10..12)
21 | self.hp_cur = rand((level * 4.5).floor..(level * 5.5).floor)
22 | self.hp_max = hp_cur
23 | self.atk_lo = rand((level * 2)..(level * 2.5).floor)
24 | self.atk_hi = rand((level * 2.5).floor..(level * 3).floor)
25 | self.defense = rand(7..9)
26 | self.dexterity = rand(10..12)
27 |
28 | self.inventory = random_item
29 | self.rox = rand((level * 5)..(level * 6))
30 | self.xp = rand((level * 7)..(level * 11))
31 |
32 | self.is_boss = true
33 | end
34 |
35 | private
36 |
37 | def random_item
38 | if [true, false].sample
39 | Inventory.new(items = [Tent.new])
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/bosses/jaspern.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/bosses/jaspern.rb
2 | # Entity::Creature::Monster::Jaspern (BOSS)
3 |
4 | require_relative '../../monster'
5 | require_relative '../../items/tent'
6 |
7 | module Gemwarrior
8 | class Jaspern < Monster
9 | def initialize
10 | super
11 |
12 | self.name = 'jaspern'
13 | self.name_display = 'Jaspern'
14 | self.description = 'Dark green hair, but yellow and brown skin, Jaspern is actually somewhat translucent, and he does not appear to be moveable or go-around-able.'
15 | self.battlecry = 'I am the keeper of this bridge! To go further, you must get through me!'
16 | self.face = 'crystalline'
17 | self.hands = 'small'
18 | self.mood = 'opaque'
19 |
20 | self.level = rand(7..8)
21 | self.hp_cur = rand((level * 4.5).floor..(level * 5.5).floor)
22 | self.hp_max = hp_cur
23 | self.atk_lo = rand((level * 2)..(level * 2.5).floor)
24 | self.atk_hi = rand((level * 2.5).floor..(level * 3).floor)
25 | self.defense = rand(5..7)
26 | self.dexterity = rand(8..9)
27 |
28 | self.inventory = random_item
29 | self.rox = rand((level * 6)..(level * 7))
30 | self.xp = rand((level * 8)..(level * 10))
31 |
32 | self.is_boss = true
33 | end
34 |
35 | def use(world)
36 | speak('You are not going any further north, little man. No matter of talking will move me!')
37 | end
38 |
39 | def river_bridge_success(world)
40 | # get object references
41 | river_bridge = world.location_by_name('river_bridge')
42 | jaspern = river_bridge.bosses_abounding[0]
43 |
44 | # mark jaspern as dead
45 | jaspern.is_dead = true
46 | jaspern.face = 'broken'
47 | jaspern.hands = 'limp'
48 | jaspern.mood = 'defeated'
49 | jaspern.hp_cur = 0
50 | jaspern.rox = 0
51 | jaspern.description = 'As Jaspern lies motionless upon the ground, you feel sorry for murdering him in cold blood without any provocation, but you feel like he was probably bad, and you really needed to explore further north. Regardless, it looks like you own the bridge now.'
52 | jaspern.inventory = Inventory.new
53 |
54 | # unlock northward travel
55 | river_bridge.description = 'The path northward on this well-constructed bridge is no longer blocked after your brutal scuffle with Jaspern, and yet the flowing river below seems unperturbed.'
56 | river_bridge.paths[:north] = true
57 | return
58 | end
59 |
60 | private
61 |
62 | def random_item
63 | if [true, false].sample
64 | Inventory.new(items = [Tent.new])
65 | else
66 | Inventory.new
67 | end
68 | end
69 | end
70 | end
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/citrinaga.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/citrinaga.rb
2 | # Entity::Creature::Monster::Citrinaga
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Citrinaga < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'citrinaga'
12 | self.name_display = 'Citrinaga'
13 | self.description = 'Refreshing in its shiny, gleaming effectiveness at ending your life.'
14 | self.battlecry = 'Slice and dice so nice!'
15 | self.face = 'shiny'
16 | self.hands = 'glistening'
17 | self.mood = 'staid'
18 |
19 | self.level = rand(5..7)
20 | self.hp_cur = rand((level * 2)..(level*3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level*1.5).floor)
23 | self.atk_hi = rand((level*1.5).floor..(level*3).floor)
24 | self.defense = rand(7..9)
25 | self.dexterity = rand(6..7)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 3))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/coraliz.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/coraliz.rb
2 | # Entity::Creature::Monster::Coraliz
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Coraliz < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'coraliz'
12 | self.name_display = 'Coraliz'
13 | self.description = 'Small blue lizard that slithers around, nipping at your ankles.'
14 | self.battlecry = 'Where am I? You\'ll never guess!'
15 | self.face = 'spotted'
16 | self.hands = 'slippery'
17 | self.mood = 'emotionless'
18 |
19 | self.level = rand(5..8)
20 | self.hp_cur = rand((level * 2)..(level*3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 3).floor)
23 | self.atk_hi = rand((level * 3).floor..(level * 3).floor)
24 | self.defense = rand(4..6)
25 | self.dexterity = rand(7..9)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 3))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/cubicat.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/cubicat.rb
2 | # Entity::Creature::Monster::Cubicat
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Cubicat < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'cubicat'
12 | self.name_display = 'Cubicat'
13 | self.description = 'Perfectly geometrically cubed feline, fresh from its woven enclosure, claws at the ready.'
14 | self.battlecry = 'I don\'t really care, as long as you die!'
15 | self.face = 'striking'
16 | self.hands = 'grippy'
17 | self.mood = 'salacious'
18 |
19 | self.level = rand(6..8)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 2).floor)
23 | self.atk_hi = rand((level * 2).floor..(level * 3).floor)
24 | self.defense = rand(5..7)
25 | self.dexterity = rand(8..10)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/monsters/diaman.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/monsters/diaman.rb
2 | # Entity::Creature::Monster::Diaman
3 |
4 | require_relative '../monster'
5 |
6 | module Gemwarrior
7 | class Diaman < Monster
8 | def initialize
9 | super
10 |
11 | self.name = 'diaman'
12 | self.name_display = 'Diaman'
13 | self.description = 'Crystalline structure in the form of a man, lumbering toward you, with outstretched, edged pincers.'
14 | self.battlecry = 'Precious human, prepare to be lost to the annals of time!'
15 | self.face = 'bright'
16 | self.hands = 'jagged'
17 | self.mood = 'adamant'
18 |
19 | self.level = rand(8..10)
20 | self.hp_cur = rand((level * 2)..(level * 3))
21 | self.hp_max = hp_cur
22 | self.atk_lo = rand(level..(level * 2.5).floor)
23 | self.atk_hi = rand((level * 2.5).floor..(level * 3).floor)
24 | self.defense = rand(6..7)
25 | self.dexterity = rand(8..10)
26 |
27 | self.rox = rand((level * 2)..(level * 3))
28 | self.xp = rand(level..(level * 2))
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/arena_master.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/arena_master.rb
2 | # Entity::Creature::Person::ArenaMaster
3 |
4 | require_relative '../person'
5 |
6 | module Gemwarrior
7 | class ArenaMaster < Person
8 | # CONSTANTS
9 | ARENA_FEE = 50
10 | ARENA_MASTER_NAME = 'Iolita'
11 |
12 | def initialize
13 | super
14 |
15 | self.name = 'arena_master'
16 | self.name_display = 'Arena Master'
17 | self.description = 'She wears simple clothing, but carries herself with an air of authority. You think she may be the person to talk with if you want to engage in battle.'
18 | end
19 |
20 | def use(world)
21 | puts "You approach #{ARENA_MASTER_NAME.colorize(color: :white, background: :black)}, the Arena Master, and ask to prove your mettle in the arena. She snickers to herself, but sees you have a good spirit about you."
22 | puts
23 |
24 | if world.player.rox >= ARENA_FEE
25 | print "She asks for the requisite payment: #{ARENA_FEE} rox. Do you pay up? (y/n) "
26 | answer = gets.chomp.downcase
27 |
28 | case answer
29 | when 'y', 'yes'
30 | world.player.rox -= ARENA_FEE
31 | puts
32 | puts 'She pockets the money and motions toward the center of the arena. She reminds you that you will be facing an ever-worsening onslaught of monsters. Each one you dispatch nets you a bonus cache of rox in addition to whatever the monster gives you. You will also become more experienced the longer you last. Finally, you can give up at any time between battles.'
33 | puts
34 | puts 'She finishes by wishing you good luck!'
35 |
36 | return { type: 'arena', data: nil }
37 | else
38 | puts
39 | puts 'She gives you a dirty look, as you have obviously wasted her time. You are told not to mess around with her anymore, and she turns away from you.'
40 | return { type: nil, data: nil }
41 | end
42 | else
43 | puts 'She can tell you seem particularly poor today and says to come back when that has changed.'
44 | puts
45 | return { type: nil, data: nil }
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/drunk_man.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/drunk_man.rb
2 | # Entity::Creature::Person::DrunkMan
3 |
4 | require_relative '../person'
5 | require_relative '../../misc/formatting'
6 |
7 | module Gemwarrior
8 | class DrunkMan < Person
9 | include Formatting
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'drunk_man'
15 | self.name_display = 'Drunk Man'
16 | self.description = 'Some supernatural force is surely keeping this obviously smashed individual from toppling over to the ground. The inebriated fellow somehow continues to stumble about in a small circle near a smattering of shipping crates, looking simultaneously dazed and cheerful.'
17 | end
18 |
19 | def use(world)
20 | choose_blurting
21 |
22 | self.used = [true, false].sample
23 |
24 | { type: nil, data: nil }
25 | end
26 |
27 | private
28 |
29 | def choose_blurting
30 | choice = [1, 2, 3, 4].sample
31 |
32 | case choice
33 | when 1
34 | speak(to_hooch('I still can\'t believe I lost at the Arena! I was doing so well, and then a slippery citrinaga got a cheap shot on me.'))
35 | speak(to_hooch('Ehhh. Someday I\'ll be back and I\'ll be victorious. That smarmy Arena Master ain\'t gettin\' the last word!'))
36 | when 2
37 | speak(to_hooch('Maybe I just needed a better weapon that last fight in the arena. Yeah! That must be it.'))
38 | when 3
39 | speak(to_hooch('Man, my head really hurts. I\'m not sure if it\'s because of the fighting or the booze.'))
40 | speak(to_hooch('I should probably get something else to drink.'))
41 | puts 'The man looks like he has thought of something genius for a moment, but then scratches his head while stumbling around in his well-worn circle again.'
42 | when 4
43 | speak(to_hooch('Ahhhhhhhhhhhhhhhhhhhh!'))
44 | puts 'He begins to quickly become frantic as he notices you approaching, and then falls over, crumpled to the floor.'
45 | puts
46 | puts 'You approach to check if he\'s still breathing. As you get closer, he gets back up, hardly noticing you, and begins his spiral once again.'
47 | end
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/queen_ruby.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/queen_ruby.rb
2 | # Entity::Creature::Person::QueenRuby
3 |
4 | require_relative '../person'
5 | require_relative '../../misc/animation'
6 |
7 | module Gemwarrior
8 | class QueenRuby < Person
9 | # CONSTANTS
10 | MOVE_TEXT = '** WHOOOOOOSH **'
11 |
12 | def initialize
13 | super
14 |
15 | self.name = 'queen_ruby'
16 | self.name_display = 'Queen Ruby'
17 | self.description = 'Queen Ruby glimmers like she was made from the substance of her name. She wears a wan smile, and her hands are delicately intertwined as she sits patiently.'
18 | end
19 |
20 | def use(world)
21 | speak('Thank you for bringing back the ShinyThing(tm)! The land of Jool is saved!')
22 | STDIN.getc
23 | speak("Please, #{world.player.name}, hand the ShinyThing(tm) to me, before all is lost!")
24 |
25 | print 'Hand over the ShinyThing(tm)? (y/n) '
26 | answer = gets.chomp.downcase
27 |
28 | case answer
29 | when 'y', 'yes'
30 | if world.player.inventory.contains_item?('sparkly_thing')
31 | world.player.inventory.remove_item('sparkly_thing')
32 | speak('Oh, thank you! Now that the evil Emerald is defeated, and I, Queen Ruby, have the ShinyThing(tm) again, peace can come to the land of Jool.')
33 | speak('Your reward is', no_end_quote = true, no_line_feed = true)
34 | Animation.run(phrase: '......', oneline: true, speed: :slow, color: :yellow, numeric: false, alpha: false)
35 | Animation.run(phrase: 'my thanks!', oneline: true, speed: :insane, color: :yellow)
36 | print '"'.colorize(:yellow)
37 | print "\n"
38 | STDIN.getc
39 | puts 'You feel an audible groan spill out of your mouth, but Queen Ruby doesn\'t seem to notice.'
40 | STDIN.getc
41 | speak('Now, be a dear and run on home.')
42 | STDIN.getc
43 | puts 'And with that, she waves her arm in a tired, yet mystical, manner. Your mind and sight go blank, and you "poof" out of existence.'
44 | puts
45 |
46 | Animation.run(phrase: MOVE_TEXT)
47 | puts
48 | return { type: 'move', data: 'home' }
49 | else
50 | speak('Hold on a minute!', no_end_quote = false, no_line_feed = true)
51 | STDIN.getc
52 | speak('You don\'t even have the SparklyThing(tm)!', no_end_quote = false, no_line_feed = true)
53 | STDIN.getc
54 | speak('How on earth did you even get here without unknowningly being transported after acquiring it?', no_end_quote = false, no_line_feed = true)
55 | STDIN.getc
56 | speak('...', no_end_quote = false, no_line_feed = true)
57 | STDIN.getc
58 | speak('...are you a wizard?!')
59 |
60 | return { type: nil, data: nil }
61 | end
62 | when 'n', 'no'
63 | speak('No? No??? Well, you are not leaving this room until you do, so think long and hard about that.')
64 | return { type: nil, data: nil }
65 | else
66 | speak('Hmm. I see. Take your time and let me know when you are going to give me the ShinyThing(tm), all right?')
67 | return { type: nil, data: nil }
68 | end
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/rockney.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/rockney.rb
2 | # Entity::Creature::Person::Rockney
3 |
4 | require_relative '../item'
5 | require_relative '../items/herb'
6 | require_relative '../weapons/dagger'
7 |
8 | module Gemwarrior
9 | class Rockney < Person
10 | # CONSTANTS
11 | PRICE_HERB = 5
12 | PRICE_DAGGER = 10
13 | PLAYER_ROX_INSUFFICIENT = 'Pity. You are a bit short on funds to purchase that item.'
14 | PLAYER_ITEMS_ADDITIONAL = 'Anything else?'
15 | PLAYER_COMMAND_INVALID = 'Huh?'
16 |
17 | def initialize
18 | super
19 |
20 | self.name = 'rockney'
21 | self.name_display = 'Rockney'
22 | self.description = 'The rat with a name looks at you, not with malice, but with kindness. Odd for a rodent hiding in a hole in a dark, metal tunnel.'
23 | self.talkable = true
24 | end
25 |
26 | def use(world)
27 | if !self.used
28 | puts 'You\'re not sure what to expect when you confront the small animal living in the crevice, but you figure it\'s this or doing anything else at all, so...'
29 | puts
30 | end
31 |
32 | rat_shop(world)
33 | end
34 |
35 | private
36 |
37 | def rat_shop(world)
38 | player_rox_remaining = world.player.rox
39 | amount_spent = 0
40 | items_purchased = []
41 |
42 | herb = Herb.new
43 | dagger = Dagger.new
44 |
45 | speak('Hello, wanderer. Welcome to my establishment, as it were. Are you in need of anything?')
46 | puts
47 | puts 'The creature gently shoves a small slip of paper out of his hole and towards you. You take a peek and notice it has a list of things with prices on it.'
48 | puts
49 | puts 'Rockney\'s Hole in the Wall'.colorize(:cyan)
50 | puts '--------------------------'
51 | puts "(1) #{'Herb'.colorize(:yellow)} - #{PRICE_HERB} rox"
52 | puts " #{herb.description}"
53 | puts "(2) #{'Dagger'.colorize(:yellow)} - #{PRICE_DAGGER} rox"
54 | puts " #{dagger.description}"
55 | puts " Attack: +#{dagger.atk_lo}-#{dagger.atk_hi} (current: #{world.player.atk_lo}-#{world.player.atk_hi})"
56 | puts
57 | speak('What are you in need of?')
58 |
59 | loop do
60 | puts " 1 - Herb #{PRICE_HERB}"
61 | puts " 2 - Dagger #{PRICE_DAGGER}"
62 | print ' x - leave'
63 | if items_purchased.length > 0
64 | print ", and buy items\n"
65 | else
66 | print "\n"
67 | end
68 | puts
69 | print 'REMAINING ROX: '
70 | Animation.run(phrase: player_rox_remaining.to_s, oneline: true)
71 | print "\n"
72 | display_shopping_cart(items_purchased)
73 | print '[ROCKNEY]>? '
74 |
75 | choice = gets.chomp.downcase
76 |
77 | case choice
78 | when '1'
79 | if player_rox_remaining >= PRICE_HERB
80 | player_rox_remaining -= PRICE_HERB
81 | items_purchased.push(Herb.new)
82 | amount_spent += PRICE_HERB
83 |
84 | speak('Excellent choice.')
85 | speak(PLAYER_ITEMS_ADDITIONAL)
86 | next
87 | else
88 | speak(PLAYER_ROX_INSUFFICIENT)
89 | next
90 | end
91 | when '2'
92 | if world.player.rox >= PRICE_DAGGER
93 | world.player.rox -= PRICE_DAGGER
94 | items_purchased.push(Dagger.new)
95 | amount_spent += PRICE_DAGGER
96 |
97 | display_shopping_cart(items_purchased)
98 | speak('A fine blade, indeed.')
99 | speak(PLAYER_ITEMS_ADDITIONAL)
100 | next
101 | else
102 | speak(PLAYER_ROX_INSUFFICIENT)
103 | next
104 | end
105 | when 'x'
106 | return_type = { type: nil, data: nil }
107 | if items_purchased.length > 0
108 | display_shopping_cart(items_purchased)
109 | speak('Are you certain you wish to buy these things? (y/n)')
110 | print '[ROCKNEY]> '
111 |
112 | answer = gets.chomp.downcase
113 |
114 | return_type = nil
115 | case answer
116 | when 'y', 'yes'
117 | world.player.rox -= amount_spent
118 | speak('Enjoy!')
119 | return_type = { type: 'purchase', data: items_purchased }
120 | else
121 | return_type = { type: nil, data: nil }
122 | end
123 | end
124 | speak('If you need anything further, I\'m always in this hole...')
125 | return return_type
126 | else
127 | speak(PLAYER_COMMAND_INVALID)
128 | next
129 | end
130 | end
131 | end
132 | end
133 | end
134 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/shifty_woman.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/shifty_woman.rb
2 | # Entity::Creature::Person::ShiftyWoman
3 |
4 | require_relative '../person'
5 |
6 | module Gemwarrior
7 | class ShiftyWoman < Person
8 | # CONSTANTS
9 | SHOO_TEXT = '** BAMF **'
10 |
11 | def initialize
12 | super
13 |
14 | self.name = 'shifty_woman'
15 | self.name_display = 'Shifty Woman'
16 | self.description = 'Sharply dressed with impeccable style, you still can\'t shake the feeling that this otherwise ordinary woman is up to something. It might be the way she almost impulsively looks back and forth along the town street while rubbing her hands together menacingly.'
17 | end
18 |
19 | def use(world)
20 | if self.used
21 | puts 'Attempting a friendly overture again, the woman turns and looks directly at you. Her brown eyes glint in the sun, almost turning an ochre hue. Her look burns you to the core, causing you to physically recoil a little.'
22 | STDIN.getc
23 | puts 'She then growls in a low voice at you:'
24 | speak('Have you heard of Emerald, the good-for-nothing wizard that doomed our little world of Jool by absconding with the SparklyThing(tm)?')
25 | STDIN.getc
26 | puts 'Before you can even begin to answer she throws up her hands and continues, stealing a look off to the side:'
27 | speak('My life was fine before that idiot decided he needed MORE power than he already has.')
28 | STDIN.getc
29 | puts 'She crosses her arms and looks down, seemingly in thought. One of her hands rolls around, a small flicker of light dancing around it as it moves.'
30 | STDIN.getc
31 | speak("If only I had some #{"tanzanite".colorize(:blue)}...I could cook up a spell that would take down ol' Em faster than he could lift a wand!")
32 | STDIN.getc
33 | if world.player.inventory.contains_item?('sand_jewel')
34 | puts 'Her head tilts upward, ever so slightly, and she looks at you, one eyebrow cocked:'
35 | speak('I can sense you might have what I need. I know you want to get rid of Emerald and take back the SparklyThing(tm) to give to our beloved queen, too.')
36 | STDIN.getc
37 | speak('I can help. Just give me that little piece of shiny you somehow came across in your travels, and I\'ll do everything in my power to make our shared goal a reality.')
38 | print 'Give the shifty woman your Sand Jewel? (y/n) '
39 | answer = gets.chomp.downcase
40 |
41 | case answer
42 | when 'y', 'yes'
43 | world.player.inventory.remove_item('sand_jewel')
44 | world.shifty_to_jewel = true
45 | speak('Yes...this will do nicely.')
46 | STDIN.getc
47 | speak('Forgive me, but I must take my leave for now. When the time is right, I will return!')
48 | puts 'And with that, she disappears. No puff of smoke or magical to-do...she is just no more.'
49 | else
50 | speak('Bah! Begone, fool!')
51 |
52 | Animation.run(phrase: SHOO_TEXT)
53 | puts
54 |
55 | puts "An aura of electric light surrounds her as you are physically pushed back a foot or so. You feel instantly, uh, #{WordList.new('adjective').get_random_value}."
56 | end
57 | else
58 | puts 'She grumbles to herself a little before giving you a little "shoo" and recommences looking shifty.'
59 | end
60 | else
61 | puts 'The woman averts her eyes from you as you commence with a greeting, giving a little scowl while she is at it.'
62 |
63 | self.used = true
64 | end
65 |
66 | { type: nil, data: nil }
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/thin_man.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/thin_man.rb
2 | # Entity::Creature::Person::ThinMan
3 |
4 | require_relative '../person'
5 |
6 | module Gemwarrior
7 | class ThinMan < Person
8 | def initialize
9 | super
10 |
11 | self.name = 'thin_man'
12 | self.name_display = 'Thin Man'
13 | self.description = 'An almost shockingly gaunt man is sitting on the ground, resting against a wall. He wears a patchwork quilt of a hat, and his slender frame is covered by a simple brown tunic. His feet point comically toward the sky in brown boots while his head dips down slightly, eyes watching something in the distance you can\'t see.'
14 | end
15 |
16 | def use(world)
17 | if self.used
18 | puts 'The thin man barely moves his head as he puts up a single grim hand, motioning you to back off.'
19 | else
20 | puts 'The thin man lifts his head up slightly, meets your gaze, and responds to your greeting:'
21 | speak('I may be incredibly spare right now, but I was once a strapping young person, such as yourself. Just in case you ever fall during your journey, be sure to approach unlikely sources, as you may find those who will help you.')
22 | speak('Now, please, allow me my peace.')
23 |
24 | self.used = true
25 | end
26 |
27 | { type: nil, data: nil }
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/people/ware_hawker.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/people/ware_hawker.rb
2 | # Entity::Creature::Person::WareHawker
3 |
4 | require_relative '../person'
5 | require_relative '../weapons/mace'
6 | require_relative '../weapons/spear'
7 | require_relative '../armor/iron_helmet'
8 |
9 | module Gemwarrior
10 | class WareHawker < Person
11 | # CONSTANTS
12 | PRICE_IRON_HELMET = 10
13 | PRICE_MACE = 30
14 | PRICE_SPEAR = 40
15 | PLAYER_ROX_INSUFFICIENT = 'You have insufficient rox to purchase that. Quit testing me, human.'
16 | PLAYER_ITEMS_ADDITIONAL = 'Will there be something else?'
17 | PLAYER_COMMAND_INVALID = 'That means nothing to me.'
18 |
19 | def initialize
20 | super
21 |
22 | self.name = 'ware_hawker'
23 | self.name_display = 'Ware Hawker'
24 | self.description = 'A literal anthropomorphic hawk has set up shop behind a crudely-made table. Some wares are scattered atop its surface, seemingly within anyone\'s grasp, but the hawk\'s piercing eyes seem to belie this observation.'
25 | end
26 |
27 | def use(world)
28 | if !self.used
29 | puts 'You greet the hawk, mentioning that you are interested in the objects presented.'
30 | STDIN.getc
31 | puts 'The hawk speaks in a beautiful, yet commanding, tone:'
32 | end
33 |
34 | hawk_shop(world)
35 | end
36 |
37 | private
38 |
39 | def hawk_shop(world)
40 | player_rox_remaining = world.player.rox
41 | amount_spent = 0
42 | items_purchased = []
43 |
44 | iron_helmet = IronHelmet.new
45 | mace = Mace.new
46 | spear = Spear.new
47 |
48 | speak('I hope you have rox, human. My time affords business transactions, not idle chit chat. What do you want?')
49 | STDIN.getc
50 |
51 | puts 'A feathered arm quickly moves across the table in an arc suggesting to you that a choice is to be made. Each object has a price tag underneath it, painstakingly written in ink.'
52 | puts
53 |
54 | puts 'Hawk Shop'.colorize(:cyan)
55 | puts '---------'
56 | puts "(1) #{'Iron Helmet'.colorize(:yellow)} - #{PRICE_IRON_HELMET} rox"
57 | puts " #{iron_helmet.description}"
58 | puts " Defense: +#{iron_helmet.defense} (current: #{world.player.defense})"
59 | puts "(2) #{'Mace'.colorize(:yellow)} - #{PRICE_MACE} rox"
60 | puts " #{mace.description}"
61 | puts " Attack: +#{mace.atk_lo}-#{mace.atk_hi} (current: #{world.player.atk_lo}-#{world.player.atk_hi})"
62 | puts "(3) #{'Spear'.colorize(:yellow)} - #{PRICE_SPEAR} rox"
63 | puts " #{spear.description}"
64 | puts " Attack: +#{spear.atk_lo}-#{spear.atk_hi} (current: #{world.player.atk_lo}-#{world.player.atk_hi})"
65 | puts
66 | speak('Choose. Now.')
67 |
68 | loop do
69 | puts " 1 - Iron Helmet (#{PRICE_IRON_HELMET})"
70 | puts " 2 - Mace (#{PRICE_MACE})"
71 | puts " 3 - Spear (#{PRICE_SPEAR})"
72 | print ' x - leave'
73 | if items_purchased.length > 0
74 | print ", and buy items\n"
75 | else
76 | print "\n"
77 | end
78 | puts
79 | print 'REMAINING ROX: '
80 | Animation.run(phrase: player_rox_remaining.to_s, oneline: true)
81 | print "\n"
82 | display_shopping_cart(items_purchased)
83 | print '[HAWK]> '
84 |
85 | choice = gets.chomp.downcase
86 |
87 | case choice
88 | when '1'
89 | if player_rox_remaining >= PRICE_IRON_HELMET
90 | player_rox_remaining -= PRICE_IRON_HELMET
91 | items_purchased.push(IronHelmet.new)
92 | amount_spent += PRICE_IRON_HELMET
93 |
94 | speak('The iron helmet? I see.')
95 | speak(PLAYER_ITEMS_ADDITIONAL)
96 | next
97 | else
98 | speak(PLAYER_ROX_INSUFFICIENT)
99 | next
100 | end
101 | when '2'
102 | if player_rox_remaining >= PRICE_MACE
103 | player_rox_remaining -= PRICE_MACE
104 | items_purchased.push(Mace.new)
105 | amount_spent += PRICE_MACE
106 |
107 | speak('Yes, fine. Buy a mace.')
108 | speak(PLAYER_ITEMS_ADDITIONAL)
109 | next
110 | else
111 | speak(PLAYER_ROX_INSUFFICIENT)
112 | next
113 | end
114 | when '3'
115 | if player_rox_remaining >= PRICE_SPEAR
116 | player_rox_remaining -= PRICE_SPEAR
117 | items_purchased.push(Spear.new)
118 | amount_spent += PRICE_SPEAR
119 |
120 | speak('Hmm. Very well, then. If the spear is what you wish.')
121 | speak(PLAYER_ITEMS_ADDITIONAL)
122 | next
123 | else
124 | speak(PLAYER_ROX_INSUFFICIENT)
125 | next
126 | end
127 | when 'x'
128 | return_type = { type: nil, data: nil }
129 | if items_purchased.length > 0
130 | display_shopping_cart(items_purchased)
131 | speak('Are you certain you wish to buy these things? (y/n)')
132 | print '[HAWK]> '
133 | answer = gets.chomp.downcase
134 |
135 | case answer
136 | when 'y', 'yes'
137 | world.player.rox -= amount_spent
138 | speak('Take them.')
139 | return_type = { type: 'purchase', data: items_purchased }
140 | end
141 | end
142 | speak('Our business is complete then.')
143 | return return_type
144 | else
145 | speak(PLAYER_COMMAND_INVALID)
146 | next
147 | end
148 | end
149 | end
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/person.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/person.rb
2 | # Entity::Creature::Person base class
3 |
4 | require_relative 'creature'
5 |
6 | module Gemwarrior
7 | class Person < Creature
8 | def initialize
9 | super
10 |
11 | self.name = 'person.'
12 | self.name_display = Formatting::upstyle(name)
13 | self.description = 'It appears to be a person of some kind.'
14 | self.takeable = false
15 | end
16 |
17 | def use(world)
18 | 'That person does not seem to want to talk to you right now.'
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapon.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapon.rb
2 | # Entity::Item::Weapon base class
3 |
4 | require_relative 'item'
5 |
6 | module Gemwarrior
7 | class Weapon < Item
8 | attr_accessor :atk_lo,
9 | :atk_hi,
10 | :dex_mod,
11 | :is_weapon
12 |
13 | def initialize
14 | super
15 |
16 | self.atk_lo = 0
17 | self.atk_hi = 0
18 | self.dex_mod = 0
19 | self.takeable = true
20 | self.equippable = true
21 | self.is_weapon = true
22 | end
23 |
24 | def use(world)
25 | 'Save the brandishing of your weapon for battle.'
26 | end
27 |
28 | def describe_detailed
29 | desc_text = "\"#{name_display}\"\n".colorize(:yellow)
30 | desc_text << "(#{name})\n".colorize(:green)
31 | desc_text << "#{description}\n".colorize(:white)
32 | desc_text << "WEAPON? #{is_weapon}\n".colorize(:white)
33 | desc_text << "ATTACK_RANGE : #{atk_lo}-#{atk_hi}\n".colorize(:white)
34 | desc_text << "TAKEABLE? #{takeable}\n".colorize(:white)
35 | desc_text << "USEABLE? #{useable}\n".colorize(:white)
36 | desc_text << "TALKABLE? #{talkable}\n".colorize(:white)
37 | desc_text << "CONSUMABLE? #{consumable}\n".colorize(:white)
38 | desc_text << "EQUIPPABLE? #{equippable}\n".colorize(:white)
39 | desc_text << "EQUIPPED? #{equipped}\n".colorize(:white)
40 | desc_text << "USED? #{used}\n".colorize(:white)
41 | desc_text << "USED AGAIN? #{used_again}\n".colorize(:white)
42 | desc_text << "USES LEFT? #{number_of_uses}\n".colorize(:white) unless number_of_uses.nil?
43 | desc_text
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/dagger.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/dagger.rb
2 | # Entity::Item::Weapon::Dagger
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Dagger < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'dagger'
12 | self.name_display = 'Dagger'
13 | self.description = 'Flint that has been sharpened to a point, attached to a block of smooth granite by thin rope. Truly a work of art.'
14 | self.atk_lo = 1
15 | self.atk_hi = 3
16 | self.dex_mod = 1
17 | end
18 |
19 | def use(world)
20 | puts 'You graze the blade of the dagger lightly and find it to be plenty sharp.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/gun.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/gun.rb
2 | # Entity::Item::Weapon::Gun
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Gun < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'gun'
12 | self.name_display = 'Gun'
13 | self.description = 'Pew pew goes this firearm, you suspect (if it has bullets).'
14 | self.atk_lo = 2
15 | self.atk_hi = 6
16 | self.dex_mod = 2
17 | end
18 |
19 | def use(world)
20 | puts 'You pull the trigger on the gun, but it does not fire. An inscription on the barrel reads: "Only shoots when pointed at a monster." How safe!'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/mace.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/mace.rb
2 | # Entity::Item::Weapon::Mace
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Mace < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'mace'
12 | self.name_display = 'Mace'
13 | self.description = 'Sharp spikes atop a steel ball, affixed to a sturdy wooden handle. You could do damage with this.'
14 | self.atk_lo = 4
15 | self.atk_hi = 6
16 | self.dex_mod = -2
17 | end
18 |
19 | def use(world)
20 | puts 'You swing the mace around a few times, really testing out its smashability.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/opalaser.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/opalaser.rb
2 | # Entity::Item::Weapon::Opalaser
3 |
4 | require_relative '../item'
5 |
6 | module Gemwarrior
7 | class Opalaser < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'opalaser'
12 | self.name_display = 'Opalaser'
13 | self.description = 'Gleaming with supernatural light, this object feels alien, yet familiar.'
14 | self.atk_lo = 9
15 | self.atk_hi = 11
16 | self.dex_mod = 2
17 | end
18 |
19 | def use(world)
20 | puts 'You pull the "trigger" on the opalaser, but nothing happens.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/spear.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/spear.rb
2 | # Entity::Item::Weapon::Spear
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Spear < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'spear'
12 | self.name_display = 'Spear'
13 | self.description = 'About six feet in length and razor-sharp at the point, this spear requires two hands, but only one good stab.'
14 | self.atk_lo = 3
15 | self.atk_hi = 7
16 | self.dex_mod = -1
17 | end
18 |
19 | def use(world)
20 | puts 'This spear does, indeed, appear to strike fear upon that which is near.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/stalactite.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/stalactite.rb
2 | # Entity::Item::Weapon::Stalactite
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Stalactite < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'stalactite'
12 | self.name_display = 'Stalactite'
13 | self.description = 'Long protrusion of cave adornment, broken off and fallen to the ground, where the stalagmites sneer at it from.'
14 | self.atk_lo = 2
15 | self.atk_hi = 3
16 | self.dex_mod = -1
17 | end
18 |
19 | def use(world)
20 | puts 'You wave the stalactite around in the air a bit, testing its weight and precision. It is a thin, long piece of rock taken from a cave wall, for sure, though.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/entities/weapons/stone.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/entities/weapons/stone.rb
2 | # Entity::Item::Weapon::Stone
3 |
4 | require_relative '../weapon'
5 |
6 | module Gemwarrior
7 | class Stone < Weapon
8 | def initialize
9 | super
10 |
11 | self.name = 'stone'
12 | self.name_display = 'Stone'
13 | self.description = 'A small, yet quite sharp, sedimentary pebble, suitable for tossing in amusement, and perhaps combat.'
14 | self.atk_lo = 1
15 | self.atk_hi = 2
16 | self.dex_mod = -1
17 | end
18 |
19 | def use(world)
20 | puts 'You toss the stone a few feet into the air, and then it falls back into your palm. The experience was truly thrilling.'
21 | { type: nil, data: nil }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/gemwarrior/game.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/game.rb
2 | # Main launching point for Gem Warrior
3 |
4 | require 'colorize'
5 | require 'matrext'
6 |
7 | require_relative 'entities/armor/iron_helmet'
8 | require_relative 'entities/items/herb'
9 | require_relative 'entities/weapons/dagger'
10 | require_relative 'entities/player'
11 | require_relative 'misc/animation'
12 | require_relative 'misc/audio'
13 | require_relative 'misc/formatting'
14 | require_relative 'misc/hr'
15 | require_relative 'evaluator'
16 | require_relative 'game_assets'
17 | require_relative 'game_options'
18 | require_relative 'inventory'
19 | require_relative 'repl'
20 | require_relative 'world'
21 |
22 | module Gemwarrior
23 | class Game
24 | # CONSTANTS
25 | INVENTORY_DEFAULT = Inventory.new
26 | INVENTORY_DEBUG = Inventory.new([Herb.new, Herb.new, Herb.new])
27 | ROX_DEFAULT = 0
28 | ROX_DEBUG = 300
29 |
30 | attr_accessor :world,
31 | :evaluator,
32 | :repl,
33 | :monsters,
34 | :weapons
35 |
36 | def initialize(options)
37 | # set game options
38 | self.init_game_options(options)
39 |
40 | # add classes for creatures, monsters, people, items, weapons, and armor to game
41 | # also add them to the global GameAssets
42 | self.init_creatures
43 | self.init_monsters
44 | self.init_people
45 | self.init_items
46 | self.init_weapons
47 | self.init_armor
48 |
49 | # create new world based on yaml/marshall data
50 | self.world = init_world
51 |
52 | # spawn bosses inside world
53 | self.init_bosses
54 |
55 | # update some aspects of world's player to make more dynamic
56 | self.world.player.name = world.player.generate_name
57 | self.world.player.face = world.player.generate_face
58 | self.world.player.hands = world.player.generate_hands
59 | self.world.player.mood = world.player.generate_mood
60 | self.world.player.inventory = GameOptions.data['debug_mode'] ? INVENTORY_DEBUG : INVENTORY_DEFAULT
61 | self.world.player.rox = GameOptions.data['debug_mode'] ? ROX_DEBUG : ROX_DEFAULT
62 |
63 | # set some global variables
64 | self.world.duration = { mins: 0, secs: 0, ms: 0 }
65 | self.world.emerald_beaten = false
66 | self.world.shifty_to_jewel = false
67 | self.world.shifty_has_jeweled = false
68 |
69 | # mark home as visited
70 | self.world.location_by_name('home').visited = true
71 |
72 | # create options file if not existing
73 | self.update_options_file
74 |
75 | # create the console
76 | self.evaluator = Evaluator.new(world)
77 | self.repl = Repl.new(self, world, evaluator)
78 |
79 | # enter Jool!
80 | self.repl.start('look', options.fetch(:extra_command), options.fetch(:new_skip), options.fetch(:resume_skip))
81 | end
82 |
83 | def update_options_file
84 | File.open(GameOptions.data['options_file_path'], 'w') do |f|
85 | f.puts "fight_completion:#{GameOptions.data['fight_completion']}"
86 | f.puts "sound_enabled:#{GameOptions.data['sound_enabled']}"
87 | f.puts "sound_system:#{GameOptions.data['sound_system']}"
88 | f.puts "sound_volume:#{GameOptions.data['sound_volume']}"
89 | f.puts "use_wordnik:#{GameOptions.data['use_wordnik']}"
90 | end
91 | end
92 |
93 | private
94 |
95 | # convert an entity filename to a class so it can be added to game asset singleton registry
96 | def file_to_class(filename)
97 | filename_to_string = Formatting.upstyle(filename.split('/').last.split('.')[0], no_space: true)
98 | Gemwarrior.const_get(filename_to_string).new
99 | end
100 |
101 | def init_game_options(options)
102 | GameOptions.add 'beast_mode', options.fetch(:beast_mode)
103 | GameOptions.add 'debug_mode', options.fetch(:debug_mode)
104 | GameOptions.add 'fight_completion', options.fetch(:fight_completion)
105 | GameOptions.add 'god_mode', options.fetch(:god_mode)
106 | GameOptions.add 'sound_enabled', options.fetch(:sound_enabled)
107 | GameOptions.add 'sound_system', options.fetch(:sound_system)
108 | GameOptions.add 'sound_volume', options.fetch(:sound_volume)
109 | GameOptions.add 'use_wordnik', options.fetch(:use_wordnik)
110 |
111 | # require needed files for selected sound_system if sound_enabled
112 | if GameOptions.data['sound_enabled']
113 | Audio.init
114 | end
115 | end
116 |
117 | def init_bosses
118 | ## Pain Quarry
119 | world.location_by_name('pain_quarry-southeast').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
120 | world.location_by_name('pain_quarry-east').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
121 | world.location_by_name('pain_quarry-central').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
122 | world.location_by_name('pain_quarry-south').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
123 | world.location_by_name('pain_quarry-west').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
124 | world.location_by_name('pain_quarry-northwest').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
125 | world.location_by_name('pain_quarry-north').bosses_abounding.push(Gemwarrior.const_get('Garynetty').new)
126 | ## River Bridge
127 | world.location_by_name('river_bridge').bosses_abounding.push(Gemwarrior.const_get('Jaspern').new)
128 | ## Throne Room
129 | world.location_by_name('sky_tower-throne_room').bosses_abounding.push(Gemwarrior.const_get('Emerald').new)
130 | end
131 |
132 | def init_creatures
133 | Dir.glob(File.expand_path('../entities/creatures/*.rb', __FILE__)).each do |creature|
134 | require_relative creature
135 | GameCreatures.add(file_to_class(creature))
136 | end
137 | end
138 |
139 | def init_monsters
140 | Dir.glob(File.expand_path('../entities/monsters/*.rb', __FILE__)).each do |monster|
141 | require_relative monster
142 | GameMonsters.add(file_to_class(monster))
143 | end
144 | Dir.glob(File.expand_path('../entities/monsters/bosses/*.rb', __FILE__)).each do |boss|
145 | require_relative boss
146 | GameMonsters.add(file_to_class(boss))
147 | end
148 | end
149 |
150 | def init_people
151 | Dir.glob(File.expand_path('../entities/people/*.rb', __FILE__)).each do |person|
152 | require_relative person
153 | GamePeople.add(file_to_class(person))
154 | end
155 | end
156 |
157 | def init_items
158 | Dir.glob(File.expand_path('../entities/items/*.rb', __FILE__)).each do |item|
159 | require_relative item
160 | GameItems.add(file_to_class(item))
161 | end
162 | end
163 |
164 | def init_weapons
165 | Dir.glob(File.expand_path('../entities/weapons/*.rb', __FILE__)).each do |weapon|
166 | require_relative weapon
167 | GameWeapons.add(file_to_class(weapon))
168 | end
169 | end
170 |
171 | def init_armor
172 | Dir.glob(File.expand_path('../entities/armor/*.rb', __FILE__)).each do |armor|
173 | require_relative armor
174 | GameArmor.add(file_to_class(armor))
175 | end
176 | end
177 |
178 | def init_world
179 | mode = GameOptions.data['save_file_mode']
180 |
181 | if mode.eql?('Y')
182 | if File.exist?(GameOptions.data['world_yaml_path'])
183 | File.open(GameOptions.data['world_yaml_path'], 'r') do |f|
184 | return YAML.unsafe_load(f)
185 | end
186 | else
187 | puts "Error: cannot load #{GameOptions.data['world_yaml_path']}."
188 | end
189 | else
190 | if File.exist?(GameOptions.data['world_bin_path'])
191 | File.open(GameOptions.data['world_bin_path'], 'r') do |f|
192 | return Marshal.load(f)
193 | end
194 | else
195 | puts "Error: cannot load #{GameOptions.data['world_bin_path']}."
196 | end
197 | end
198 | end
199 | end
200 | end
201 |
--------------------------------------------------------------------------------
/lib/gemwarrior/game_assets.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/game_assets.rb
2 | # Gem Warrior Global Assets
3 | ## Game Armor
4 | ## Game Creatures
5 | ## Game Items
6 | ## Game Monsters
7 | ## Game People
8 | ## Game Weapons
9 |
10 | module Gemwarrior
11 | module GameArmor
12 | def self.add obj
13 | @@data ||= []
14 | @@data.push(obj)
15 | end
16 |
17 | def self.data
18 | @@data ||= []
19 | end
20 |
21 | def self.get(name)
22 | self.data.find { |i| i.name.downcase == name.downcase }
23 | end
24 | end
25 |
26 | module GameCreatures
27 | def self.add obj
28 | @@data ||= []
29 | @@data.push(obj)
30 | end
31 |
32 | def self.data
33 | @@data ||= []
34 | end
35 |
36 | def self.get(name)
37 | self.data.find { |i| i.name.downcase == name.downcase }
38 | end
39 | end
40 |
41 | module GameItems
42 | def self.add obj
43 | @@data ||= []
44 | @@data.push(obj)
45 | end
46 |
47 | def self.data
48 | @@data ||= []
49 | end
50 |
51 | def self.get(name)
52 | self.data.find { |i| i.name.downcase == name.downcase }
53 | end
54 | end
55 |
56 | module GameMonsters
57 | def self.add obj
58 | @@data ||= []
59 | @@data.push(obj)
60 | end
61 |
62 | def self.data
63 | @@data ||= []
64 | end
65 |
66 | def self.get(name)
67 | self.data.find { |i| i.name.downcase == name.downcase }
68 | end
69 | end
70 |
71 | module GamePeople
72 | def self.add obj
73 | @@data ||= []
74 | @@data.push(obj)
75 | end
76 |
77 | def self.data
78 | @@data ||= []
79 | end
80 |
81 | def self.get(name)
82 | self.data.find { |i| i.name.downcase == name.downcase }
83 | end
84 | end
85 |
86 | module GameWeapons
87 | def self.add obj
88 | @@data ||= []
89 | @@data.push(obj)
90 | end
91 |
92 | def self.data
93 | @@data ||= []
94 | end
95 |
96 | def self.get(name)
97 | self.data.find { |i| i.name.downcase == name.downcase }
98 | end
99 | end
100 | end
101 |
--------------------------------------------------------------------------------
/lib/gemwarrior/game_options.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/game_options.rb
2 | # Gem Warrior Global Game Options
3 |
4 | module Gemwarrior
5 | module GameOptions
6 | def self.add key, value
7 | @@data ||= {}
8 | @@data[key] = value
9 | end
10 |
11 | def self.data
12 | @@data ||= {}
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/lib/gemwarrior/inventory.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/inventory.rb
2 | # Collection of items a creature possesses
3 |
4 | require_relative 'game_options'
5 |
6 | module Gemwarrior
7 | class Inventory
8 | # CONSTANTS
9 | ERROR_ITEM_REMOVE_INVALID = 'Your inventory does not contain that item, so you cannot drop it.'
10 | ERROR_ITEM_ADD_UNTAKEABLE = 'That would be great if you could take that, wouldn\'t it? Huh!'
11 | ERROR_ITEM_ADD_INVALID = 'That item cannot be taken or does not exist.'
12 | ERROR_ITEM_DESCRIBE_INVALID = 'That does not seem to be in the inventory.'
13 | ERROR_ITEM_EQUIP_INVALID = 'You do not possess anything called that to equip.'
14 | ERROR_ITEM_EQUIP_NONARMAMENT = 'That item cannot be equipped.'
15 | ERROR_ITEM_UNEQUIP_INVALID = 'You do not possess anything called that to unequip.'
16 | ERROR_ITEM_UNEQUIP_NONARMAMENT = 'That item cannot be unequipped.'
17 | VOWELS = 'aeiou'
18 |
19 | attr_accessor :items,
20 | :weapon,
21 | :armor
22 |
23 | def initialize(items = [], weapon = nil, armor = nil)
24 | self.items = items
25 | self.weapon = weapon
26 | self.armor = armor
27 | end
28 |
29 | def an_words
30 | ['herb']
31 | end
32 |
33 | def article_chooser(word)
34 | (VOWELS.include?(word.to_s[0]) or an_words.include?(word.to_s)) ? 'an' : 'a'
35 | end
36 |
37 | def is_empty?
38 | self.items.nil? || self.items.empty?
39 | end
40 |
41 | # non-English-like contents of inventory for simple lists
42 | def contents
43 | if is_empty?
44 | nil
45 | else
46 | item_hash = {}
47 | self.items.map(&:name).each do |i|
48 | i_sym = i.to_sym
49 | if item_hash.keys.include? i_sym
50 | item_hash[i_sym] += 1
51 | else
52 | item_hash[i_sym] = 1
53 | end
54 | end
55 |
56 | # one item? return string
57 | if item_hash.length == 1
58 | i = item_hash.keys.join
59 | q = item_hash.values.join.to_i
60 | return q > 1 ? "#{i}s x#{q}" : i
61 | # multiple items? return array of strings to mush together
62 | else
63 | item_arr = []
64 | item_hash.each do |i, q|
65 | if q > 1
66 | item_arr.push("#{i}s x#{q}")
67 | else
68 | item_arr.push(i)
69 | end
70 | end
71 |
72 | return item_arr.join(', ')
73 | end
74 | end
75 | end
76 |
77 | # English-like sentence summary of inventory
78 | def list_contents
79 | if is_empty?
80 | 'You possess nothing.'
81 | else
82 | # build hash of inventory's items
83 | item_hash = {}
84 | self.items.map(&:name).each do |i|
85 | i_sym = i.to_sym
86 | if item_hash.keys.include? i_sym
87 | item_hash[i_sym] += 1
88 | else
89 | item_hash[i_sym] = 1
90 | end
91 | end
92 |
93 | # one item? return string
94 | if item_hash.length == 1
95 | i = item_hash.keys.join
96 | q = item_hash.values.join.to_i
97 | if q > 1
98 | return "You have #{q} #{i.to_s.colorize(:yellow)}#{'s'.colorize(:yellow)}."
99 | else
100 | return "You have #{self.article_chooser(i)} #{i.to_s.colorize(:yellow)}."
101 | end
102 | # multiple items? return array of strings to mush together
103 | else
104 | item_list_text = 'You have '
105 | item_arr = []
106 | item_hash.each do |i, q|
107 | if q > 1
108 | item_arr.push("#{q} #{i.to_s.colorize(:yellow)}#{'s'.colorize(:yellow)}")
109 | else
110 | item_arr.push("#{self.article_chooser(i)} #{i.to_s.colorize(:yellow)}")
111 | end
112 | end
113 |
114 | item_arr[-1].replace("and #{item_arr[-1]}.")
115 |
116 | return item_list_text << item_arr.join(', ')
117 | end
118 | end
119 | end
120 |
121 | def contains_item?(item_name)
122 | self.items.map{ |i| i.name.downcase }.include?(item_name.downcase)
123 | end
124 |
125 | def contains_battle_item?
126 | battle_item_found = false
127 | self.items.each do |i|
128 | battle_item_found = true if i.useable_battle
129 | end
130 | battle_item_found
131 | end
132 |
133 | def list_battle_items
134 | battle_items = []
135 | self.items.each do |i|
136 | battle_items.push(i) if i.useable_battle
137 | end
138 | battle_items
139 | end
140 |
141 | def describe_item(item_name, world)
142 | if contains_item?(item_name)
143 | self.items.each do |i|
144 | if i.name.eql?(item_name)
145 | if GameOptions.data['debug_mode']
146 | return i.describe_detailed(world)
147 | else
148 | return i.describe(world)
149 | end
150 | end
151 | end
152 | else
153 | ERROR_ITEM_DESCRIBE_INVALID
154 | end
155 | end
156 |
157 | def equip_item(item_name)
158 | if contains_item?(item_name)
159 | self.items.each do |i|
160 | if i.name.eql?(item_name)
161 | if i.equippable
162 | i.equipped = true
163 | if i.is_weapon
164 | self.weapon = i
165 | return "The #{i.name.colorize(:yellow)} has taken charge, and been equipped."
166 | elsif i.is_armor
167 | self.armor = i
168 | return "The #{i.name.colorize(:yellow)} has fortified you, and been equipped."
169 | end
170 | else
171 | return ERROR_ITEM_EQUIP_NONARMAMENT
172 | end
173 | end
174 | end
175 | else
176 | ERROR_ITEM_EQUIP_INVALID
177 | end
178 | end
179 |
180 | def unequip_item(item_name)
181 | if contains_item?(item_name)
182 | self.items.each do |i|
183 | if i.name.eql?(item_name)
184 | if i.equippable
185 | i.equipped = false
186 | if i.is_weapon
187 | self.weapon = nil
188 | return "The #{i.name.colorize(:yellow)} has been demoted to unequipped."
189 | elsif i.is_armor
190 | self.armor = nil
191 | return "The #{i.name.colorize(:yellow)} has been demoted to unequipped."
192 | end
193 | else
194 | return ERROR_ITEM_UNEQUIP_NONARMAMENT
195 | end
196 | end
197 | end
198 | else
199 | ERROR_ITEM_UNEQUIP_INVALID
200 | end
201 | end
202 |
203 | def add_item(item_name, cur_loc = nil, player = nil)
204 | if cur_loc.nil?
205 | self.items.push(item_name)
206 | else
207 | cur_loc.items.each do |i|
208 | if i.name.eql?(item_name)
209 | if i.takeable
210 | self.items.push(i)
211 | cur_loc.remove_item(item_name)
212 |
213 | # stats
214 | player.items_taken += 1
215 |
216 | return "#{"Added".colorize(:green)} #{item_name.colorize(:yellow)} #{"to your increasing collection of bits of tid".colorize(:green)}."
217 | else
218 | return ERROR_ITEM_ADD_UNTAKEABLE.colorize(:red)
219 | end
220 | end
221 | end
222 | end
223 | ERROR_ITEM_ADD_INVALID.colorize(:red)
224 | end
225 |
226 | def drop_item(item_name, cur_loc)
227 | if contains_item?(item_name)
228 | remove_item(item_name)
229 | cur_loc.add_item(item_name)
230 | "You dropped #{item_name.colorize(:yellow)}."
231 | else
232 | ERROR_ITEM_REMOVE_INVALID
233 | end
234 | end
235 |
236 | def remove_item(item_name)
237 | self.items.delete_at(self.items.map(&:name).index(item_name) || self.items.length)
238 | unless self.weapon.nil?
239 | self.weapon = nil if self.weapon.name.eql?(item_name)
240 | end
241 | end
242 | end
243 | end
244 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/animation.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/animation.rb
2 | # Animation routine using matrext
3 |
4 | module Gemwarrior
5 | module Animation
6 | def self.run(opts)
7 | options = {
8 | oneline: false,
9 | speed: nil,
10 | alpha: true,
11 | numeric: true,
12 | random: true,
13 | color: nil,
14 | background: nil
15 | }.merge(opts)
16 |
17 | th = Thread.new do
18 | print Matrext.process({
19 | phrase: options.fetch(:phrase),
20 | oneline: options.fetch(:oneline),
21 | speed: options.fetch(:speed),
22 | alpha: options.fetch(:alpha),
23 | numeric: options.fetch(:numeric),
24 | random: options.fetch(:random),
25 | color: options.fetch(:color),
26 | background: options.fetch(:background)
27 | })
28 | end
29 |
30 | return th.join
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/audio.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/audio.rb
2 | # Audio cues using either synth or samples
3 | # Synth: win32-sound, feep, or bloopsaphone depending on platform/choice
4 | # Samples: small wav files
5 |
6 | require_relative '../game_options'
7 |
8 | module Gemwarrior
9 | module Audio
10 | # CONSTANTS
11 | ERROR_SOUND_NOT_ENABLED = 'Sound is disabled! Enable in main options to hear sound.'
12 | ERROR_SOUND_SYSTEM_NOT_CHOSEN = 'Sound system not chosen! Choose one in main options to hear sound.'
13 | ERROR_BLOOPS_NOT_FOUND = 'bloopsaphone gem not found. Try \'gem install bloopsaphone\'.'
14 | ERROR_FEEP_NOT_FOUND = 'feep gem not found. Try \'gem install feep\'.'
15 | ERROR_WIN32_NOT_FOUND = 'win32-sound gem not found. Try \'gem install win32-sound\'.'
16 |
17 | def self.init
18 | if GameOptions.data['sound_system'].eql?('win32-sound')
19 | begin
20 | require 'win32/sound'
21 | rescue
22 | GameOptions.data['errors'] = "#{GameOptions.data['sound_system']} could not be loaded. You may need to run 'gem install #{GameOptions.data['sound_system']}'. Silence for now."
23 | end
24 | elsif GameOptions.data['sound_system'].eql?('feep')
25 | begin
26 | require 'feep'
27 | rescue
28 | GameOptions.data['errors'] = "#{GameOptions.data['sound_system']} could not be loaded. You may need to run 'gem install #{GameOptions.data['sound_system']}'. Silence for now."
29 | end
30 | elsif GameOptions.data['sound_system'].eql?('bloops')
31 | begin
32 | require 'bloops'
33 | rescue
34 | GameOptions.data['errors'] = "#{GameOptions.data['sound_system']} could not be loaded. You may need to run 'gem install #{GameOptions.data['sound_system']}aphone'. Silence for now."
35 | end
36 | else
37 | GameOptions.data['errors'] = "'#{GameOptions.data['sound_system']}' is not a valid sound system. Audio subsystem load failed."
38 | end
39 | end
40 |
41 | def self.get_cues
42 | if GameOptions.data['sound_enabled']
43 | case GameOptions.data['sound_system']
44 | when 'win32-sound', 'feep'
45 | require_relative 'audio_cues'
46 | AudioCues.cues
47 | when 'bloops'
48 | require_relative 'bloops_cues'
49 | BloopsCues.cues
50 | end
51 | end
52 | end
53 |
54 | def self.play_synth(audio_cue_symbol)
55 | if GameOptions.data['sound_enabled']
56 | if GameOptions.data['sound_system']
57 | case GameOptions.data['sound_system']
58 | when 'win32-sound'
59 | if system('gem list -ie win32-sound')
60 | require_relative 'audio_cues'
61 | require_relative 'musical_notes'
62 |
63 | if AudioCues.cues[audio_cue_symbol]
64 | Thread.start do
65 | AudioCues.cues[audio_cue_symbol][:synth].each do |seq|
66 | threads = []
67 | seq[:frequencies].split(',').each do |note|
68 | threads << Thread.new do
69 | Win32::Sound::play_freq(Notes::NOTE_FREQ[note], seq[:duration], GameOptions.data['sound_volume'])
70 | end
71 | end
72 | threads.each { |th| th.join }
73 | end
74 | end
75 | end
76 | else
77 | GameOptions.data['errors'] = ERROR_WIN32_NOT_FOUND
78 | end
79 | when 'feep'
80 | if system('gem list -ie feep')
81 | require_relative 'audio_cues'
82 |
83 | feep_defaults = {
84 | frequencies: '440',
85 | waveform: 'sine',
86 | volume: GameOptions.data['sound_volume'],
87 | duration: 500,
88 | notext: true
89 | }
90 |
91 | if AudioCues.cues[audio_cue_symbol]
92 | Thread.start do
93 | AudioCues.cues[audio_cue_symbol][:synth].each do |seq|
94 | seq = feep_defaults.merge(seq)
95 |
96 | Feep::Base.new({
97 | freq_or_note: seq[:frequencies],
98 | waveform: seq[:waveform],
99 | volume: seq[:volume],
100 | duration: seq[:duration],
101 | notext: seq[:notext]
102 | })
103 | end
104 | end
105 | end
106 | else
107 | GameOptions.data['errors'] = ERROR_FEEP_NOT_FOUND
108 | end
109 | when 'bloops'
110 | if system('gem list -ie bloops')
111 | require_relative 'bloops_cues'
112 |
113 | if BloopsCues.cues[audio_cue_symbol]
114 | Thread.start do
115 | BloopsCues.cues[audio_cue_symbol][:synth].each do |seq|
116 | threads = []
117 |
118 | seq.each do |note|
119 | threads << Thread.new do
120 | b = Bloops.new
121 | b.tempo = 240
122 | snd = b.sound Bloops::SQUARE
123 | snd.punch = GameOptions.data['sound_volume']/2
124 | snd.sustain = 0.7
125 | snd.decay = 0.2
126 | b.tune snd, note[1]
127 | b.play
128 | sleep 0.1 while !b.stopped?
129 | end
130 | end
131 |
132 | threads.each { |th| th.join }
133 | end
134 | end
135 | end
136 | else
137 | GameOptions.data['errors'] = ERROR_BLOOPS_NOT_FOUND
138 | end
139 | end
140 | else
141 | GameOptions.data['errors'] = ERROR_SOUND_SYSTEM_NOT_CHOSEN
142 | end
143 | else
144 | GameOptions.data['errors'] = ERROR_SOUND_NOT_ENABLED
145 | end
146 | end
147 |
148 | def self.play_sample(audio_cue_symbol)
149 | # future use
150 | end
151 | end
152 | end
153 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/audio_cues.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/audio_cues.rb
2 | # Audio cue symbol -> notes/wav_file
3 |
4 | module Gemwarrior
5 | module AudioCues
6 | def self.add key, val
7 | @@cues ||= {}
8 | @@cues[key] = val
9 | end
10 |
11 | def self.cues
12 | @@cues ||= {}
13 | end
14 |
15 | self.add :bg1, {
16 | synth: [
17 | { frequencies: 'C4', duration: 400 },
18 | { frequencies: 'C5', duration: 400 },
19 | { frequencies: 'C4', duration: 400 },
20 | { frequencies: 'C5', duration: 400 },
21 | { frequencies: 'C4', duration: 400 },
22 | { frequencies: 'C5', duration: 400 },
23 | { frequencies: 'G4', duration: 400 },
24 | { frequencies: 'A4', duration: 400 },
25 | { frequencies: 'C4', duration: 400 },
26 | { frequencies: 'C5', duration: 400 },
27 | { frequencies: 'C4', duration: 400 },
28 | { frequencies: 'C5', duration: 400 },
29 | { frequencies: 'C4', duration: 400 },
30 | { frequencies: 'C5', duration: 400 },
31 | { frequencies: 'B4', duration: 400 },
32 | { frequencies: 'A4', duration: 400 },
33 | ],
34 | sample: 'bg1.wav'
35 | }
36 |
37 | self.add :battle_start, {
38 | synth: [
39 | { frequencies: 'G4', duration: 50 },
40 | { frequencies: 'G#4', duration: 50 },
41 | { frequencies: 'G4', duration: 50 },
42 | { frequencies: 'G#4', duration: 50 },
43 | { frequencies: 'G4', duration: 50 },
44 | { frequencies: 'G#4', duration: 50 }
45 | ],
46 | sample: 'battle_start.wav'
47 | }
48 |
49 | self.add :battle_player_attack, {
50 | synth: [{ frequencies: 'A4,E4,B5', duration: 75 }],
51 | sample: 'battle_player_attack.wav'
52 | }
53 |
54 | self.add :battle_player_miss, {
55 | synth: [{ frequencies: 'A4', duration: 75 }],
56 | sample: 'battle_player_miss.wav'
57 | }
58 |
59 | self.add :battle_monster_attack, {
60 | synth: [{ frequencies: 'B4,E#5,A5', duration: 75 }],
61 | sample: 'battle_monster_attack.wav'
62 | }
63 |
64 | self.add :battle_monster_miss, {
65 | synth: [{ frequencies: 'B4', duration: 75 }],
66 | sample: 'battle_monster_miss.wav'
67 | }
68 |
69 | self.add :battle_win_boss, {
70 | synth: [
71 | { frequencies: 'E5', duration: 50 },
72 | { frequencies: 'F5', duration: 50 },
73 | { frequencies: 'E5', duration: 100 },
74 | { frequencies: 'E5', duration: 50 },
75 | { frequencies: 'F5', duration: 50 },
76 | { frequencies: 'E5', duration: 100 },
77 | { frequencies: 'E4,A4', duration: 50 },
78 | { frequencies: 'E4,A4', duration: 200 }
79 | ],
80 | sample: 'battle_win_boss.wav'
81 | }
82 |
83 | self.add :battle_win_monster, {
84 | synth: [
85 | { frequencies: 'D5', duration: 50 },
86 | { frequencies: 'E5', duration: 50 },
87 | { frequencies: 'D5', duration: 100 },
88 | { frequencies: 'D4', duration: 50 },
89 | { frequencies: 'D4', duration: 200 }
90 | ],
91 | sample: 'battle_win_monster.wav'
92 | }
93 |
94 | self.add :intro, {
95 | synth: [
96 | { frequencies: 'C4,G4', duration: 350 },
97 | { frequencies: 'D3,A4', duration: 85 },
98 | { frequencies: 'E3,B4', duration: 85 },
99 | { frequencies: 'F3,C5', duration: 170 },
100 | { frequencies: 'F3,C5', duration: 170 },
101 | { frequencies: 'F3,C5', duration: 170 },
102 | { frequencies: 'G3,B4,D5', duration: 350 }
103 | ],
104 | sample: 'intro.wav'
105 | }
106 |
107 | self.add :player_level_up, {
108 | synth: [
109 | { frequencies: 'D4,A4,D5,A5,D6', duration: 100 },
110 | { frequencies: 'D4,A4,D5,A5,D6', duration: 350 },
111 | { frequencies: 'E4,B4,E5,B5,E6', duration: 500 }
112 | ]
113 | }
114 |
115 | self.add :player_resurrection, {
116 | synth: [
117 | { frequencies: 'D#5', duration: 100 },
118 | { frequencies: 'A4', duration: 150 },
119 | { frequencies: 'F#4', duration: 200 },
120 | { frequencies: 'F4', duration: 1000 }
121 | ],
122 | sample: 'player_resurrection.wav'
123 | }
124 |
125 | self.add :player_travel, {
126 | synth: [
127 | { frequencies: 'C4', duration: 75 },
128 | { frequencies: 'D4', duration: 75 },
129 | { frequencies: 'E4', duration: 75 }
130 | ],
131 | sample: 'player_travel.wav'
132 | }
133 |
134 | self.add :player_travel_east, {
135 | synth: [
136 | { frequencies: 'E4', duration: 75 },
137 | { frequencies: 'G4', duration: 75 },
138 | { frequencies: 'E4', duration: 75 }
139 | ],
140 | sample: 'player_travel_east.wav'
141 | }
142 |
143 | self.add :player_travel_north, {
144 | synth: [
145 | { frequencies: 'C4', duration: 75 },
146 | { frequencies: 'D4', duration: 75 },
147 | { frequencies: 'E4', duration: 75 }
148 | ],
149 | sample: 'player_travel_north.wav'
150 | }
151 |
152 | self.add :player_travel_south, {
153 | synth: [
154 | { frequencies: 'E4', duration: 75 },
155 | { frequencies: 'D4', duration: 75 },
156 | { frequencies: 'C4', duration: 75 }
157 | ],
158 | sample: 'player_travel_south.wav'
159 | }
160 |
161 | self.add :player_travel_west, {
162 | synth: [
163 | { frequencies: 'C4', duration: 75 },
164 | { frequencies: 'A3', duration: 75 },
165 | { frequencies: 'C4', duration: 75 }
166 | ],
167 | sample: 'player_travel_west.wav'
168 | }
169 |
170 | self.add :resume_game, {
171 | synth: [
172 | { frequencies: 'C4', duration: 75 },
173 | { frequencies: 'D4', duration: 75 },
174 | { frequencies: 'E4', duration: 75 },
175 | { frequencies: 'F#4', duration: 75 },
176 | { frequencies: 'G#4', duration: 75 },
177 | { frequencies: 'A#4', duration: 75 },
178 | { frequencies: 'C5', duration: 75 },
179 | { frequencies: 'D5', duration: 75 },
180 | { frequencies: 'E5', duration: 75 },
181 | { frequencies: 'F#5', duration: 75 }
182 | ],
183 | sample: 'test.wav'
184 | }
185 |
186 | self.add :test, {
187 | synth: [
188 | { frequencies: 'F4', duration: 75 },
189 | { frequencies: 'E5', duration: 75 },
190 | { frequencies: 'C5', duration: 75 },
191 | { frequencies: 'E5', duration: 75 }
192 | ],
193 | sample: 'test.wav'
194 | }
195 |
196 | self.add :uncover_secret, {
197 | synth: [
198 | { frequencies: 'F5', duration: 150 },
199 | { frequencies: 'E5', duration: 150 },
200 | { frequencies: 'C#4', duration: 150 },
201 | { frequencies: 'C4', duration: 150 },
202 | { frequencies: 'D#5', duration: 150 },
203 | { frequencies: 'F#5', duration: 150 },
204 | { frequencies: 'A5', duration: 150 }
205 | ],
206 | sample: 'uncover_secret.wav'
207 | }
208 |
209 | self.add :win_game, {
210 | synth: [
211 | { frequencies: 'G3', duration: 250 },
212 | { frequencies: 'A3', duration: 50 },
213 | { frequencies: 'B3', duration: 50 },
214 | { frequencies: 'C4', duration: 50 },
215 | { frequencies: 'D4', duration: 250 },
216 | { frequencies: 'E4', duration: 50 },
217 | { frequencies: 'F#4', duration: 50 },
218 | { frequencies: 'G4', duration: 50 },
219 | { frequencies: 'A4', duration: 250 },
220 | { frequencies: 'B4', duration: 50 },
221 | { frequencies: 'C5', duration: 50 },
222 | { frequencies: 'D5', duration: 50 },
223 | { frequencies: 'E5', duration: 50 },
224 | { frequencies: 'F#5', duration: 50 },
225 | { frequencies: 'G5', duration: 1000 }
226 | ],
227 | sample: 'win_game.wav'
228 | }
229 | end
230 | end
231 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/bloops_cues.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/bloops_cues.rb
2 | # Bloops cue symbol -> notes/wav_file
3 |
4 | module Gemwarrior
5 | module BloopsCues
6 | def self.add key, val
7 | @@cues ||= {}
8 | @@cues[key] = val
9 | end
10 |
11 | def self.cues
12 | @@cues ||= {}
13 | end
14 |
15 | self.add :bg1, {
16 | synth: [
17 | { s1: '2:C4' },
18 | { s1: '2:C5' },
19 | { s1: '2:C4' },
20 | { s1: '2:C5' },
21 | { s1: '2:C4' },
22 | { s1: '2:C5' },
23 | { s1: '2:G4' },
24 | { s1: '2:A4' },
25 | { s1: '2:C4' },
26 | { s1: '2:C5' },
27 | { s1: '2:C4' },
28 | { s1: '2:C5' },
29 | { s1: '2:C4' },
30 | { s1: '2:C5' },
31 | { s1: '2:B4' },
32 | { s1: '2:A4' },
33 | ],
34 | sample: 'bg1.wav'
35 | }
36 |
37 | self.add :battle_start, {
38 | synth: [
39 | { s1: '16:G4' },
40 | { s1: '16:G#4' },
41 | { s1: '16:G4' },
42 | { s1: '16:G#4' },
43 | { s1: '16:G4' },
44 | { s1: '16:G#4' }
45 | ],
46 | sample: 'battle_start.wav'
47 | }
48 |
49 | self.add :battle_player_attack, {
50 | synth: [{ s1: '16:A4', s2: '16:E4', s3: '16:B5' }],
51 | sample: 'battle_player_attack.wav'
52 | }
53 |
54 | self.add :battle_player_miss, {
55 | synth: [{ s1: '8:A4' }],
56 | sample: 'battle_player_miss.wav'
57 | }
58 |
59 | self.add :battle_monster_attack, {
60 | synth: [{ s1: '16:B4', s2: '16:E#5', s3: '16:A5' }],
61 | sample: 'battle_monster_attack.wav'
62 | }
63 |
64 | self.add :battle_monster_miss, {
65 | synth: [{ s1: '8:B4' }],
66 | sample: 'battle_monster_miss.wav'
67 | }
68 |
69 | self.add :battle_win_boss, {
70 | synth: [
71 | { s1: '16:E5' },
72 | { s1: '16:F5' },
73 | { s1: '8:E5' },
74 | { s1: '16:E5' },
75 | { s1: '16:F5' },
76 | { s1: '8:E5' },
77 | { s1: '16:E4', s2: '16:A4' },
78 | { s1: '4:E4', s2: '4:A4' }
79 | ],
80 | sample: 'battle_win_boss.wav'
81 | }
82 |
83 | self.add :battle_win_monster, {
84 | synth: [
85 | { s1: '16:D5' },
86 | { s1: '16:E5' },
87 | { s1: '8:D5' },
88 | { s1: '16:D4' },
89 | { s1: '4:D4' }
90 | ],
91 | sample: 'battle_win_monster.wav'
92 | }
93 |
94 | self.add :intro, {
95 | synth: [
96 | { s1: '4:C4', s2: '4:G4' },
97 | { s1: '16:D3', s2: '16:A4' },
98 | { s1: '16:E3', s2: '16:B4' },
99 | { s1: '8:F3', s2: '8:C5' },
100 | { s1: '8:F3', s2: '8:C5' },
101 | { s1: '8:F3', s2: '8:C5' },
102 | { s1: '4:G3', s2: '4:B4', s3: '4:D5' }
103 | ],
104 | sample: 'intro.wav'
105 | }
106 |
107 | self.add :player_level_up, {
108 | synth: [
109 | { s1: '8:D4', s2: '8:A4', s3: '8:D5', s4: '8:A5', s5: '8:D6' },
110 | { s1: '4:D4', s2: '4:A4', s3: '4:D5', s4: '4:A5', s5: '4:D6' },
111 | { s1: '1:E4', s2: '1:B4', s3: '1:E5', s4: '1:B5', s5: '1:E6' }
112 | ]
113 | }
114 |
115 | self.add :player_resurrection, {
116 | synth: [
117 | { s1: '16:D#5' },
118 | { s1: '14:A4' },
119 | { s1: '12:F#4' },
120 | { s1: '2:F4' }
121 | ],
122 | sample: 'player_resurrection.wav'
123 | }
124 |
125 | self.add :player_travel, {
126 | synth: [
127 | { s1: '16:C4' },
128 | { s1: '16:D4' },
129 | { s1: '16:E4' }
130 | ],
131 | sample: 'player_travel.wav'
132 | }
133 |
134 | self.add :player_travel_east, {
135 | synth: [
136 | { s1: '16:E4' },
137 | { s1: '16:G4' },
138 | { s1: '16:E4' }
139 | ],
140 | sample: 'player_travel_east.wav'
141 | }
142 |
143 | self.add :player_travel_north, {
144 | synth: [
145 | { s1: '16:C4' },
146 | { s1: '16:D4' },
147 | { s1: '16:E4' }
148 | ],
149 | sample: 'player_travel_north.wav'
150 | }
151 |
152 | self.add :player_travel_south, {
153 | synth: [
154 | { s1: '16:E4' },
155 | { s1: '16:D4' },
156 | { s1: '16:C4' }
157 | ],
158 | sample: 'player_travel_south.wav'
159 | }
160 |
161 | self.add :player_travel_west, {
162 | synth: [
163 | { s1: '16:C4' },
164 | { s1: '16:A4' },
165 | { s1: '16:C4' }
166 | ],
167 | sample: 'player_travel_west.wav'
168 | }
169 |
170 | self.add :resume_game, {
171 | synth: [
172 | { s1: '16:C4' },
173 | { s1: '16:D4' },
174 | { s1: '16:E4' },
175 | { s1: '8:F#4' }
176 | ],
177 | sample: 'test.wav'
178 | }
179 |
180 | self.add :test, {
181 | synth: [
182 | { s1: '4:F4' },
183 | { s1: '4:E5' },
184 | { s1: '4:C5' },
185 | { s1: '4:E5' }
186 | ],
187 | sample: 'test.wav'
188 | }
189 |
190 | self.add :uncover_secret, {
191 | synth: [
192 | { s1: '8:F5' },
193 | { s1: '8:E5' },
194 | { s1: '8:C#4' },
195 | { s1: '8:C4' },
196 | { s1: '8:D#5' },
197 | { s1: '8:F#5' },
198 | { s1: '8:A5' }
199 | ],
200 | sample: 'uncover_secret.wav'
201 | }
202 |
203 | self.add :win_game, {
204 | synth: [
205 | { s1: '4:G3' },
206 | { s1: '16:A3' },
207 | { s1: '16:B3' },
208 | { s1: '16:C4' },
209 | { s1: '4:D4' },
210 | { s1: '16:E4' },
211 | { s1: '16:F#4' },
212 | { s1: '16:G4' },
213 | { s1: '4:A4' },
214 | { s1: '16:B4' },
215 | { s1: '16:C5' },
216 | { s1: '16:D5' },
217 | { s1: '16:E5' },
218 | { s1: '16:F#5' },
219 | { s1: '1:G5' }
220 | ],
221 | sample: 'win_game.wav'
222 | }
223 | end
224 | end
225 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/formatting.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/formatting.rb
2 | # Formatting methods for text
3 |
4 | module Gemwarrior
5 | module Formatting
6 | def self.upstyle(str_arr, no_space = false)
7 | if str_arr.is_a? Array
8 | str_arr_upstyled = []
9 |
10 | str_arr.each do |str_arr_item|
11 | str_arr_item_upstyled = []
12 |
13 | str_arr_item.split(' ').each do |s|
14 | str_arr_item_upstyled << upstyle_string(s, no_space)
15 | end
16 |
17 | str_arr_upstyled << str_arr_item_upstyled.join(' ')
18 | end
19 |
20 | str_arr_upstyled
21 | else
22 | upstyle_string(str_arr, no_space)
23 | end
24 | end
25 |
26 | def to_hooch(s)
27 | words = s.split(' ')
28 | words_hooched = []
29 |
30 | words.each do |w|
31 | if rand(0..100) > 60 and w.length > 1
32 | w = w.split('')
33 | w = w.insert(rand(0..w.length-1), '*HIC*')
34 | w = w.join('')
35 | end
36 | words_hooched << w
37 | end
38 |
39 | words_hooched.join(' ')
40 | end
41 |
42 | private
43 |
44 | def self.upstyle_string(s, no_space)
45 | s_upstyle = ''
46 | s_upstyle << s[0].upcase
47 | 1.upto(s.length-1) do |i|
48 | if s[i-1].eql?('_')
49 | s_upstyle[i-1] = no_space ? '' : ' '
50 | s_upstyle << s[i].upcase
51 | else
52 | s_upstyle << s[i].downcase
53 | end
54 | end
55 | s_upstyle
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/hr.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/hr.rb
2 | # Standardized, cross-platform horizontal rule
3 | # Cribbed extensively from https://github.com/ivantsepp/hr
4 |
5 | require_relative '../game_options'
6 |
7 | module Gemwarrior
8 | module Hr
9 | extend self
10 |
11 | def print(*patterns)
12 | Kernel.print string(*patterns)
13 | end
14 |
15 | def string(*patterns)
16 | options = patterns.last.is_a?(Hash) ? patterns.pop : {}
17 | screen_width = GameOptions.data['wrap_width']
18 | output = patterns.map do |pattern|
19 | pattern = pattern.to_s
20 | times = (screen_width / pattern.length) + 1
21 | (pattern * times)[0..screen_width - 1]
22 | end.join
23 | output << "\n"
24 | options = options.inject({}){|tmp,(k,v)| tmp[k.to_sym] = v.to_sym; tmp}
25 | options.any? ? output.colorize(options) : output
26 | end
27 |
28 | private
29 |
30 | def command_exists?(command)
31 | ENV['PATH'].split(File::PATH_SEPARATOR).any? { |path|
32 | (File.exist? File.join(path, "#{command}")) || (File.exist? File.join(path, "#{command}.com")) || (File.exist? File.join(path, "#{command}.exe"))
33 | }
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/musical_notes.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/musical_notes.rb
2 | # Musical note->freq hash
3 |
4 | module Gemwarrior
5 | module Notes
6 | NOTE_FREQ = Hash[
7 | 'C0' => 16.351,
8 | 'C#0' => 17.324,
9 | 'Db0' => 17.324,
10 | 'D0' => 18.354,
11 | 'D#0' => 19.445,
12 | 'Eb0' => 19.445,
13 | 'E0' => 20.601,
14 | 'F0' => 21.827,
15 | 'F#0' => 23.124,
16 | 'Gb0' => 23.124,
17 | 'G0' => 24.499,
18 | 'G#0' => 25.956,
19 | 'Ab0' => 25.956,
20 | 'A0' => 27.500,
21 | 'A#0' => 29.135,
22 | 'Bb0' => 29.135,
23 | 'B0' => 30.868,
24 | 'C1' => 32.703,
25 | 'C#1' => 34.648,
26 | 'Db1' => 34.648,
27 | 'D1' => 36.708,
28 | 'D#1' => 38.891,
29 | 'Eb1' => 38.891,
30 | 'E1' => 41.203,
31 | 'F1' => 43.654,
32 | 'F#1' => 46.249,
33 | 'Gb1' => 46.249,
34 | 'G1' => 48.999,
35 | 'G#1' => 51.913,
36 | 'Ab1' => 51.913,
37 | 'A1' => 55.000,
38 | 'A#1' => 58.270,
39 | 'Bb1' => 58.270,
40 | 'B1' => 61.375,
41 | 'C2' => 65.406,
42 | 'C#2' => 69.296,
43 | 'Db2' => 69.296,
44 | 'D2' => 73.416,
45 | 'D#2' => 77.782,
46 | 'Eb2' => 77.782,
47 | 'E2' => 82.407,
48 | 'F2' => 87.307,
49 | 'F#2' => 92.499,
50 | 'Gb2' => 92.499,
51 | 'G2' => 97.999,
52 | 'G#2' => 97.999,
53 | 'Ab2' => 103.826,
54 | 'A2' => 110.000,
55 | 'A#2' => 116.541,
56 | 'Bb2' => 116.541,
57 | 'B2' => 123.471,
58 | 'C3' => 130.813,
59 | 'C#3' => 138.591,
60 | 'Db3' => 138.591,
61 | 'D3' => 146.832,
62 | 'D#3' => 155.564,
63 | 'Eb3' => 155.564,
64 | 'E3' => 164.814,
65 | 'F3' => 174.614,
66 | 'F#3' => 184.997,
67 | 'Gb3' => 184.997,
68 | 'G3' => 195.998,
69 | 'G#3' => 207.652,
70 | 'Ab3' => 207.652,
71 | 'A3' => 220.000,
72 | 'A#3' => 233.082,
73 | 'Bb3' => 233.082,
74 | 'B3' => 246.942,
75 | 'C4' => 261.626,
76 | 'C#4' => 277.183,
77 | 'Db4' => 277.183,
78 | 'D4' => 293.665,
79 | 'D#4' => 311.127,
80 | 'Eb4' => 311.127,
81 | 'E4' => 329.628,
82 | 'F4' => 349.228,
83 | 'F#4' => 369.994,
84 | 'Gb4' => 369.994,
85 | 'G4' => 391.995,
86 | 'G#4' => 415.305,
87 | 'Ab4' => 415.305,
88 | 'A4' => 440.000,
89 | 'A#4' => 466.164,
90 | 'Bb4' => 466.164,
91 | 'B4' => 493.883,
92 | 'C5' => 523.251,
93 | 'C#5' => 554.365,
94 | 'Db5' => 554.365,
95 | 'D5' => 587.330,
96 | 'D#5' => 622.254,
97 | 'Eb5' => 622.254,
98 | 'E5' => 659.255,
99 | 'F5' => 698.457,
100 | 'F#5' => 739.989,
101 | 'Gb5' => 739.989,
102 | 'G5' => 783.991,
103 | 'G#5' => 830.609,
104 | 'Ab5' => 830.609,
105 | 'A5' => 880.000,
106 | 'A#5' => 932.328,
107 | 'Bb5' => 932.328,
108 | 'B5' => 987.767,
109 | 'C6' => 1046.502,
110 | 'C#6' => 1108.731,
111 | 'Db6' => 1108.731,
112 | 'D6' => 1174.659,
113 | 'D#6' => 1244.508,
114 | 'Eb6' => 1244.508,
115 | 'E6' => 1318.510,
116 | 'F6' => 1396.913,
117 | 'F#6' => 1479.978,
118 | 'Gb6' => 1479.978,
119 | 'G6' => 1567.982,
120 | 'G#6' => 1661.219,
121 | 'Ab6' => 1661.219,
122 | 'A6' => 1760.000,
123 | 'A#6' => 1864.655,
124 | 'Bb6' => 1864.655,
125 | 'B6' => 1975.533,
126 | 'C7' => 2093.005,
127 | 'C#7' => 2217.461,
128 | 'Db7' => 2217.461,
129 | 'D7' => 2349.318,
130 | 'D#7' => 2489.016,
131 | 'Eb7' => 2489.016,
132 | 'E7' => 2637.021,
133 | 'F7' => 2793.826,
134 | 'F#7' => 2959.956,
135 | 'Gb7' => 2959.956,
136 | 'G7' => 3135.964,
137 | 'G#7' => 3322.438,
138 | 'Ab7' => 3322.438,
139 | 'A7' => 3520.000,
140 | 'A#7' => 3729.310,
141 | 'Bb7' => 3729.310,
142 | 'B7' => 3951.066,
143 | 'C8' => 4186.009,
144 | 'C#8' => 4434.922,
145 | 'Db8' => 4434.922,
146 | 'D8' => 4698.636,
147 | 'D#8' => 4978.032,
148 | 'Eb8' => 4978.032,
149 | 'E8' => 5274.042,
150 | 'F8' => 5587.652,
151 | 'F#8' => 5919.910,
152 | 'Gb8' => 5919.910,
153 | 'G8' => 6271.928,
154 | 'G#8' => 6644.876,
155 | 'Ab8' => 6644.876,
156 | 'A8' => 7040.000,
157 | 'A#8' => 7458.620,
158 | 'Bb8' => 7458.620,
159 | 'B8' => 7902.132,
160 | 'C9' => 8372.018,
161 | 'C#9' => 8869.844,
162 | 'Db9' => 8869.844,
163 | 'D9' => 9397.272,
164 | 'D#9' => 9956.064,
165 | 'Eb9' => 9956.064,
166 | 'E9' => 10548.084,
167 | 'F9' => 11175.304,
168 | 'F#9' => 11839.820,
169 | 'Gb9' => 11839.820,
170 | 'G9' => 12543.856,
171 | 'G#9' => 13289.752,
172 | 'Ab9' => 13289.752,
173 | 'A9' => 14080.000,
174 | 'A#9' => 14917.240,
175 | 'Bb9' => 14917.240,
176 | 'B9' => 15804.264
177 | ]
178 | end
179 | end
180 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/name_generator.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/name_generator.rb
2 | # NameGenerator Ruby class (translated from name_generator.js)
3 | # written and released to the public domain by drow
4 | # http://creativecommons.org/publicdomain/zero/1.0/
5 |
6 | require 'yaml'
7 |
8 | class NameGenerator
9 | attr_accessor :type, :name_set, :chain_cache
10 |
11 | def initialize(type)
12 | self.type = type
13 | self.name_set = get_name_set(self.type)
14 | self.chain_cache = {}
15 | end
16 |
17 | # load sample names
18 | def get_name_set(type)
19 | names = []
20 | names_data = YAML.load_file(File.expand_path("../../../../data/#{type}_names.yaml", __FILE__))
21 | names_data.each do |n|
22 | names.push(n)
23 | end
24 | return names
25 | end
26 |
27 | # generator function
28 | def generate_name
29 | chain = nil
30 |
31 | if (chain = markov_chain(self.type))
32 | return markov_name(chain)
33 | end
34 |
35 | return ''
36 | end
37 |
38 | # generate multiple
39 | def generate_names(count = 1)
40 | list = []
41 |
42 | (1..count).each {
43 | list.push(generate_name)
44 | }
45 |
46 | return list
47 | end
48 |
49 | # get markov chain by type
50 | def markov_chain(type)
51 | chain = nil
52 |
53 | if (chain = chain_cache[type])
54 | return chain
55 | else
56 | if (list = name_set)
57 | chain = nil
58 | if (chain = construct_chain(list))
59 | chain_cache[type] = chain
60 | return chain
61 | end
62 | end
63 | end
64 |
65 | return false
66 | end
67 |
68 | # construct markov chain from list of names
69 | def construct_chain(list)
70 | chain = {}
71 |
72 | for i in 0..list.length-1
73 | names = list[i].split(/\s+/)
74 | chain = incr_chain(chain, 'parts', names.length)
75 |
76 | for j in 0..names.length-1
77 | name = names[j].nil? ? [] : names[j]
78 | chain = incr_chain(chain, 'name_len', name.length)
79 |
80 | c = name[0, 1]
81 | chain = incr_chain(chain, 'initial', c)
82 |
83 | string = name[1..name.length]
84 | last_c = c
85 |
86 | while string.length > 0 do
87 | c = string[0, 1]
88 | chain = incr_chain(chain, last_c, c)
89 |
90 | string = string[1..string.length]
91 | last_c = c
92 | end
93 | end
94 | end
95 |
96 | return scale_chain(chain)
97 | end
98 |
99 | def incr_chain(chain, key, token)
100 | if chain[key]
101 | if chain[key][token]
102 | chain[key][token] += 1
103 | else
104 | chain[key][token] = 1
105 | end
106 | else
107 | chain[key] = {}
108 | chain[key][token] = 1
109 | end
110 |
111 | return chain
112 | end
113 |
114 | def scale_chain(chain)
115 | table_len = {}
116 |
117 | chain.each do |key, subkey|
118 | table_len[key] = 0
119 |
120 | subkey.each do |subsubkey, value|
121 | count = value
122 | weighted = (count ** 1.3).floor
123 |
124 | chain[key][subsubkey] = weighted
125 | table_len[key] += weighted
126 | end
127 | end
128 |
129 | chain['table_len'] = table_len
130 |
131 | return chain
132 | end
133 |
134 | # construct name from markov chain
135 | def markov_name(chain)
136 | parts = select_link(chain, 'parts')
137 | names = []
138 |
139 | (0..parts-1).each {
140 | name_len = select_link(chain, 'name_len')
141 | c = select_link(chain, 'initial')
142 | name = c
143 | last_c = c
144 |
145 | while name.length < name_len do
146 | c = select_link(chain, last_c)
147 | name += c
148 | last_c = c
149 | end
150 | names.push(name)
151 | }
152 |
153 | return names.join(' ')
154 | end
155 |
156 | def select_link(chain, key)
157 | len = chain['table_len'][key]
158 | idx = (rand() * len).floor
159 |
160 | t = 0
161 | chain[key].each do |chain_key, chain_value|
162 | t += chain_value
163 | return chain_key if (idx < t)
164 | end
165 |
166 | return '-'
167 | end
168 | end
169 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/player_levels.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/player_levels.rb
2 | # Stats table for each level the player can reach
3 |
4 | module Gemwarrior
5 | module PlayerLevels
6 | def self.get_level_stats(level)
7 | case level
8 | when 1
9 | {
10 | level: 1, xp_start: 0,
11 | hp_max: 30,
12 | atk_lo: 1, atk_hi: 2,
13 | defense: 1, dexterity: 3,
14 | special_abilities: nil
15 | }
16 | when 2
17 | {
18 | level: 2, xp_start: 50,
19 | hp_max: 35,
20 | atk_lo: 2, atk_hi: 3,
21 | defense: 3, dexterity: 4,
22 | special_abilities: :rocking_vision
23 | }
24 | when 3
25 | {
26 | level: 3, xp_start: 120,
27 | hp_max: 45,
28 | atk_lo: 3, atk_hi: 5,
29 | defense: 5, dexterity: 6,
30 | special_abilities: :gleam
31 | }
32 | when 4
33 | {
34 | level: 4, xp_start: 250,
35 | hp_max: 55,
36 | atk_lo: 5, atk_hi: 6,
37 | defense: 6, dexterity: 8,
38 | special_abilities: :rock_slide
39 | }
40 | when 5
41 | {
42 | level: 5, xp_start: 600,
43 | hp_max: 70,
44 | atk_lo: 7, atk_hi: 8,
45 | defense: 8, dexterity: 9,
46 | special_abilities: :graniton
47 | }
48 | when 6
49 | {
50 | level: 6, xp_start: 1000,
51 | hp_max: 85,
52 | atk_lo: 8, atk_hi: 10,
53 | defense: 10, dexterity: 11,
54 | special_abilities: :stone_face
55 | }
56 | when 7
57 | {
58 | level: 7, xp_start: 1500,
59 | hp_max: 100,
60 | atk_lo: 10, atk_hi: 12,
61 | defense: 13, dexterity: 14,
62 | special_abilities: :breakthru
63 | }
64 | else
65 | {
66 | level: 8, xp_start: 10000,
67 | hp_max: 200,
68 | atk_lo: 50, atk_hi: 100,
69 | defense: 50, dexterity: 100,
70 | special_abilities: nil
71 | }
72 | end
73 | end
74 |
75 | def self.check_level(xp)
76 | if xp < 50
77 | 1
78 | elsif xp < 120
79 | 2
80 | elsif xp < 250
81 | 3
82 | elsif xp < 600
83 | 4
84 | elsif xp < 1000
85 | 5
86 | elsif xp < 1500
87 | 6
88 | elsif xp < 10000
89 | 7
90 | else
91 | 8
92 | end
93 | end
94 |
95 | def self.get_ability_description(ability)
96 | case ability
97 | when :rocking_vision # LV2
98 | 'Allows you to see the enemy hit points while in battle.'
99 | when :gleam # LV3
100 | 'The map now shows every place in Jool, whether you have been there or not.'
101 | when :rock_slide # LV4
102 | 'Adds a random boost to the player\'s attack in battle.'
103 | when :graniton # LV5
104 | 'Chance to be much more accurate in your attacks.'
105 | when :stone_face # LV6
106 | 'Chance to auto-win in battle against any non-boss monster (does not work in arena or if ambushed).'
107 | when :breakthru
108 | 'Teleport to any location, given that you can remember its name.'
109 | else
110 | 'Unsure, but it\'s probably cool!'
111 | end
112 | end
113 | end
114 | end
115 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/timer.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/timer.rb
2 | # Timer
3 |
4 | require 'observer'
5 |
6 | module Gemwarrior
7 | class Timer
8 | include Observable
9 |
10 | attr_accessor :duration_in_s, :timer_name, :background, :progress, :verbose, :command
11 |
12 | DEFAULTS = {
13 | duration_in_s: 5,
14 | timer_name: 'timer',
15 | background: true,
16 | progress: false,
17 | verbose: false,
18 | command: nil
19 | }
20 |
21 | def initialize(options = {}, repl)
22 | options = DEFAULTS.merge(options)
23 |
24 | self.duration_in_s = options[:duration_in_s]
25 | self.timer_name = options[:timer_name]
26 | self.background = options[:background]
27 | self.progress = options[:progress]
28 | self.verbose = options[:verbose]
29 | self.command = options[:command]
30 |
31 | add_observer(repl)
32 | end
33 |
34 | def start
35 | if background
36 | Thread.start { self.run }
37 | else
38 | self.run
39 | end
40 | end
41 |
42 | def run
43 | puts "#{timer_name} began at #{Time.now} for #{duration_in_s} seconds" if verbose
44 |
45 | end_time = Time.now + duration_in_s
46 |
47 | loop do
48 | sleep 1
49 | print '.' if progress
50 | if Time.now >= end_time
51 | return stop
52 | end
53 | end
54 | end
55 |
56 | def stop
57 | puts "\n#{timer_name} ended at #{Time.now}" if verbose
58 | changed
59 | notify_observers(self.command) unless self.command.nil?
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/lib/gemwarrior/misc/wordlist.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/misc/wordlist.rb
2 | # List of words for flavor text, hopefully randomized from Wordnik
3 |
4 | require 'http'
5 | require 'json'
6 |
7 | require_relative '../game_options'
8 |
9 | module Gemwarrior
10 | class WordList
11 | STATIC_ADJECTIVE_VALUES = [
12 | '5 o\'clock-shadowed', 'angry', 'aristocratic', 'calm', 'choice', 'clinical', 'cracked', 'depressed', 'dingy', 'excited', 'ginormous', 'handsome', 'hydrothermal', 'lackadaisical', 'man-sized', 'moist', 'non-venomous', 'picaresque', 'positive', 'relaxed', 'ruddy', 'smooth', 'shocked', 'sticky', 'tense', 'tingly', 'tired', 'toneless', 'unpolished', 'worn'
13 | ]
14 | STATIC_NOUN_VALUES = [
15 | 'arrestor', 'blockhead', 'busker', 'candlestick', 'cigarette', 'clavinet', 'cursor', 'degeneration', 'devotchka', 'drive', 'earthquake', 'genie', 'granddaddy', 'haunter', 'heater', 'locality', 'nitrogen', 'quitter', 'raccoon', 'radish', 'recession', 'sheepdog', 'smorgasbord', 'softener', 'sphere', 'stage-hand', 'tsunami', 'tuber', 'whatsit', 'zillionaire'
16 | ]
17 | STATIC_NOUN_PLURAL_VALUES = [
18 | 'abutments', 'asterisms', 'bains', 'blebs', 'blowholes', 'chapes', 'civility', 'crocuses', 'dancers', 'deniers', 'diastoles', 'dinges', 'dualism', 'ebullitions', 'extremities', 'fingering', 'gabardines', 'gullets', 'knops', 'nooks', 'payments', 'phaetons', 'scalawags', 'snickers', 'specters', 'splats', 'squiggles', 'thalamuses', 'wallets', 'xylophones'
19 | ]
20 | STATIC_VERB_VALUES = [
21 | 'accentuate', 'accompany', 'blatter', 'bully', 'collide', 'crusade', 'disallow', 'entitle', 'infest', 'lateral', 'micturate', 'mourn', 'munge', 'numb', 'outdraw', 'overstep', 'plummet', 'refill', 'refurnish', 'reroute', 'rumple', 'scupper', 'smoosh', 'spifflicate', 'straighten', 'synthesize', 'terrorize', 'unshift', 'vociferate'
22 | ]
23 |
24 | attr_accessor :type, :limit, :words, :error
25 |
26 | def initialize(type = 'noun', limit = 10)
27 | self.type = type
28 | self.limit = limit
29 | self.words = populate_words(type, limit)
30 | self.error = nil
31 | end
32 |
33 | def get_random_value
34 | random_value = words[rand(0..limit)]
35 |
36 | return random_value.nil? ? get_random_value : random_value
37 | end
38 |
39 | def list_words
40 | words.join(',')
41 | end
42 |
43 | private
44 |
45 | def populate_words(type, limit = 10)
46 | url = 'http://api.wordnik.com:80/v4/words.json/randomWords'
47 | api_key = ENV['WORDNIK_API_KEY']
48 |
49 | unless api_key.nil? || GameOptions.data['use_wordnik'] == false
50 | case type
51 | when 'noun', 'noun-plural', 'adjective', 'verb'
52 | else
53 | error = 'invalid wordlist type'
54 | return
55 | end
56 |
57 | json_return = HTTP.get(
58 | url,
59 | params: {
60 | hasDictionaryDef: true,
61 | includePartOfSpeech: type,
62 | minCorpusCount: 1,
63 | maxCorpusCount: -1,
64 | minDictionaryCount: 1,
65 | maxDictionaryCount: -1,
66 | minLength: 5,
67 | maxLength: 12,
68 | sortBy: 'alpha',
69 | sortOrder: 'asc',
70 | limit: limit,
71 | api_key: api_key
72 | }
73 | )
74 |
75 | json_data = JSON.parse(json_return.to_s)
76 |
77 | if json_data.include?('type') && json_data.include?('message')
78 | error = "wordnik #{json_data['type']}: #{json_data['message']}"
79 | return get_static_values
80 | else
81 | word_list = []
82 | json_data.map {|j| word_list.push(j['word'])}
83 | if word_list.length > 0
84 | return word_list
85 | else
86 | error = 'Empty array from Wordnik'
87 | return get_static_values(type)
88 | end
89 | end
90 | end
91 |
92 | return get_static_values(type)
93 | end
94 |
95 | def get_static_values(type = nil)
96 | static_values = []
97 | 0.upto(10) do
98 | case type
99 | when 'noun'
100 | static_values.push(STATIC_NOUN_VALUES[rand(0..STATIC_NOUN_VALUES.length-1)])
101 | when 'noun-plural'
102 | static_values.push(STATIC_NOUN_PLURAL_VALUES[rand(0..STATIC_NOUN_PLURAL_VALUES.length-1)])
103 | when 'adjective'
104 | static_values.push(STATIC_ADJECTIVE_VALUES[rand(0..STATIC_ADJECTIVE_VALUES.length-1)])
105 | when 'verb'
106 | static_values.push(STATIC_VERB_VALUES[rand(0..STATIC_VERB_VALUES.length-1)])
107 | else
108 | error = 'invalid wordlist type'
109 | return
110 | end
111 | end
112 | return static_values
113 | end
114 |
115 | end
116 | end
117 |
--------------------------------------------------------------------------------
/lib/gemwarrior/version.rb:
--------------------------------------------------------------------------------
1 | # lib/gemwarrior/version.rb
2 | # Version of Gem Warrior
3 |
4 | module Gemwarrior
5 | VERSION = '0.15.20'
6 | end
7 |
--------------------------------------------------------------------------------
/spec/gemwarrior_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | include Gemwarrior
3 |
4 | describe Gemwarrior do
5 | let(:default_load_options) do
6 | GameOptions.add 'log_file_path', "#{Dir.home}/.gemwarrior_log"
7 | GameOptions.add 'options_file_path', "#{Dir.home}/.gemwarrior_options"
8 |
9 | Game.new(
10 | beast_mode: false,
11 | debug_mode: false,
12 | god_mode: false,
13 | new_game: false,
14 | sound_enabled: false,
15 | sound_volume: 0.3,
16 | use_wordnik: false,
17 | extra_command: nil
18 | )
19 | end
20 |
21 | describe 'basic properties' do
22 | it 'has a version number' do
23 | expect(VERSION).not_to be nil
24 | end
25 | it 'display help menu' do
26 | skip 'not implemented yet' do
27 | end
28 | end
29 | end
30 |
31 | describe 'game load' do
32 | context 'default options' do
33 | it 'displays the main menu' do
34 | skip 'not implemented yet' do
35 | end
36 | end
37 | end
38 | context 'new game option enabled' do
39 | it 'displays the main game prompt and runs the look command' do
40 | skip 'not implemented yet' do
41 | end
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # binary/executable
2 | $LOAD_PATH.unshift File.expand_path('../../bin', __FILE__)
3 | # main module
4 | $LOAD_PATH.unshift File.expand_path('../../lib/gemwarrior', __FILE__)
5 | require 'pry'
6 | require 'game'
7 |
--------------------------------------------------------------------------------
/tests/compare_versions.rb:
--------------------------------------------------------------------------------
1 | new_release_available = false
2 |
3 | puts 'Checking releases...'
4 |
5 | remote_release = '0.10.3'
6 | local_release = '0.10.3'
7 |
8 | 0.upto(2) do |i|
9 | if remote_release.split('.')[i].to_i > local_release.split('.')[i].to_i
10 | new_release_available = true
11 | end
12 | end
13 |
14 | status_text = new_release_available ? "New v#{remote_release} available!" : 'You have the latest version.'
15 |
16 | puts "local_release: #{local_release}"
17 | puts "remote_release #{remote_release}"
18 | puts status_text
--------------------------------------------------------------------------------
/tests/getch_test.rb:
--------------------------------------------------------------------------------
1 | require 'io/console'
2 |
3 | puts 'press a key using STDIN.getc'
4 | c = STDIN.getc
5 | puts "c: #{c.dump}"
6 |
7 | puts 'press another key using STDIN.getch'
8 | ch = STDIN.getch
9 | puts "ch: #{ch.dump}"
10 |
--------------------------------------------------------------------------------
/tests/hooch.rb:
--------------------------------------------------------------------------------
1 | s = 'I still can\'t believe I lost at the Arena! I was doing so well, and then a slippery citrinaga got a cheap shot on me.'
2 | words = s.split(' ')
3 | words_hooched = []
4 |
5 | words.each do |w|
6 | puts "w: #{w}"
7 | if rand(0..100) > 45 and w.length > 1
8 | w = w.split('')
9 | w = w.insert(rand(0..w.length-1), '*HIC*')
10 | w = w.join('')
11 | end
12 | words_hooched << w
13 | end
14 |
15 | puts
16 | puts "Final sentence: #{words_hooched.join(' ')}"
17 |
--------------------------------------------------------------------------------
/tests/item_hashes.rb:
--------------------------------------------------------------------------------
1 | class Item
2 | attr_accessor :name
3 |
4 | def initialize(name = 'item')
5 | self.name = name
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/tests/json_api_call.rb:
--------------------------------------------------------------------------------
1 | require 'http'
2 | require 'json'
3 |
4 | url = 'http://api.wordnik.com:80/v4/words.json/randomWords'
5 |
6 | json_return = HTTP.get(
7 | url,
8 | :params => {
9 | :hasDictionaryDef => true,
10 | :includePartOfSpeech => 'noun-plural',
11 | :minCorpusCount => 10,
12 | :maxCorpusCount => -1,
13 | :minDictionaryCount => 1,
14 | :maxDictionaryCount => -1,
15 | :minLength => 5,
16 | :maxLength => 12,
17 | :sortBy => 'alpha',
18 | :sortOrder => 'asc',
19 | :limit => 10,
20 | :api_key => '63f5001dfacf2d619230e08591702875786da258b471becb6'
21 | }
22 | )
23 |
24 | if json_return
25 | json_data = JSON.parse(json_return.to_s)
26 |
27 | if json_data.include?("type") && json_data.include?("message")
28 | puts "wordnik error: #{json_data["message"]}"
29 | else
30 | word_list = []
31 | json_data.map {|j| word_list.push(j["word"])}
32 | if word_list.length > 0
33 | p word_list
34 | else
35 | puts 'no words received'
36 | end
37 | end
38 | else
39 | puts "json error: #{json_return.to_s}"
40 | end
41 |
42 |
43 |
--------------------------------------------------------------------------------
/tests/module_hashes.rb:
--------------------------------------------------------------------------------
1 | module AudioCues
2 | def self.add key, val
3 | @@cues ||= {}
4 | @@cues[key] = val
5 | end
6 |
7 | def self.cues
8 | @@cues ||= {}
9 | end
10 |
11 | self.add :battle_start, {
12 | synth: [
13 | { frequencies: 'G4', duration: 50 },
14 | { frequencies: 'G#4', duration: 50 },
15 | { frequencies: 'G4', duration: 50 },
16 | { frequencies: 'G#4', duration: 50 },
17 | { frequencies: 'G4', duration: 50 },
18 | { frequencies: 'G#4', duration: 50 }
19 | ],
20 | sample: 'battle_start.wav'
21 | }
22 |
23 | self.add :battle_player_attack, {
24 | synth: [{ frequencies: 'A4,E4,B5', duration: 75 }],
25 | sample: 'battle_player_attack.wav'
26 | }
27 |
28 | self.add :battle_player_miss, {
29 | synth: [{ frequencies: 'A4', duration: 75 }],
30 | sample: 'battle_player_miss.wav'
31 | }
32 |
33 | self.add :battle_monster_attack, {
34 | synth: [{ frequencies: 'B4,E#5,A5', duration: 75 }],
35 | sample: 'battle_monster_attack.wav'
36 | }
37 |
38 | self.add :battle_monster_miss, {
39 | synth: [{ frequencies: 'B4', duration: 75 }],
40 | sample: 'battle_monster_miss.wav'
41 | }
42 |
43 | self.add :intro, {
44 | synth: [
45 | { frequencies: 'A3,E4,C#5,E5', duration: 300 },
46 | { frequencies: 'A3,E4,C#5,F#5', duration: 600 }
47 | ],
48 | sample: 'intro.wav'
49 | }
50 |
51 | self.add :player_resurrection, {
52 | synth: [
53 | { frequencies: 'D#5', duration: 100 },
54 | { frequencies: 'A4', duration: 150 },
55 | { frequencies: 'F#4', duration: 200 },
56 | { frequencies: 'F4', duration: 1000 }
57 | ],
58 | sample: 'player_resurrection.wav'
59 | }
60 |
61 | self.add :player_travel, {
62 | synth: [
63 | { frequencies: 'C4', duration: 75 },
64 | { frequencies: 'D4', duration: 75 },
65 | { frequencies: 'E4', duration: 75 }
66 | ],
67 | sample: 'player_travel.wav'
68 | }
69 |
70 | self.add :win_game, {
71 | synth: [
72 | { frequencies: 'G3', duration: 250 },
73 | { frequencies: 'A3', duration: 50 },
74 | { frequencies: 'B3', duration: 50 },
75 | { frequencies: 'C4', duration: 50 },
76 | { frequencies: 'D4', duration: 250 },
77 | { frequencies: 'E4', duration: 50 },
78 | { frequencies: 'F#4', duration: 50 },
79 | { frequencies: 'G4', duration: 50 },
80 | { frequencies: 'A4', duration: 250 },
81 | { frequencies: 'B4', duration: 50 },
82 | { frequencies: 'C5', duration: 50 },
83 | { frequencies: 'D5', duration: 50 },
84 | { frequencies: 'E5', duration: 50 },
85 | { frequencies: 'F#5', duration: 50 },
86 | { frequencies: 'G5', duration: 1000 }
87 | ],
88 | sample: 'win_game.wav'
89 | }
90 | end
91 |
--------------------------------------------------------------------------------
/tests/test-class/test-class.rb:
--------------------------------------------------------------------------------
1 | class Rat
2 | attr_accessor :name,
3 | :level,
4 | :hp
5 |
6 | def initialize(name = 'rat')
7 | self.name = name
8 | self.level = rand(1..4)
9 | self.hp = rand((self.level * 3)..(self.level * 5))
10 | end
11 | end
12 |
13 | m = [Rat.new]
14 |
15 | rat_o = m[0]
16 | rat_c = m[0].clone
17 |
18 | puts "[initial]"
19 | puts "m[0] : #{m[0].inspect}"
20 | puts "rat_o : #{rat_o.inspect}"
21 | puts "rat_c : #{rat_c.inspect}"
22 |
23 | m[0].hp -= 1
24 |
25 | puts "[m[0] - 1hp]"
26 | puts "m[0] : #{m[0].inspect}"
27 | puts "rat_o : #{rat_o.inspect}"
28 | puts "rat_c : #{rat_c.inspect}"
29 |
30 | rat_o.hp -= 1
31 |
32 | puts "[rat_o - 1hp]"
33 | puts "m[0] : #{m[0].inspect}"
34 | puts "rat_o : #{rat_o.inspect}"
35 | puts "rat_c : #{rat_c.inspect}"
36 |
37 | rat_c.hp -= 1
38 |
39 | puts "[rat_c - 1hp]"
40 | puts "m[0] : #{m[0].inspect}"
41 | puts "rat_o : #{rat_o.inspect}"
42 | puts "rat_c : #{rat_c.inspect}"
43 |
44 | rat_c2 = m[0].clone
45 |
46 | puts "[rat_c2 created from m[0]]"
47 | puts "m[0] : #{m[0].inspect}"
48 | puts "rat_o : #{rat_o.inspect}"
49 | puts "rat_c : #{rat_c.inspect}"
50 | puts "rat_c2: #{rat_c2.inspect}"
51 |
--------------------------------------------------------------------------------
/tests/test-feep/test-feep.rb:
--------------------------------------------------------------------------------
1 | require 'feep'
2 |
3 | sequence = [
4 | {freq_or_note: 'A3', duration: 80},
5 | {freq_or_note: 'E4', duration: 80},
6 | {freq_or_note: 'G4', duration: 80},
7 | {freq_or_note: 'C#5', duration: 80},
8 | {freq_or_note: 'G5', duration: 240}
9 | ]
10 |
11 | defaults = {
12 | :freq_or_note => '440',
13 | :waveform => 'saw',
14 | :volume => 0.3,
15 | :duration => 100,
16 | :notext => true
17 | }
18 |
19 | sequence.each do |seq|
20 | puts "seq before merge: #{seq}"
21 |
22 | seq = defaults.merge(seq)
23 |
24 | puts "seq after merge: #{seq}"
25 |
26 | puts "playing #{seq[:freq_or_note]}"
27 |
28 | Feep::Base.new({
29 | :freq_or_note => seq[:freq_or_note],
30 | :waveform => seq[:waveform],
31 | :volume => seq[:volume],
32 | :duration => seq[:duration],
33 | :notext => seq[:notext]
34 | })
35 | end
--------------------------------------------------------------------------------
/tests/test-save-load/save-load.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'io/console'
3 |
4 | class SaveLoad
5 | SAVE_DATA_FILE = 'save.conf'
6 |
7 | attr_accessor :data_changed
8 |
9 | def initialize
10 | self.data_changed = false
11 | end
12 |
13 | module Config
14 | def self.add key, value
15 | @@data ||= {}
16 | @@data[key] = value
17 | end
18 |
19 | def self.data
20 | @@data ||= {}
21 | end
22 | end
23 |
24 | def show_change_data_menu
25 | puts 'Change Data'
26 | puts '-----------'
27 | puts
28 | puts " (1) Name: #{Config.data['name']}"
29 | puts " (2) Age: #{Config.data['age']}"
30 | puts " (3) Hometown: #{Config.data['hometown']}"
31 | puts
32 | puts ' (q) Back to main menu'
33 | puts
34 | print 'data> '
35 | choice = STDIN.getch.downcase
36 |
37 | case choice
38 | when '1'
39 | print 'Name: '
40 | answer = gets.chomp
41 |
42 | unless answer.empty?
43 | if Config.data['name'].nil?
44 | Config.add 'name', answer
45 | else
46 | Config.data['name'] = answer
47 | end
48 | self.data_changed = true
49 | end
50 | show_change_data_menu
51 | when '2'
52 | print 'Age: '
53 | answer = gets.chomp
54 |
55 | unless answer.empty?
56 | if Config.data['age'].nil?
57 | Config.add 'age', answer
58 | else
59 | Config.data['age'] = answer
60 | end
61 | self.data_changed = true
62 | end
63 | show_change_data_menu
64 | when '3'
65 | print 'Hometown: '
66 | answer = gets.chomp
67 |
68 | unless answer.empty?
69 | if Config.data['hometown'].nil?
70 | Config.add 'hometown', answer
71 | else
72 | Config.data['hometown'] = answer
73 | end
74 | self.data_changed = true
75 | end
76 | show_change_data_menu
77 | when 'q', 'x'
78 | puts
79 | return
80 | else
81 | show_change_data_menu
82 | end
83 | end
84 |
85 | def show_main_menu
86 | puts 'Main Menu'
87 | puts '---------'
88 | puts
89 | puts ' (1) Display loaded data'
90 | puts ' (2) Change data'
91 | puts ' (3) Read from save file'
92 | puts ' (4) Write to save file'
93 | puts
94 | puts ' (q) Quit from script'
95 | puts
96 | print 'menu> '
97 | choice = STDIN.getch.downcase
98 |
99 | case choice
100 | when '1'
101 | puts choice
102 | display_loaded_data
103 | show_main_menu
104 | when '2'
105 | puts choice
106 | show_change_data_menu
107 | show_main_menu
108 | when '3'
109 | puts choice
110 | read_from_save
111 | show_main_menu
112 | when '4'
113 | puts choice
114 | write_to_save
115 | show_main_menu
116 | when 'x', 'q'
117 | puts choice
118 | if data_changed
119 | puts 'You changed stuff. Do you want to save before exiting? (y/n)'
120 | answer = STDIN.getch.downcase
121 |
122 | case answer
123 | when 'y'
124 | write_to_save
125 | end
126 | end
127 | puts "Exiting..."
128 | exit
129 | else
130 | show_main_menu
131 | end
132 | end
133 |
134 | def display_loaded_data
135 | if Config.data.empty?
136 | puts 'No loaded data yet.'
137 | puts
138 | else
139 | Config.data.each do |key, val|
140 | puts "#{key} : #{val}"
141 | end
142 | puts
143 | end
144 | end
145 |
146 | def read_from_save
147 | if File.exist?(SAVE_DATA_FILE)
148 | #save_data = YAML.load_file(SAVE_DATA_FILE)
149 |
150 | print 'Overwrite current session with saved data? (y/n) '
151 | a = STDIN.getch.chomp.downcase
152 |
153 | case a
154 | when 'y'
155 | File.open(SAVE_DATA_FILE).readlines.each do |line|
156 | l = line.split(':')
157 | Config.add l[0], l[1]
158 | end
159 | puts "Successfully read from #{SAVE_DATA_FILE}"
160 | puts
161 | end
162 | else
163 | puts 'No save file.'
164 | end
165 | end
166 |
167 | def write_to_save
168 | File.open(SAVE_DATA_FILE, 'w') do |f|
169 | Config.data.each do |key, val|
170 | f.puts "#{key}:#{val}"
171 | end
172 | end
173 | puts "Wrote to #{SAVE_DATA_FILE}"
174 | puts
175 | end
176 | end
177 |
178 | puts 'Welcome to the Save/Load data test!'
179 | puts
180 | sl = SaveLoad.new
181 | sl.show_main_menu
182 |
--------------------------------------------------------------------------------
/tests/test-save-load/save.conf:
--------------------------------------------------------------------------------
1 | name:mike
2 | age:34
3 |
--------------------------------------------------------------------------------
/tests/test-singleton/game.rb:
--------------------------------------------------------------------------------
1 | require_relative 'game_options'
2 |
3 | puts GameOptions.data
4 | puts GameOptions.data['sound_enabled']
5 |
--------------------------------------------------------------------------------
/tests/test-singleton/game_options.rb:
--------------------------------------------------------------------------------
1 | module GameOptions
2 | def self.add key, value
3 | @@data ||= {}
4 | @@data[key] = value
5 | end
6 |
7 | def self.data
8 | @@data ||= {}
9 | end
10 | end
11 |
12 | GameOptions.data
13 |
14 | GameOptions.add 'sound_enabled', true
15 | GameOptions.add 'sound_volume', 0.3
16 |
--------------------------------------------------------------------------------