diff --git a/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/bcrypt_ext.so b/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/bcrypt_ext.so deleted file mode 100644 index e7d37b2..0000000 Binary files a/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/bcrypt_ext.so and /dev/null differ diff --git a/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/gem.build_complete b/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/gem.build_complete deleted file mode 100644 index e69de29..0000000 diff --git a/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/gem_make.out b/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/gem_make.out deleted file mode 100644 index f88e6d1..0000000 --- a/.bundle/ruby/3.2.0/extensions/x86_64-linux/3.2.0/bcrypt-3.1.18/gem_make.out +++ /dev/null @@ -1,36 +0,0 @@ -current directory: /home/leeloo/github/ruby-text-game/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri -/home/leeloo/.rbenv/versions/3.2.0/bin/ruby -I /home/leeloo/.rbenv/versions/3.2.0/lib/ruby/site_ruby/3.2.0 extconf.rb -creating Makefile - -current directory: /home/leeloo/github/ruby-text-game/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri -make DESTDIR\= sitearchdir\=./.gem.20230118-31928-balnvr sitelibdir\=./.gem.20230118-31928-balnvr clean - -current directory: /home/leeloo/github/ruby-text-game/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri -make DESTDIR\= sitearchdir\=./.gem.20230118-31928-balnvr sitelibdir\=./.gem.20230118-31928-balnvr -compiling bcrypt_ext.c -bcrypt_ext.c: In function ‘Init_bcrypt_ext’: -bcrypt_ext.c:108:6: warning: old-style function definition [-Wold-style-definition] - 108 | void Init_bcrypt_ext(){ - | ^~~~~~~~~~~~~~~ -bcrypt_ext.c: At top level: -cc1: note: unrecognized command-line option ‘-Wno-self-assign’ may have been intended to silence earlier diagnostics -cc1: note: unrecognized command-line option ‘-Wno-parentheses-equality’ may have been intended to silence earlier diagnostics -cc1: note: unrecognized command-line option ‘-Wno-constant-logical-operand’ may have been intended to silence earlier diagnostics -compiling crypt_blowfish.c -gcc -D__SKIP_GNU -I/home/leeloo/.rbenv/versions/3.2.0/include -c -o x86.o x86.S -compiling crypt_gensalt.c -compiling wrapper.c -wrapper.c:182:60: warning: ‘struct crypt_data’ declared inside parameter list will not be visible outside of this definition or declaration - 182 | char *crypt_r(const char *key, const char *setting, struct crypt_data *data) - | ^~~~~~~~~~ -cc1: note: unrecognized command-line option ‘-Wno-self-assign’ may have been intended to silence earlier diagnostics -cc1: note: unrecognized command-line option ‘-Wno-parentheses-equality’ may have been intended to silence earlier diagnostics -cc1: note: unrecognized command-line option ‘-Wno-constant-logical-operand’ may have been intended to silence earlier diagnostics -linking shared-object bcrypt_ext.so - -current directory: /home/leeloo/github/ruby-text-game/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri -make DESTDIR\= sitearchdir\=./.gem.20230118-31928-balnvr sitelibdir\=./.gem.20230118-31928-balnvr install -/usr/bin/install -c -m 0755 bcrypt_ext.so ./.gem.20230118-31928-balnvr - -current directory: /home/leeloo/github/ruby-text-game/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri -make DESTDIR\= sitearchdir\=./.gem.20230118-31928-balnvr sitelibdir\=./.gem.20230118-31928-balnvr clean diff --git a/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri/Makefile b/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri/Makefile index e632bbc..ed00502 100644 --- a/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri/Makefile +++ b/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/ext/mri/Makefile @@ -13,29 +13,29 @@ NULLCMD = : #### Start of system configuration section. #### srcdir = . -topdir = /home/leeloo/.rbenv/versions/3.2.0/include/ruby-3.2.0 +topdir = /usr/include/ruby-3.2.0 hdrdir = $(topdir) -arch_hdrdir = /home/leeloo/.rbenv/versions/3.2.0/include/ruby-3.2.0/x86_64-linux +arch_hdrdir = /usr/include/x86_64-linux-gnu/ruby-3.2.0 PATH_SEPARATOR = : VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby -prefix = $(DESTDIR)/home/leeloo/.rbenv/versions/3.2.0 -rubysitearchprefix = $(rubylibprefix)/$(sitearch) -rubyarchprefix = $(rubylibprefix)/$(arch) +prefix = $(DESTDIR)/usr +rubysitearchprefix = $(sitearchlibdir)/$(RUBY_BASE_NAME) +rubyarchprefix = $(archlibdir)/$(RUBY_BASE_NAME) rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) exec_prefix = $(prefix) -vendorarchhdrdir = $(vendorhdrdir)/$(sitearch) -sitearchhdrdir = $(sitehdrdir)/$(sitearch) -rubyarchhdrdir = $(rubyhdrdir)/$(arch) +vendorarchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/vendor_ruby +sitearchhdrdir = $(sitearchincludedir)/$(RUBY_VERSION_NAME)/site_ruby +rubyarchhdrdir = $(archincludedir)/$(RUBY_VERSION_NAME) vendorhdrdir = $(rubyhdrdir)/vendor_ruby sitehdrdir = $(rubyhdrdir)/site_ruby rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) -vendorarchdir = $(vendorlibdir)/$(sitearch) +vendorarchdir = $(rubysitearchprefix)/vendor_ruby/$(ruby_version) vendorlibdir = $(vendordir)/$(ruby_version) vendordir = $(rubylibprefix)/vendor_ruby -sitearchdir = $(sitelibdir)/$(sitearch) +sitearchdir = $(DESTDIR)/usr/local/lib/x86_64-linux-gnu/site_ruby sitelibdir = $(sitedir)/$(ruby_version) -sitedir = $(rubylibprefix)/site_ruby -rubyarchdir = $(rubylibdir)/$(arch) +sitedir = $(DESTDIR)/usr/local/lib/site_ruby +rubyarchdir = $(rubyarchprefix)/$(ruby_version) rubylibdir = $(rubylibprefix)/$(ruby_version) sitearchincludedir = $(includedir)/$(sitearch) archincludedir = $(includedir)/$(arch) @@ -53,10 +53,10 @@ infodir = $(datarootdir)/info docdir = $(datarootdir)/doc/$(PACKAGE) oldincludedir = $(DESTDIR)/usr/include includedir = $(prefix)/include -runstatedir = $(localstatedir)/run -localstatedir = $(prefix)/var +runstatedir = $(DESTDIR)/var/run +localstatedir = $(DESTDIR)/var sharedstatedir = $(prefix)/com -sysconfdir = $(prefix)/etc +sysconfdir = $(DESTDIR)/etc datadir = $(datarootdir) datarootdir = $(prefix)/share libexecdir = $(exec_prefix)/libexec @@ -66,12 +66,12 @@ archdir = $(rubyarchdir) CC_WRAPPER = -CC = gcc -CXX = g++ +CC = x86_64-linux-gnu-gcc +CXX = x86_64-linux-gnu-g++ LIBRUBY = $(LIBRUBY_SO) LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a -LIBRUBYARG_SHARED = -Wl,-rpath,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME) -LIBRUBYARG_STATIC = -Wl,-rpath,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS) +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) empty = OUTFLAG = -o $(empty) COUTFLAG = -o $(empty) @@ -85,39 +85,39 @@ debugflags = -ggdb3 warnflags = -Wall -Wextra -Wdeprecated-declarations -Wdiv-by-zero -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef cppflags = CCDLFLAGS = -fPIC -CFLAGS = $(CCDLFLAGS) $(cflags) -fPIC $(ARCH_FLAG) +CFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.5 -fPIC $(ARCH_FLAG) INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) DEFS = -CPPFLAGS = -D__SKIP_GNU -I/home/leeloo/.rbenv/versions/3.2.0/include $(DEFS) $(cppflags) -CXXFLAGS = $(CCDLFLAGS) $(ARCH_FLAG) -ldflags = -L. -L/home/leeloo/.rbenv/versions/3.2.0/lib -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed -dldflags = -L/home/leeloo/.rbenv/versions/3.2.0/lib -Wl,--compress-debug-sections=zlib +CPPFLAGS = -D__SKIP_GNU -Wdate-time -D_FORTIFY_SOURCE=3 $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=BUILDDIR=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=BUILDDIR=/usr/src/ruby3.2-3.2.3-1ubuntu0.24.04.5 $(ARCH_FLAG) +ldflags = -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,--no-as-needed +dldflags = -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now ARCH_FLAG = DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) LDSHARED = $(CC) -shared LDSHAREDXX = $(CXX) -shared -AR = gcc-ar +AR = x86_64-linux-gnu-gcc-ar EXEEXT = -RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) -RUBY_SO_NAME = ruby +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)3.2 +RUBY_SO_NAME = ruby-3.2 RUBYW_INSTALL_NAME = RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) RUBYW_BASE_NAME = rubyw RUBY_BASE_NAME = ruby -arch = x86_64-linux +arch = x86_64-linux-gnu sitearch = $(arch) ruby_version = 3.2.0 -ruby = $(bindir)/$(RUBY_BASE_NAME) +ruby = $(bindir)/$(RUBY_BASE_NAME)3.2 RUBY = $(ruby) -BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME) +BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)3.2 ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h RM = rm -f RM_RF = rm -fr RMDIRS = rmdir --ignore-fail-on-non-empty -p -MAKEDIRS = /usr/bin/mkdir -p +MAKEDIRS = /bin/mkdir -p INSTALL = /usr/bin/install -c INSTALL_PROG = $(INSTALL) -m 0755 INSTALL_DATA = $(INSTALL) -m 644 @@ -127,8 +127,8 @@ TOUCH = exit > #### End of system configuration section. #### preload = -libpath = . $(libdir) -LIBPATH = -L. -L$(libdir) -Wl,-rpath,$(libdir) +libpath = . $(archlibdir) +LIBPATH = -L. -L$(archlibdir) DEFFILE = CLEANFILES = mkmf.log @@ -142,7 +142,7 @@ LOCAL_LIBS = LIBS = $(LIBRUBYARG_SHARED) -lm -lpthread -lc ORIG_SRCS = bcrypt_ext.c crypt.c crypt_blowfish.c crypt_gensalt.c wrapper.c SRCS = $(ORIG_SRCS) bcrypt_ext.c crypt_blowfish.c x86.c crypt_gensalt.c wrapper.c -OBJS = bcrypt_ext.o crypt_blowfish.o x86.o crypt_gensalt.o wrapper.o +OBJS = bcrypt_ext.o crypt_blowfish.o crypt_gensalt.o wrapper.o x86.o HDRS = $(srcdir)/crypt.h $(srcdir)/crypt_blowfish.h $(srcdir)/crypt_gensalt.h $(srcdir)/ow-crypt.h LOCAL_HDRS = TARGET = bcrypt_ext diff --git a/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/lib/bcrypt_ext.so b/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/lib/bcrypt_ext.so old mode 100644 new mode 100755 index e7d37b2..3802309 Binary files a/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/lib/bcrypt_ext.so and b/.bundle/ruby/3.2.0/gems/bcrypt-3.1.18/lib/bcrypt_ext.so differ diff --git a/.bundle/ruby/3.2.0/specifications/bcrypt-3.1.18.gemspec b/.bundle/ruby/3.2.0/specifications/bcrypt-3.1.18.gemspec index b5fc288..44d662b 100644 --- a/.bundle/ruby/3.2.0/specifications/bcrypt-3.1.18.gemspec +++ b/.bundle/ruby/3.2.0/specifications/bcrypt-3.1.18.gemspec @@ -18,10 +18,10 @@ Gem::Specification.new do |s| s.homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--title".freeze, "bcrypt-ruby".freeze, "--line-numbers".freeze, "--inline-source".freeze, "--main".freeze, "README.md".freeze] - s.rubygems_version = "3.4.3".freeze + s.rubygems_version = "3.4.20".freeze s.summary = "OpenBSD's bcrypt() password hashing algorithm.".freeze - s.installed_by_version = "3.4.3" if s.respond_to? :installed_by_version + s.installed_by_version = "3.4.20" if s.respond_to? :installed_by_version s.specification_version = 4 diff --git a/.gitignore b/.gitignore index 18dc187..67a7898 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .DS_Store *.env .bundle +saves/ diff --git a/Gemfile b/Gemfile index 29e6aa5..da79126 100644 --- a/Gemfile +++ b/Gemfile @@ -8,5 +8,3 @@ gemspec gem "rake", "~> 13.0" gem "rubocop", "~> 1.21" - -gem "bcrypt" diff --git a/README.md b/README.md index 2840554..c7a98b5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,149 @@ -# Ruby Kingdom -A simple text based game built in Ruby +# Ruby Kingdom - Enhanced Text Adventure -# [Play it on Replit!](https://replit.com/@CrystalCampbell/Ruby-Text-Game?v=1) +A mystical text-based adventure game built in Ruby, where code and magic intertwine! Explore the Ruby Kingdom, complete quests, battle monsters, and seek the legendary Ruby Castle where the Heart of Ruby awaits. + +## ✨ New Features + +### 🛡️ Local Save System +- **Unlimited save slots** - Create as many saves as you want +- **Named saves** - Give your saves custom names or use auto-generated ones +- **Complete character persistence** - All progress, items, stats, and location saved +- **Load/Delete management** - Easy save file management from main menu +- **No authentication required** - Removed Firebase dependency for local-only saves + +### 📜 Quest System +- **Starter quests** automatically given to new characters +- **Quest tracking** with progress indicators +- **Multiple quest types**: Kill enemies, explore locations, find special areas +- **Rewards** including gold and experience points +- **Quest log** accessible anytime during gameplay + +### 🗺️ Enhanced Exploration +- **Rich location descriptions** with Ruby Kingdom lore +- **9 unique biomes**: Ruby Forest, Crystal Lake, Cursed Tarpit, Ancient Ruins, and more +- **Location tracking** for quest progression +- **Visual map** showing your current position +- **Discovery rewards** for visiting new areas + +### ⚔️ Improved Combat +- **Enhanced battle feedback** with emojis and better descriptions +- **Quest integration** - battles contribute to quest progress +- **Balanced enemy scaling** based on player level +- **Victory rewards** with gold and experience + +### 🏪 Advanced Shop System +- **Ruby Kingdom Blacksmith** with immersive dialogue +- **6 item categories**: Weapons, potions, shields, magic items +- **Magical effects**: Ruby-touched items with special powers +- **Stat upgrades**: Permanent improvements to attack, HP, and more +- **Lore integration**: Shop items tied to Ruby Kingdom mythology + +### 🎒 Enhanced Character System +- **Detailed inventory** showing equipped items and stats +- **Character progression** with leveling and stat growth +- **Three classes**: Warrior, Mage, Programmer (each with unique starting equipment) +- **Comprehensive stats tracking**: HP, Attack, Gold, EXP, Level + +## 🎮 How to Play + +### Starting the Game +1. Run `ruby main.rb` +2. Choose from the main menu: + - **Load Game** - Continue from a saved adventure + - **New Game** - Create a new character + - **Delete Save** - Remove unwanted save files + - **Exit** - Close the game + +### Character Creation +1. Choose your character name +2. Select your class: + - **Warrior** - Master of blade and battle + - **Mage** - Wielder of arcane mysteries + - **Programmer** - Hacker of reality's code + +### Gameplay Commands +- **Move** - Travel between locations (North, South, East, West) +- **Fight** - Battle enemies for gold and experience +- **Check Inventory** - View items, stats, and equipment +- **Quest Log** - Track active and completed quests +- **Save Game** - Save your progress at any time +- **Shop** - Purchase weapons, potions, and magical items (when available) + +### Quest System +- New characters receive starter quests automatically +- Complete quests by killing enemies, exploring locations, or finding special places +- Check your Quest Log regularly to track progress +- Completed quests provide gold and experience rewards + +## 🌟 Game Features + +### Save System +- Saves stored in `saves/` directory as JSON files +- Automatic backup of all character data +- Unlimited save slots with custom naming +- Easy save management from main menu + +### Combat +- Turn-based battle system +- Enemy difficulty scales with player level +- Creative combat input (shout battle cries!) +- Quest progress tracking for victories + +### Exploration +- 3x3 grid world with 9 unique locations +- Each location features rich descriptions and unique atmosphere +- Random enemy encounters and special locations +- Castle and shop locations for advanced gameplay + +### Character Progression +- Experience points and leveling system +- Gold economy for purchasing upgrades +- Equipment system with weapon upgrades +- Stat improvements through items and leveling + +## 🔧 Technical Details + +### Dependencies +- Ruby (no external gems required) +- JSON support for save system +- File system access for save storage + +### Installation +1. Clone the repository +2. Navigate to the game directory +3. Run `ruby main.rb` + +### File Structure +``` +lib/ +├── auth.rb (legacy - can be removed) +├── character.rb - Character class and stats +├── enemy.rb - Enemy generation and combat +├── game.rb - Main game loop and combat system +├── intro.rb - Game initialization +├── items.rb - Item definitions +├── location.rb - Location generation and descriptions +├── main_menu.rb - Main menu and character creation +├── map.rb - World map and navigation +├── menu.rb - In-game menu system +├── quest_system.rb - Quest management and tracking +├── save_system.rb - Save/load functionality +└── [other support files] +saves/ - Save game files (auto-created) +``` + +## 🎯 Ruby Kingdom Lore + +In the mystical Ruby Kingdom, ancient magic flows through crystalline formations scattered across the land. The legendary Ruby Castle holds the Heart of Ruby - the source of all magical power in the realm. As an adventurer, you must explore diverse biomes, from the Enchanted Ruby Forest to the Cursed Tarpit, seeking the castle while growing stronger through quests and battles. + +Each location tells part of the kingdom's story: +- **Ruby Mountain** - Ancient runes tell of brave adventurers +- **Crystal Lake** - Blessed waters that sparkle with ruby energy +- **Ancient Ruins** - Remnants of the first Ruby Mages +- **Forbidden Wasteland** - Cursed lands where dark magic failed + +The Ruby Kingdom Blacksmith forges legendary weapons infused with the land's magical power, helping adventurers prepare for the challenges ahead. + +--- + +*Find the Ruby Castle. Claim your destiny. The Heart of Ruby awaits...* diff --git a/lib/character.rb b/lib/character.rb index 37df131..54622e2 100644 --- a/lib/character.rb +++ b/lib/character.rb @@ -23,7 +23,7 @@ def initialize @next_level_exp = 10 @alive = true @equipped_weapon = "Sword" - @location = 0 + @location = 5 # Start at center of map end @@ -76,7 +76,7 @@ def get_status def revive @gold = 0 @alive = true - @hp = @_hp_max + @hp = @hp_max end def check_status @@ -121,7 +121,7 @@ def get_weapon end def set_gold(gold_amt, add_gold) - if add_gold == false && gold_amt > @_gold + if add_gold == false && gold_amt > @gold @gold = 0 elsif add_gold == true @gold = @gold + gold_amt @@ -182,5 +182,12 @@ def get_atk end ## Map Location + def get_location + @location + end + + def set_location(location) + @location = location + end end diff --git a/lib/game.rb b/lib/game.rb index 3118575..a4ea000 100644 --- a/lib/game.rb +++ b/lib/game.rb @@ -1,6 +1,7 @@ require "./lib/slow_text.rb" require "./lib/character.rb" require "./lib/enemy.rb" +require "./lib/quest_system.rb" class Game @@ -15,24 +16,18 @@ def combat_game while @current_character.get_status == true && @combat_mode == true enemy = Enemy.new(@current_character) - puts puts - puts "Oh no! You spot a level #{enemy.get_level} #{enemy.get_name}!".red + puts "⚔️ Oh no! You spot a level #{enemy.get_level} #{enemy.get_name}!".red sleep 2 puts "Fight! Fight! Fight!".green - while enemy.get_alive? == true - - puts - sleep 1 #Enemy Atk - puts "#{enemy.get_name} attacks you for #{enemy.get_atk}!".red.bold @current_character.change_hp(enemy.get_atk, "loss") break if @current_character.get_status == false @@ -44,7 +39,6 @@ def combat_game player_words = gets.chomp #player Atk - puts "You shout \"#{player_words}!\" as you attack #{enemy.get_name} with your #{@current_character.get_weapon} for #{@current_character.get_atk}!".red.italic enemy.remove_hp(@current_character.get_atk) break if enemy.get_alive? == false @@ -59,7 +53,11 @@ def combat_game sleep 1 if @current_character.get_status == true puts - puts "You have beaten #{enemy.get_name}!" + puts "🏆 You have beaten #{enemy.get_name}!" + + # Update quest progress + QuestSystem.update_quest_progress(:enemy_killed, enemy.get_name.downcase) + @current_character.add_exp(enemy.get_worth_exp) @current_character.set_gold(enemy.get_gold, true) puts @@ -73,7 +71,6 @@ def combat_game break end - end puts @@ -83,8 +80,6 @@ def combat_game $map.defeat_enemy $map.return_to_menu end - - end def game_over diff --git a/lib/intro.rb b/lib/intro.rb index 5f299ae..7ddb85d 100644 --- a/lib/intro.rb +++ b/lib/intro.rb @@ -5,120 +5,36 @@ require "./lib/random_name_class.rb" require "./lib/pokemon_api.rb" require "./lib/game.rb" -require "./lib/auth.rb" +require "./lib/main_menu.rb" +require "./lib/quest_system.rb" class Intro -WARRIOR_TEXT = "A warrior? Guess you expect a sword now too, huh?" -MAGE_TEXT= "A mage? Like Harry Potter? Hope your brought your own wand." -PROGRAMMER_TEXT = "You wanna be a programmer? That's.... weird." -PROGRAMMER_TEXT_2 = "What are you even going to fight with?" + def run + MainMenu.show_main_menu + run_game + end + + def run_game + # Create game instance & add attributes + $current_game = Game.new($current_character) + $map = Map.new + + # Initialize quests for new characters (level 1) + if $current_character.get_level == 1 && $current_character.instance_variable_get(:@exp_points) == 0 + puts + sleep 1 + puts "📜 The Ruby Kingdom Adventurer's Guild has tasks for you...".cyan + sleep 1 + QuestSystem.initialize_starter_quests + puts + sleep 2 + end + + # Set character location (default to center, or load from save) + location = $current_character.get_location + location = 5 if location.nil? || location == 0 + $map.set_character_location(location) + end -NUMBER_INPUT_TEXT = "You couldn't even type out the whole word?" -WORD_INPUT_TEXT = "Why didn't you just type the number?" -MISTAKE_TEXT = "Really?" -MISTAKE_TEXT_2 = "Let's try this again.." - -## Welcome text - -def run - greeting - skip_check - run_game - - -end - -def greeting -puts <<-'BIG_TEXT' -__ __ _ _ ____ _ -\ \ / /__| | ___ ___ _ __ ___ ___ | |_ ___ | _ \ _ _| |__ _ _ - \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | __/ _ \ | |_) | | | | '_ \| | | | - \ V V / __/ | (_| (_) | | | | | | __/ | || (_) | | _ <| |_| | |_) | |_| | - \_/\_/ \___|_|\___\___/|_| |_| |_|\___| \__\___/ |_| \_\\__,_|_.__/ \__, | - |___/ - _ ___ _ _ - | |/ (_)_ __ __ _ __| | ___ _ __ ___ | | - | ' /| | '_ \ / _` |/ _` |/ _ \| '_ ` _ \| | - | . \| | | | | (_| | (_| | (_) | | | | | |_| - |_|\_\_|_| |_|\__, |\__,_|\___/|_| |_| |_(_) - |___/ -BIG_TEXT - -puts -puts -slow_text do - "Ruby Kingdom is a simple text-based game built in ".cyan + "Ruby".red -end - -slow_text do - "Find me on Github @leeloomina".green -end -puts -puts - -sleep 1 - -end - -# login = "" -# while login != "y" && login != "n" -# puts "Have you been here before?" -# puts "Y/N" -# print "> ".green -# login = gets.chomp.downcase -# end - -# if login.downcase == "y" -# Auth.login -# else -# Auth.character_creation -# end - -def skip_check -slow_text do - "Would you like to skip the introduction?" -end -slow_text do - "Y/N" end -print "> ".green -input = gets.chomp.downcase -puts -if input == "yes" || input == "y" - Auth.intro_skip -else - Auth.character_intro -end - -puts -sleep 1 -end - -## Show map -# ## Create game instance & add attributes - -def run_game - -$current_game = Game.new($current_character) -$map = Map.new -# map.generate_map - $map.set_character_location(5) - -end - -end -# $current_map = #get map - -# $current_game.set_character($current_character) -# $current_game.set_map($current_map) - -# $current_game.start_game - -## User input - -## Inventory - -## Move - -## Randomly gen enemy diff --git a/lib/location.rb b/lib/location.rb index 4f3f9ef..ae61ab3 100644 --- a/lib/location.rb +++ b/lib/location.rb @@ -10,65 +10,65 @@ class Location ## These are intentionally out of the correct indentation for display formatting reasons. @@location_descriptions = { "mountain" => """ -You find yourself standing at the base of a towering mountain. -The rough, rocky terrain stretches up before you, leading to a jagged peak that disappears into the clouds above. -The air is thin and crisp, and the sound of the wind whipping through the crags and crevices of the mountain is the only thing you can hear.", +🏔️ You find yourself standing at the base of the Ruby Mountain, one of the kingdom's most treacherous peaks. +The rough, rocky terrain stretches up before you, leading to a jagged peak where ruby crystals gleam in the sunlight. +The air is thin and crisp, filled with magic. Ancient runes are carved into the mountainside, +telling tales of brave adventurers who sought the Ruby Castle's secrets.""", "lake" => """ -As you continue on your journey, you find yourself walking along the shores of a serence lake. -The calm water reflects the blue sky above you. -You watch as a family of ducks slide into the water as your grow near.""", +🏞️ As you continue on your journey, you find yourself walking along the shores of the Crystal Lake. +The calm water reflects not just the blue sky, but shimmers with an otherworldly ruby glow. +Local legends say this lake was blessed by the Ruby Heart itself. +A family of mystical swans glide across the surface, their feathers sparkling with magical energy.""", "grasslands" => """ -Tall grass stretches out before you, as far as you can see. -The sound of small birds chirping and insects buzzing about fills the air around you.""", +🌾 The Ruby Grasslands stretch out before you, as far as you can see. +The tall grass sways in patterns that seem almost intentional, as if guided by unseen forces. +Ruby wildflowers dot the landscape, their petals glowing softly in the breeze. +You can hear the songs of crystal birds and feel the ancient magic that flows through this land.""", "tarpit" => """ -Ahead of you lies a vast tar pit. -The ground feels like syrup. -Thick, sticky.. it grabs at your feet as you walk. -The sent of decay fills the air. -The only trees that survive here are blacked and twisted.""", +⚫ Ahead of you lies the Cursed Tarpit, a scar upon the beautiful Ruby Kingdom. +The ground feels like cursed syrup that grabs at your boots with each step. +This place was once a thriving ruby mine until dark magic corrupted it. +The twisted, blackened trees whisper warnings of the dangers that lurk in the shadows.""", "forest" => """ -The trail you're following winds into a dense forest. -The trees here are tall and ancient, their branches only let in small streams of sunlight. -The air smells thick with the scent of recent rain. -You hear small creatues scurrying away as you approach.""", +🌲 The trail winds into the Enchanted Ruby Forest, where ancient magic runs deepest. +The towering trees are adorned with ruby bark that glows faintly in the dim light. +Streams of magical energy filter down through the canopy like golden sunbeams. +You hear the rustle of mystical creatures and feel the watchful eyes of forest guardians.""", "ruins" => """ -Just up ahead you spot some sort of structures. A town? -As you near, you start to realize it's abandonded. -In fact... it hasn't been occupied for a very long time. -The ancient stone buildings are covered with vines, their walls crumbling. -Nature is hard at work, taking back her land.", +🏛️ Before you stand the Ancient Ruby Ruins, remnants of the kingdom's earliest civilization. +These weathered stone buildings once housed the first Ruby Mages who discovered the Heart's power. +Ruby crystals still grow from the crumbling walls, pulsing with residual magic. +The spirits of ancient scholars seem to whisper secrets of forgotten spells and lost treasures.""", "desert" => """ -In front of you there is only one thing - sand. You hate sand. -It's course, rough, and irritating, and it gets everywhere. -The land ahead sparkles in the intense sunlight. -Wind whips through the dunes, picking up particles. -You squint your eyes as you try to continue.""", +🏜️ The Ruby Desert spreads endlessly before you, its red sands sparkling like crushed gems. +This harsh landscape tests the resolve of every adventurer who dares cross it. +Mirages dance in the heat, sometimes revealing glimpses of the legendary Ruby Castle. +The wind carries tales of buried treasures and the bones of those who couldn't find their way.""", "graveyard" => """ -A graveyard stretches out before you. -Rows of weathered headstones stand as silent monuments to the passage of time. -You feel uneasy. -The ground below your feet is loose and uneven. -The air feels damp and smells of mold.""", +⚰️ The Hallowed Graveyard stands as a monument to Ruby Kingdom's fallen heroes. +Ancient headstones bear the names of legendary warriors who died protecting the realm. +Ruby roses grow wild here, their thorns sharp but their blooms beautiful. +You feel a solemn reverence and the presence of noble spirits who still guard their sacred rest.""", "stream" => """ -A bubbling stream winds its way through the landscape ahead. -The water is blue and so clear that you can see small schools of minnows swimming about. -You feel a refreshing breeze.""", +🏞️ The Ruby Stream winds through the landscape like a ribbon of liquid light. +The crystal-clear water flows from the heart of the kingdom, carrying magical properties. +Schools of rainbow fish swim in the current, their scales shimmering with ruby dust. +Drinking from this stream is said to restore both body and spirit.""", "wasteland" => """ -The sky above you suddenly darkens. -Shadows grow and the wind howls. -The land is filled with the bones of animals unfortunate enough to venture here. -Nothing survives in this place for long. Best to move along quickly.""", +💀 The Forbidden Wasteland stretches before you, a realm where few dare to tread. +The sky above churns with dark clouds shot through with ominous red lightning. +This cursed land was created when dark sorcerers tried to steal the Ruby Heart's power. +The bones of fallen monsters litter the ground, and shadows move independently of their casters.""", "castle" => """ -An ancient castle stands before you. -The grey stone walls are tall and formidable. -A deep and digusting moat surrounds it. -The wooden drawbridge is open, as if to invite you inside...""", +🏰 The legendary Ruby Castle rises majestically before you, its crystalline spires reaching toward the heavens! +Built from pure ruby crystal, the entire structure pulses with magical energy. +This is the heart of Ruby Kingdom, where the Ruby Heart - source of all magic - awaits within. +The drawbridge beckons you forward, as if the castle itself recognizes your worthy spirit.""", "shop" => """ -The air is filled with the chatter of people going about their daily business. -Just up ahead is a busy town square. -Local merchants have set up shop to peddle their wares. -Chickens cluck from metal cages, vegetables lay in woven baskets, but it's the local blacksmith shop that catches your eye. -You peer through the window to take a look at their offerings.""" +🏪 The bustling Ruby Kingdom Market Square spreads out before you. +Merchants from across the realm gather here to trade in magical goods and enchanted wares. +The famous Ruby Kingdom Blacksmith's forge glows bright red, where legendary weapons are born. +The air rings with the sound of hammers on enchanted metal and the chatter of adventurers planning their next quests.""" } diff --git a/lib/main_menu.rb b/lib/main_menu.rb new file mode 100644 index 0000000..e738b35 --- /dev/null +++ b/lib/main_menu.rb @@ -0,0 +1,204 @@ +require './lib/text_style.rb' +require './lib/slow_text.rb' +require './lib/character.rb' +require './lib/save_system.rb' +require './lib/random_name_class.rb' + +module MainMenu + + def self.show_main_menu + clear_screen + show_title + + menu_choice = SaveSystem.show_save_menu + + if menu_choice == :new_game + create_new_character + elsif menu_choice.is_a?(Hash) && menu_choice[:type] == :load_game + load_existing_character(menu_choice[:filename]) + else + puts "Something went wrong!".red + exit + end + end + + def self.clear_screen + system("clear") || system("cls") + end + + def self.show_title + puts <<-'BIG_TEXT' +__ __ _ _ ____ _ +\ \ / /__| | ___ ___ _ __ ___ ___ | |_ ___ | _ \ _ _| |__ _ _ + \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | __/ _ \ | |_) | | | | '_ \| | | | + \ V V / __/ | (_| (_) | | | | | | __/ | || (_) | | _ <| |_| | |_) | |_| | + \_/\_/ \___|_|\___\___/|_| |_| |_|\___| \__\___/ |_| \_\\__,_|_.__/ \__, | + |___/ + _ ___ _ _ + | |/ (_)_ __ __ _ __| | ___ _ __ ___ | | + | ' /| | '_ \ / _` |/ _` |/ _ \| '_ ` _ \| | + | . \| | | | | (_| | (_| | (_) | | | | | |_| + |_|\_\_|_| |_|\__, |\__,_|\___/|_| |_| |_(_) + |___/ +BIG_TEXT + + puts + puts + slow_text do + "Welcome to Ruby Kingdom - A mystical realm where code and magic intertwine!".cyan + end + + slow_text do + "Find the legendary Ruby Castle and claim your destiny...".green + end + puts + puts + sleep 1 + end + + def self.create_new_character + puts "\n=== CHARACTER CREATION ===".cyan.bold + puts + + # Get character name + slow_text(0.03) do + "What will your name be, brave adventurer?" + end + print "> ".green + character_name = gets.chomp.strip + + while character_name.empty? + puts "You must enter a name!".red + print "> ".green + character_name = gets.chomp.strip + end + + puts + sleep 1 + puts "#{character_name}... an interesting choice.".yellow.bold + puts + sleep 1 + slow_text(0.03) do + "Very well, #{character_name}. Choose your path wisely." + end + + sleep 2 + + # Character class selection + character_class_check = false + class_input = nil + + while character_class_check != true + puts + slow_text do + <<-'CLASS_TEXT' + +Pick your class: + 1. Warrior - Master of blade and battle + 2. Mage - Wielder of arcane mysteries + 3. Programmer - Hacker of reality's code + +CLASS_TEXT + end + + print "> ".green + class_input = gets.chomp + puts + + sleep 1 + + if Character::CHARACTER_CLASSES.include?(class_input.downcase.capitalize()) + character_class_check = true + class_input = class_input.downcase.capitalize() + elsif class_input.to_i == 1 + slow_text(0.03) do + "A warrior's path... steel and courage shall be your tools." + end + class_input = Character::CHARACTER_CLASSES[0] + character_class_check = true + elsif class_input.to_i == 2 + slow_text(0.03) do + "The way of magic... reality bends to your will." + end + class_input = Character::CHARACTER_CLASSES[1] + character_class_check = true + elsif class_input.to_i == 3 + slow_text(0.03) do + "A programmer... you see the world as others cannot." + end + slow_text(0.03) do + "The very fabric of Ruby Kingdom is code - and you can rewrite it." + end + class_input = Character::CHARACTER_CLASSES[2] + character_class_check = true + else + slow_text(0.03) do + "That path does not exist in Ruby Kingdom. Choose again.".red + end + character_class_check = false + end + end + + puts + sleep 2 + + # Create character instance + $current_character = Character.new + $current_character.set_name(character_name) + $current_character.set_class(class_input) + + puts + slow_text(0.03) do + "Welcome to Ruby Kingdom, #{$current_character.get_name} the #{$current_character.get_class}!".green.bold + end + + puts + sleep 1 + + show_character_intro + end + + def self.load_existing_character(save_filename) + character = SaveSystem.load_game(save_filename) + + if character + $current_character = character + puts + slow_text(0.03) do + "Welcome back, #{character.get_name} the #{character.get_class}!".green.bold + end + puts "Level #{character.get_level} | HP: #{character.get_hp} | Gold: #{character.get_gold}".yellow + puts + sleep 2 + else + puts "Failed to load character. Starting new game instead.".red + sleep 2 + create_new_character + end + end + + def self.show_character_intro + puts + slow_text(0.03) do + "You stand at the edge of Ruby Kingdom, a land where ancient magic" + end + slow_text(0.03) do + "flows through crystalline formations and mystical creatures roam freely." + end + puts + slow_text(0.03) do + "Legends speak of the Ruby Castle, hidden somewhere in these lands," + end + slow_text(0.03) do + "where the Heart of Ruby - source of all magic - awaits a worthy champion." + end + puts + sleep 2 + slow_text(0.03) do + "Your journey begins now...".green.bold + end + puts + sleep 3 + end + +end \ No newline at end of file diff --git a/lib/map.rb b/lib/map.rb index 5d7c645..e9b9f8e 100644 --- a/lib/map.rb +++ b/lib/map.rb @@ -1,4 +1,5 @@ require "./lib/location.rb" +require "./lib/quest_system.rb" class Map def initialize @@ -15,6 +16,7 @@ def initialize @map_grid = Array.new(7) { Array.new(4, "") } @map_cords = [1, 2, 3, 4, 5, 6, 7, 8, 9] @character_location = 9 + @visited_locations = [] @locations = { "1" => Location.new, @@ -50,7 +52,7 @@ def set_character_location(locaton) clear_location @map_grid[1][1] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["1"].roll_enemy print_map run_location(1) @@ -58,7 +60,7 @@ def set_character_location(locaton) clear_location @map_grid[1][2] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["2"].roll_enemy print_map run_location(2) @@ -66,7 +68,7 @@ def set_character_location(locaton) clear_location @map_grid[1][4] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["3"].roll_enemy print_map run_location(3) @@ -74,7 +76,7 @@ def set_character_location(locaton) clear_location @map_grid[3][1] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["4"].roll_enemy print_map run_location(4) @@ -82,7 +84,7 @@ def set_character_location(locaton) clear_location @map_grid[3][2] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["5"].roll_enemy print_map run_location(5) @@ -90,7 +92,7 @@ def set_character_location(locaton) clear_location @map_grid[3][4] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["6"].roll_enemy print_map run_location(6) @@ -98,7 +100,7 @@ def set_character_location(locaton) clear_location @map_grid[5][1] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["7"].roll_enemy print_map run_location(7) @@ -106,7 +108,7 @@ def set_character_location(locaton) clear_location @map_grid[5][2] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["8"].roll_enemy print_map run_location(8) @@ -114,7 +116,7 @@ def set_character_location(locaton) clear_location @map_grid[5][4] = " X " @character_location = locaton - $current_character.location = locaton + $current_character.set_location(locaton) @locations["9"].roll_enemy print_map run_location(9) @@ -157,6 +159,17 @@ def move end def run_location(cord) + # Track visited locations for quests + unless @visited_locations.include?(cord) + @visited_locations << cord + QuestSystem.update_quest_progress(:location_visited, "locations") + + # Special quest progress for castle + if @locations["#{cord}"].castle? == true + QuestSystem.update_quest_progress(:location_visited, "castle") + end + end + @locations["#{cord}"].run end diff --git a/lib/menu.rb b/lib/menu.rb index a57bef0..24e8428 100644 --- a/lib/menu.rb +++ b/lib/menu.rb @@ -1,12 +1,12 @@ require "./lib/location.rb" require "./lib/text_style.rb" - +require "./lib/save_system.rb" +require "./lib/quest_system.rb" module Menu @@location = nil @@input_tester = false - def self.run(location) @@input_tester = false @@location = location @@ -17,61 +17,69 @@ def self.run(location) if location.enemy_check puts "2. Fight" puts "3. Check Inventory" + puts "4. Quest Log" + puts "5. Save Game" elsif location.shop == true puts "2. Shop" puts "3. Check Inventory" + puts "4. Quest Log" + puts "5. Save Game" else puts "2. Check Inventory" + puts "3. Quest Log" + puts "4. Save Game" end puts print "> ".green user_selection = gets.chomp + + # Handle save command + if user_selection.downcase == 'save' + save_game + next + end + user_selection = test_input(user_selection, location) if @@input_tester == false puts "We'll keep trying this until you get it right!".yellow.italic end end - if user_selection == 1 - move - elsif user_selection == 2 && location.enemy_check == true - fight - elsif user_selection == 2 && location.shop == true - shop - elsif user_selection == 2 || user_selection == 3 - check_inventory + case user_selection + when 1 + move + when 2 + if location.enemy_check == true + fight + elsif location.shop == true + shop + else + check_inventory + end + when 3 + if location.enemy_check == true || location.shop == true + check_inventory + else + quest_log + end + when 4 + if location.enemy_check == true || location.shop == true + quest_log + else + save_game + end + when 5 + save_game end end def self.test_input(input, location) - if input.to_i > 3 || input.to_i < 1 + max_options = location.enemy_check || location.shop ? 5 : 4 + + if input.to_i > max_options || input.to_i < 1 @@input_tester = false return '' - # end - - # if input.to_i == 0 - # case input.downcase - # when "move" - # @@input_tester = true - # return 1 - # when "shop" && location.shop == true - # @@input_tester = true - # return 2 - # when "fight" && location.enemy_check == true - # @@input_tester = true - # return 2 - # when "check inventory", "inventory" - # if location.shop == false && location.enemy_check == false - # @@input_tester = true - # return 2 - # else - # @@input_tester = true - # return 3 - # end - # else - # @@input_tester = false - # end else @@input_tester = true return input.to_i @@ -87,11 +95,164 @@ def self.fight end def self.check_inventory - puts "inventory" + puts "\n=== INVENTORY ===".cyan.bold + inventory = $current_character.get_inventory + + if inventory.empty? + puts "Your inventory is empty.".yellow + else + puts "Items:".green + inventory.each_with_index do |item, index| + equipped = (item == $current_character.get_weapon) ? " (equipped)".green : "" + puts " #{index + 1}. #{item}#{equipped}" + end + end + + puts "\nCharacter Stats:".cyan + puts " Level: #{$current_character.get_level}" + puts " HP: #{$current_character.get_hp}" + puts " Attack: #{$current_character.get_atk}" + puts " Gold: #{$current_character.get_gold}" + puts " EXP: #{$current_character.instance_variable_get(:@exp_points)}/#{$current_character.instance_variable_get(:@next_level_exp)}" + puts + + puts "Press Enter to continue...".gray + gets end def self.shop - puts "shop" + puts "=== THE RUBY KINGDOM BLACKSMITH ===".yellow.bold + puts + puts "\"Welcome, brave #{$current_character.get_class.downcase}!\" booms the blacksmith," + puts "his hammer paused mid-strike over a glowing ruby-infused blade." + puts "\"I craft the finest weapons in all the realm!\"" + puts + puts "\"The magic of the Ruby Kingdom flows through my forge.\"" + puts "\"Each weapon I create is imbued with the land's power!\"" + puts + puts "Available Items:".green.bold + puts "1. Ruby-Touched Blade - 75 gold (+3 Attack) ⚔️" + puts "2. Mystic Steel Sword - 150 gold (+5 Attack) ⚔️" + puts "3. Legendary Ruby Weapon - 300 gold (+8 Attack) ⚔️" + puts "4. Greater Health Potion - 40 gold (Restore 50 HP) 🧪" + puts "5. Magic Shield Charm - 100 gold (+20 Max HP) 🛡️" + puts "6. Ruby Dust - 200 gold (+1 All Stats) ✨" + puts "7. Leave" + puts + puts "Your gold: #{$current_character.get_gold} 💰".yellow + print "> ".green + + choice = gets.chomp.to_i + + case choice + when 1 + buy_weapon("Ruby-Touched Blade", 75, 3) + when 2 + buy_weapon("Mystic Steel Sword", 150, 5) + when 3 + buy_weapon("Legendary Ruby Weapon", 300, 8) + when 4 + buy_potion(40, 50) + when 5 + buy_shield_charm(100, 20) + when 6 + buy_ruby_dust(200) + when 7 + puts "\"May your blade stay sharp and your armor strong!\" the blacksmith calls.".yellow + puts "\"Return when you need the finest equipment Ruby Kingdom has to offer!\"" + else + puts "The blacksmith raises an eyebrow. \"I don't understand, friend.\"".yellow + end + end + + def self.buy_weapon(item_name, cost, attack_bonus) + if $current_character.get_gold >= cost + $current_character.set_gold(cost, false) + old_weapon = $current_character.get_weapon + $current_character.add_to_inventory(item_name) + $current_character.change_weapon(item_name) + + # Update attack with bonus + current_atk = $current_character.get_atk + $current_character.instance_variable_set(:@atk, current_atk + attack_bonus) + + puts "\"An excellent choice! Your #{old_weapon} pales in comparison!\"".yellow + puts "\"That #{item_name} will serve you well in your quest for the Ruby Castle!\"".yellow + puts "Attack increased by #{attack_bonus}! ⚔️".green + else + puts "\"I'm afraid you need more gold for that masterpiece.\"".red + puts "\"Come back when your purse is heavier, #{$current_character.get_name}!\"" + end + end + + def self.buy_potion(cost, heal_amount) + if $current_character.get_gold >= cost + $current_character.set_gold(cost, false) + current_hp = $current_character.get_hp + max_hp = $current_character.instance_variable_get(:@hp_max) + + if current_hp >= max_hp + puts "\"You're already at full health, but I'll give you this for emergencies!\"".yellow + else + $current_character.change_hp(heal_amount, "gain") + actual_heal = [$current_character.get_hp - current_hp, heal_amount].min + puts "\"Drink up! The ruby-infused herbs will restore your strength!\"".yellow + puts "Restored #{actual_heal} HP! 💚".green + end + else + puts "\"That potion costs more than you have, friend.\"".red + end + end + + def self.buy_shield_charm(cost, hp_bonus) + if $current_character.get_gold >= cost + $current_character.set_gold(cost, false) + current_max_hp = $current_character.instance_variable_get(:@hp_max) + new_max_hp = current_max_hp + hp_bonus + $current_character.instance_variable_set(:@hp_max, new_max_hp) + $current_character.change_hp(hp_bonus, "gain") # Also heal current HP + + puts "\"The protective magic flows through you!\"".yellow + puts "\"This ruby-blessed charm will keep you safer in battle!\"".yellow + puts "Maximum HP increased by #{hp_bonus}! 🛡️".green + else + puts "\"Magic charms aren't cheap, adventurer.\"".red + end + end + + def self.buy_ruby_dust(cost) + if $current_character.get_gold >= cost + $current_character.set_gold(cost, false) + + # Increase all stats + $current_character.instance_variable_set(:@atk, $current_character.get_atk + 1) + current_max_hp = $current_character.instance_variable_get(:@hp_max) + $current_character.instance_variable_set(:@hp_max, current_max_hp + 10) + $current_character.change_hp(10, "gain") + + puts "\"Ah, the Ruby Dust! Made from the very essence of our kingdom!\"".yellow + puts "\"Feel the power of the Ruby Heart flowing through you!\"".yellow + puts "All stats increased! Attack +1, Max HP +10! ✨".green + else + puts "\"Ruby Dust is precious and expensive. You need more gold.\"".red + end + end + + def self.save_game + puts "\nEnter a name for your save (or press Enter for auto-name):".cyan + print "> ".green + save_name = gets.chomp.strip + + save_name = nil if save_name.empty? + + saved_filename = SaveSystem.save_game($current_character, save_name) + puts + puts "Press Enter to continue...".gray + gets + end + + def self.quest_log + QuestSystem.show_quest_log end end diff --git a/lib/quest_system.rb b/lib/quest_system.rb new file mode 100644 index 0000000..9f9b0d1 --- /dev/null +++ b/lib/quest_system.rb @@ -0,0 +1,143 @@ +require "./lib/text_style.rb" + +class Quest + attr_accessor :name, :description, :type, :target, :progress, :max_progress, :reward_gold, :reward_exp, :completed + + def initialize(name, description, type, target, max_progress, reward_gold, reward_exp) + @name = name + @description = description + @type = type # :kill, :collect, :explore, :deliver + @target = target + @progress = 0 + @max_progress = max_progress + @reward_gold = reward_gold + @reward_exp = reward_exp + @completed = false + end + + def update_progress(amount = 1) + return if @completed + + @progress += amount + @progress = [@progress, @max_progress].min + + if @progress >= @max_progress && !@completed + complete_quest + end + end + + def complete_quest + @completed = true + puts + puts "🎉 QUEST COMPLETED: #{@name}!".green.bold + puts "Reward: #{@reward_gold} gold, #{@reward_exp} EXP".yellow + end + + def progress_text + "#{@progress}/#{@max_progress}" + end + + def self.starter_quests + [ + Quest.new( + "First Blood", + "Defeat your first enemy in Ruby Kingdom", + :kill, + "any", + 1, + 25, + 15 + ), + Quest.new( + "Explorer", + "Visit 3 different locations", + :explore, + "locations", + 3, + 50, + 25 + ), + Quest.new( + "Collector", + "Find the Ruby Castle", + :explore, + "castle", + 1, + 100, + 50 + ) + ] + end +end + +module QuestSystem + @@active_quests = [] + @@completed_quests = [] + + def self.initialize_starter_quests + @@active_quests = Quest.starter_quests + puts "📜 You have received starter quests! Check your quest log anytime.".cyan + end + + def self.update_quest_progress(type, target = nil) + @@active_quests.each do |quest| + next if quest.completed + + case quest.type + when :kill + if type == :enemy_killed && (quest.target == "any" || quest.target == target) + quest.update_progress + end + when :explore + if type == :location_visited && (quest.target == "locations" || quest.target == target) + quest.update_progress + end + end + end + + # Move completed quests + completed = @@active_quests.select(&:completed) + completed.each do |quest| + @@completed_quests << quest + @@active_quests.delete(quest) + + # Give rewards + $current_character.set_gold(quest.reward_gold, true) + $current_character.add_exp(quest.reward_exp) + end + end + + def self.show_quest_log + puts "\n=== QUEST LOG ===".cyan.bold + puts + + if @@active_quests.empty? + puts "No active quests.".gray + else + puts "Active Quests:".green + @@active_quests.each_with_index do |quest, index| + status = quest.completed ? "[COMPLETE]".green : "[#{quest.progress_text}]".yellow + puts " #{index + 1}. #{quest.name} #{status}" + puts " #{quest.description}".gray + end + end + + puts + + if @@completed_quests.any? + puts "Completed Quests: #{@@completed_quests.length}".green + end + + puts + puts "Press Enter to continue...".gray + gets + end + + def self.active_quests + @@active_quests + end + + def self.completed_quests + @@completed_quests + end +end \ No newline at end of file diff --git a/lib/save_system.rb b/lib/save_system.rb new file mode 100644 index 0000000..c253502 --- /dev/null +++ b/lib/save_system.rb @@ -0,0 +1,214 @@ +require 'json' +require 'fileutils' +require 'time' + +module SaveSystem + SAVE_DIRECTORY = File.join(Dir.pwd, 'saves') + + def self.ensure_save_directory + FileUtils.mkdir_p(SAVE_DIRECTORY) unless Dir.exist?(SAVE_DIRECTORY) + end + + def self.save_game(character, save_name = nil) + ensure_save_directory + + # Generate save name if not provided + if save_name.nil? + timestamp = Time.now.strftime("%Y%m%d_%H%M%S") + save_name = "#{character.get_name}_#{timestamp}" + end + + # Clean save name for filename + clean_name = save_name.gsub(/[^0-9A-Za-z_\-]/, '_') + save_file = File.join(SAVE_DIRECTORY, "#{clean_name}.json") + + save_data = { + name: character.get_name, + class: character.get_class, + hp: character.get_hp, + level: character.get_level, + exp_points: character.instance_variable_get(:@exp_points), + next_level_exp: character.instance_variable_get(:@next_level_exp), + gold: character.get_gold, + inventory: character.get_inventory, + equipped_weapon: character.get_weapon, + location: character.instance_variable_get(:@location), + hp_max: character.instance_variable_get(:@hp_max), + atk: character.get_atk, + alive: character.get_status, + save_timestamp: Time.now.to_s, + save_name: save_name + } + + File.write(save_file, JSON.pretty_generate(save_data)) + puts "Game saved as: #{save_name}".green + return clean_name + end + + def self.load_game(save_filename) + ensure_save_directory + save_file = File.join(SAVE_DIRECTORY, "#{save_filename}.json") + + unless File.exist?(save_file) + puts "Save file not found: #{save_filename}".red + return nil + end + + begin + save_data = JSON.parse(File.read(save_file)) + character = Character.new + + # Restore character data + character.set_name(save_data['name']) + character.set_class(save_data['class']) + character.instance_variable_set(:@hp, save_data['hp']) + character.instance_variable_set(:@level, save_data['level']) + character.instance_variable_set(:@exp_points, save_data['exp_points']) + character.instance_variable_set(:@next_level_exp, save_data['next_level_exp']) + character.instance_variable_set(:@gold, save_data['gold']) + character.instance_variable_set(:@inventory, save_data['inventory']) + character.instance_variable_set(:@equipped_weapon, save_data['equipped_weapon']) + character.instance_variable_set(:@location, save_data['location'] || 5) + character.instance_variable_set(:@hp_max, save_data['hp_max']) + character.instance_variable_set(:@atk, save_data['atk']) + character.instance_variable_set(:@alive, save_data['alive']) + + puts "Game loaded: #{save_data['save_name']}".green + return character + rescue JSON::ParserError, StandardError => e + puts "Error loading save file: #{e.message}".red + return nil + end + end + + def self.list_saves + ensure_save_directory + save_files = Dir.glob(File.join(SAVE_DIRECTORY, "*.json")) + + if save_files.empty? + puts "No save files found.".yellow + return [] + end + + saves = [] + save_files.each_with_index do |file, index| + begin + save_data = JSON.parse(File.read(file)) + filename = File.basename(file, '.json') + saves << { + index: index + 1, + filename: filename, + name: save_data['save_name'] || filename, + character: save_data['name'], + level: save_data['level'], + location: save_data['location'], + timestamp: save_data['save_timestamp'] + } + rescue JSON::ParserError, StandardError + # Skip corrupted save files + next + end + end + + saves + end + + def self.delete_save(save_filename) + ensure_save_directory + save_file = File.join(SAVE_DIRECTORY, "#{save_filename}.json") + + if File.exist?(save_file) + File.delete(save_file) + puts "Save file deleted: #{save_filename}".green + return true + else + puts "Save file not found: #{save_filename}".red + return false + end + end + + def self.show_save_menu + loop do + puts "\n=== RUBY KINGDOM - SAVE MANAGER ===".cyan.bold + puts + + saves = list_saves + + if saves.empty? + puts "No saved games found.".yellow + puts + puts "1. Start New Game" + puts "2. Exit" + puts + print "> ".green + choice = gets.chomp.to_i + + case choice + when 1 + return :new_game + when 2 + puts "Thanks for playing Ruby Kingdom!".cyan + exit + else + puts "Invalid choice!".red + end + else + puts "Saved Games:".green + saves.each do |save| + timestamp = save[:timestamp] ? Time.parse(save[:timestamp]).strftime("%Y-%m-%d %H:%M") : "Unknown" + puts "#{save[:index]}. #{save[:name]} (#{save[:character]}, Level #{save[:level]}) - #{timestamp}" + end + puts + puts "#{saves.length + 1}. Start New Game" + puts "#{saves.length + 2}. Delete Save" + puts "#{saves.length + 3}. Exit" + puts + print "> ".green + choice = gets.chomp.to_i + + if choice >= 1 && choice <= saves.length + selected_save = saves[choice - 1] + return { type: :load_game, filename: selected_save[:filename] } + elsif choice == saves.length + 1 + return :new_game + elsif choice == saves.length + 2 + delete_save_menu(saves) + elsif choice == saves.length + 3 + puts "Thanks for playing Ruby Kingdom!".cyan + exit + else + puts "Invalid choice!".red + end + end + end + end + + private + + def self.delete_save_menu(saves) + puts "\nWhich save would you like to delete?".yellow + saves.each do |save| + puts "#{save[:index]}. #{save[:name]} (#{save[:character]}, Level #{save[:level]})" + end + puts "#{saves.length + 1}. Cancel" + puts + print "> ".green + choice = gets.chomp.to_i + + if choice >= 1 && choice <= saves.length + selected_save = saves[choice - 1] + puts "Are you sure you want to delete '#{selected_save[:name]}'? (y/N)".red + confirm = gets.chomp.downcase + + if confirm == 'y' || confirm == 'yes' + delete_save(selected_save[:filename]) + else + puts "Deletion cancelled.".green + end + elsif choice == saves.length + 1 + # Cancel - return to main menu + else + puts "Invalid choice!".red + end + end +end \ No newline at end of file diff --git a/main.rb b/main.rb index a6903fb..f3df397 100644 --- a/main.rb +++ b/main.rb @@ -1,7 +1,6 @@ require './lib/text_style.rb' - require './lib/intro.rb' - - +intro = Intro.new +intro.run