Reedo 5 Posted September 17, 2013 (edited) -- Under Development - Near Release -- Reedo's Simple Quest System (RSQS) Version 0.1 (beta) September 16, 2013 By Reedo References None. This is an original script by Reedo. Description RSQS is an easy-to-use quest system. This script is purely about managing quests and is not a quest journal. There are no custom scenes in this script. A quest system itself is about assigning quests, tracking their status, turning them in, and giving rewards. All of this can be done without any kind of quest journal for viewing existing quests. A quest journal is an additional script which can work in conjunction with a quest system. While this script does not include a quest journal at this time, I do intend to write one in the near future. In my estimation, this design (featuring a separation of concerns between the quest system and the quest journal) will result in a cleaner and easier to use quest journal when it is created. This quest system is easily utilized by installing the script, writing a simple "quest loader" script to configure your quests, and then using simple script commands in events to assign and turn in quests. Features Easy-to-use quest system Unlimited quests with unlimited categories Multi-stage quests, unlimited stages per quest (minimum one) Unlimited number of requirements per stage -- party has certain number of items in inventory -- collect specified number of virtual item drops from battle -- kill specified number of certain enemy -- specified switch is set or not set -- specified variable equals the given value Unlimited number of rewards per stage -- award gold -- award experience -- award items -- award armor -- award weapons Automatic quest updates at end of battle Simple event script command interface using $game_reedo_quests assign quests from an event provide quest status feedback from an event turn in a quest from an event Quest configuration via easy-to-write secondary script Virtual Items A virtual item is one that does not exist in the database. It is not a real game item. Virtual items are dropped by monsters after battle and while a quest tracks the number of virtual items received, there are never any actual items in the player's inventory. This makes it very easy to collect items for quest turn-in purposes only, without having to create anything in the database ahead of time. When you create a new virtual item, in addition to giving it a name, you will also assign the enemy ID and drop chance for each enemy that can drop the virtual item after a battle. Virtual items are awarded after a battle, along with any other normal enemy drop items. Known Bugs None at this time, however, this is a beta script and is not fully tested. Please report any bugs found. Requirements Requires separate configuration script to setup quests. Requires on-map events and or common events to manage quests. Installation Plug-and-Play* (see requirements) Just insert a new script directly under Materials, name it RSQS, and paste in the script code. Configuration After inserting the main script, insert a second script beneath RSQS and name it ReedoQuestManager (this name isn't actually important). This script will be used to load all of your quest definitions. It contains a single module which must be named "ReedoQuestManager" and which must contain the single method "self.load_quests". module ReedoQuestManagerdef self.load_questsendend Within the self.load_quests method you will create and configure instances of Reedo_Quest and supporting objects. Each quest will receive an ID number in the order it is added to the $data_reedo_quests collection, so it is good to add comments to each quest so you can easily recognize the quest ID. A complete ReedoQuestManager example, with comments, follows: module ReedoQuestManager def self.load_quests#01 add a comment to remind yourself of the ID number #ID 0#02 create a new quest instance with the given name and category quest = Reedo_Quest.new("Slimy Balls", "Side Quest")#03 create a new stage instance - every quest needs at least one stage stage = Reedo_Quest_Stage.new#04 optionally, add a short reminder text about the quest;# only shown in game optionally - mostly meant for quest journal add-on,# or for events which show quest status. stage.story_text = "There are too many slimes!\nKill at least 8 and bring\nback 4 Slime Balls."#05 create a requirement which must be met to turn the quest in requirement = Reedo_Quest_Requirement.new#06 configure the requirement by calling any of the following methods: # add_item(itemId, reqCount) - must have specified qty of item in inventory# add_virtual(item, reqCount) - must collect specified qty of virtual items# add_kill(enemyId, reqCount) - must kill specified number of enemy# add_switch(switchId, state) - switch must equal state# add_variable(variableId, value) - variable must equal value requirement.add_kill(1, 8) # kill 8 slimes#06.a virtual items are defined first, then assigned to the requirement vitem = Reedo_Quest_Virtual_Item.new vitem.set_name("Slime Ball") vitem.set_provider(1, 0.5) # slimes have 50% chance to drop "Slime Ball" requirement.add_virtual(vitem, 4) # requires 4 "Slime Ball" virtual items#07 once configured, add requirement to quest stage stage.requirements.push(requirement)#07.a repeat from #5 to add additional requirements#08 create a reward for completing this stage reward = Reedo_Quest_Reward.new#09 configure the reward by calling any of the following methods:# award_gold(value) - give amount of gold# award_exp(value) - reward amount of experience to living party members# award_item(itemId, count) - add count of item to inventory# award_armor(armorId, count) - add count of armor to inventory# award_weapon(weaponId, count) - add count of weapon to inventory reward.award_gold(25) reward.award_exp(20)#10 once configured, add reward to quest stage stage.rewards.push(reward)#10.a repeat from #8 to add additional rewards if needed#11 once configured, add the stage to the quest quest.add_stage(stage)#11.a repeat from #3 to add additional stages if desired#13 once configured, add the quest to the global quest repository $data_reedo_quests.push(quest)#14 repeat from #1 to add additional quests until complete endend # Once all of your quests are defined, you can use simple events in the game# to assign quests to the player, give feed-back to the player on the status# of a quest, and turn a completed quest in.## A basic event page for a quest giver and turn in might look like:#mailto:#@>Conditional Branch: Script: $game_reedo_quests.contains?(0)# @>Conditional Branch: Script: $game_reedo_quests.get_quest(0).turn_in# @> (show text to tell any story that goes along with finsihing the quest)# @>Control Self Switch: A=ON (disable the event)# : Else# @> (show text to tell the player that they aren't finished yet)# : Branch End#: Else# @> (show text to offer the player the quest)# @>Script: $game_reedo_quests.assign_quest(0)#: Branch End Event Screen Shot Here is an example of an event which gives a quest, provides quest status, and turns in the quest when complete. Note the simple script commands used to branch the event to first either assign the quest or update it and then to either thank the player for finishing the quest or provide them with their status so far. Compatibility Should be compatible with most other scripts.Modifies DataManager and BattleManager, but maintains existing method implementations on overwritten methods. All other classes are original. Script Here is the complete RSQS script: ################################################################################# RSQS - Reedo's Simple Quest System## Version 0.1 (beta)## September 16, 2013## By Reedo################################################################################# REFERENCES#### None. This is an original script by Reedo.################################################################################# FEATURES#### + Easy-to-use quest system## + Unlimited quests with unlimited categories## + Multi-stage quests, unlimited stages per quest (minimum one)## + Unlimited number of requirements per stage## - Party has certain number of items in inventory## - Collect specified number of virtual item drops from battle## - Kill specified number of certain enemy## - Specified switch is set or not set## - Specified variable equals the given value## + Unlimited number of rewards per stage## - award gold## - award experience## - award items## - award armor## - award weapons## + Automatic quest updates at end of battle## + Simple event script command interface using $game_reedo_quests## - assign quests from an event## - provide quest status feedback from an event## - turn in a quest from an event## + Quest configuration via easy-to-write secondary script################################################################################### COMPATIBILITY#### Should be compatible with most other scripts.#### OVERWRITES (0*)## Modifies DataManager and BattleManager, but maintains existing## method implementations on overwritten methods.################################################################################# REQUIREMENTS#### Requires seperate configuration script to setup quests.## Requires on-map events and or common events to manage quests.################################################################################# INSTALLATION#### Plug-and-play*(see requirements)#### Insert below Materials, above other add-on scripts.################################################################################# RIGHTS & RESTRICTIONS#### As with most Reedo scripts, this script is free to re-use, as-is,## in personal, educational, and commercial RPGVX Ace development projects,## providing that: this script is credited in writing displayed readily## to the user of the final compiled code assembly.#### Reedo retains all rights of intellect and ownership.## You forego all rights of warranty by utilizing this script.############################################################################### ################################################################################# USER OPTIONS###############################################################################module RSQS STAGE_COMPLETE_MESSAGE_FORMAT = "Stage Complete: %s" STAGE_WORKING_MESSAGE_FORMAT = "You are still working on %s." STAGE_WORKING_USE_STORY = true QUEST_ITEM_UPDATE_MESSAGE_FORMAT = "Found Quest Item: %s" QUEST_REQUIREMENT_MET_MESSAGE_FORMAT = "You've met the requirements for: %s" QUEST_COMPLETE_ME_NAME = "fanfare1" QUEST_COMPLETE_ME_PITCH = 100 QUEST_COMPLETE_ME_VOLUME = 100end################################################################################# MAIN SCRIPT################################################################################# EDITS BEYOND THIS POINT ARE AT YOUR OWN RISK!!!###############################################################################module RSQSDataManager def RSQSDataManager.included(mod) @m_load_normal_database = mod.method(:load_normal_database) @m_create_game_objects = mod.method(:create_game_objects) @m_make_save_contents = mod.method(:make_save_contents) @m_extract_save_contents = mod.method(:extract_save_contents) end def get_load_normal_database @m_load_normal_database end def get_create_game_objects @m_create_game_objects end def get_make_save_contents @m_make_save_contents end def get_extract_save_contents @m_extract_save_contents end module_function :get_load_normal_database module_function :get_create_game_objects module_function :get_make_save_contents module_function :get_extract_save_contentsend module RSQSBattleManager def RSQSBattleManager.included(mod) @m_gain_drop_items = mod.method(:gain_drop_items) end def get_gain_drop_items @m_gain_drop_items end module_function :get_gain_drop_itemsend module DataManager include RSQSDataManager def self.load_normal_database RSQSDataManager.get_load_normal_database[] begin $data_reedo_quests = load_data("Data/ReedoQuestData.rvdata2") rescue $data_reedo_quests = [] end end def self.create_game_objects RSQSDataManager.get_create_game_objects[] $game_reedo_quests = Reedo_Quests.new begin qm = ReedoQuestManager rescue qm = nil end qm.load_quests if qm end def self.make_save_contents contents = RSQSDataManager.get_make_save_contents[] contents[:reedo_quests] = $game_reedo_quests contents end def self.extract_save_contents(contents) RSQSDataManager.get_extract_save_contents[contents] $game_reedo_quests = contents[:reedo_quests] $game_reedo_quests = Reedo_Quests.new if !$game_reedo_quests endend module BattleManager include RSQSBattleManager def self.gain_drop_items reedo_gain_quest_updates RSQSBattleManager.get_gain_drop_items[] end def self.reedo_gain_quest_updates $game_troop.dead_members.each do |enemy| $game_reedo_quests.active_quests.each do |quest| if quest.current_stage if !quest.current_stage.complete? quest.current_stage.requirements.each do |requirement| requirement.kills.each_key do |enemyid| requirement.kill_count[enemyid] += 1 if enemyid == enemy.enemy_id end requirement.virtual.each_key do |item| if item.providers.keys.include?(enemy.enemy_id) if rand(0) <= item.providers[enemy.enemy_id] requirement.virtual_count[item] += 1 $game_message.add(sprintf(RSQS::QUEST_ITEM_UPDATE_MESSAGE_FORMAT, item.name)) end end end end if quest.current_stage.complete? $game_message.add(sprintf(RSQS::QUEST_REQUIREMENT_MET_MESSAGE_FORMAT, quest.current_stage.name)) end end end end end endend class Reedo_Quest_Virtual_Item attr_reader :name # name of virtual item attr_reader :providers # hash of enemy ID and drop chance def initialize @name = "" @providers = {} end def set_name(itemName) @name = itemName end def add_provider(enemyId, chance) @providers[enemyId] = chance endend class Reedo_Quest_Requirement attr_reader :items # hash of item ID and required count attr_reader :virtual # hash of virtual item and required count attr_reader :kills # hash of enemy ID and required count attr_reader :switches # hash of switch id and state flag attr_reader :variables # hash of variable name and value attr_reader :virtual_count # hash of virtual item and current count attr_reader :kill_count # hash of enemy ID and current count def initialize @items = {} @virtual = {} @kills = {} @switches = {} @variables = {} @virtual_count = {} @kill_count = {} end def add_item(itemId, reqCount) @items[itemId] = reqCount end def add_virtual(item, reqCount) @virtual[item] = reqCount @virtual_count[item] = 0 end def add_kill(enemyId, reqCount) @kills[enemyId] = reqCount @kill_count[enemyId] = 0 end def add_switch(switchId, state) @switches[switchId] = state end def add_variable(variableId, value) @variables[variableId] = value end def kills_left(enemyId) @kills[enemyId] - @kill_count[enemyId] end def virtual_left @virtual[item] - @virtual_count[item] end def complete? @items.each do |key, value| return false if $game_party.item_number($data_items[key]) < value end @virtual.each do |key, value| return false if @virtual_count[key] < value end @kills.each do |key, value| return false if @kill_count[key] < value end @switches.each do |key, value| return false if !$game_switches[key] == value end @variables.each do |key, value| return false if !$game_variables[key] == value end return true endend class Reedo_Quest_Reward attr_reader :gold # amount of gold rewarded attr_reader :exp # amount of experience rewarded attr_reader :items # hash of reward item id and count attr_reader :armors # hash of reward armor id and count attr_reader :weapons # hash of reward weapon id and count def initialize @gold = 0 @exp = 0 @items = {} @armors = {} @weapons = {} end def award_gold(value) @gold = value end def award_exp(value) @exp = value end def award_item(itemId, count) @items[itemId] = count end def award_armor(armorId, count) @armors[armorId] = count end def award_weapon(weaponId, count) @weapons[weaponId] = cout endend class Reedo_Quest_Stage #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_reader :quest # the quest the stage belongs to attr_accessor :stage_number # order of stage in quest line attr_accessor :stage_name # name of the stage (optional) attr_reader :requirements # array of requirements to complete stage attr_reader :rewards # array of rewards for completing stage attr_accessor :story_text # message to display def initialize @quest = nil @stage_number = 0 @stage_name = nil @requirements = [] @rewards = [] @story_text = "" end def complete? @requirements.each do |requirement| return false if !requirement.complete? end return true end def name return @stage_name if @stage_name and @stage_name.size > 0 return @quest.quest_name if @quest and @quest.quest_name and @quest.quest_name.size > 0 return "(???)" end def set_story(text) story_text = text end def set_owner(ownerQuest) @quest = ownerQuest endend class Reedo_Quest #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_reader :category # quest type category name (unique id) attr_reader :quest_name # name of the quest (unique id) attr_reader :description # brief description of quest attr_reader :stages # array of stages attr_reader :stage_index # index of active quest stage def initialize @category = "Quest" @name = "" @description = "" @stages = [] @stage_index = 0 end def initialize(name, cat) @category = cat @quest_name = name @description = "" @stages = [] @stage_index = 0 end def add_stage(stage) stage.set_owner(self) @stages.push(stage) end def set_description(text) @description = text end def assign_rewards if current_stage current_stage.rewards.each do |reward| if reward.gold > 0 $game_party.gain_gold(reward.gold) msg = sprintf(Vocab::ObtainGold, reward.gold) $game_message.add('\.' + msg) end if reward.exp > 0 $game_party.alive_members.each do |member| member.gain_exp(reward.exp) end msg = sprintf(Vocab::ObtainExp, reward.exp) $game_message.add('\.' + msg) end reward.items.each_key do |itemId| item = $data_items[itemId] $game_party.gain_item(item, reward.items[itemId]) $game_message.add(sprintf(Vocab::ObtainItem, item.name)) end reward.armors.each_key do |itemId| item = $data_armors[itemId] $game_party.gain_item(item, reward.armors[itemId]) $game_message.add(sprintf(Vocab::ObtainItem, item.name)) end reward.weapons.each_key do |itemId| item = $data_weapons[itemId] $game_party.gain_item(item, reward.weapons[itemId]) $game_message.add(sprintf(Vocab::ObtainItem, item.name)) end end end end # determines if quest is completed def complete? @stage_index >= stages.size end # gets the currently active quest stage def current_stage @stages.sort_by{|item| item.stage_number}[stage_index] end # attempts to turn in a quest if complete; returns true/false indicating success def turn_in(showComplete = true, showWorking = false) if !complete? if current_stage.complete? if showComplete $game_reedo_quests.play_quest_complete_me msg = sprintf(RSQS::STAGE_COMPLETE_MESSAGE_FORMAT, current_stage.name) $game_message.add('\.' + msg) end assign_rewards @stage_index += 1 return true end if showWorking if RSQS::STAGE_WORKING_USE_STORY msg = sprintf(current_stage.story_text, current_stage.name) $game_message.add('\.' + msg) else msg = sprintf(RSQS::STAGE_WORKING_MESSAGE_FORMAT, current_stage.name) $game_message.add('\.' + msg) end end end return false endend class Reedo_Quests def initialize @quests = [] @quest_ids = [] @quest_complete_me = RPG::ME.new(RSQS::QUEST_COMPLETE_ME_NAME, RSQS::QUEST_COMPLETE_ME_VOLUME, RSQS::QUEST_COMPLETE_ME_PITCH) end def active_quests @quests.select {|quest| !quest.complete? } end def assign_quest(questId) @quests.push($data_reedo_quests[questId]) @quest_ids.push(questId) end def contains?(questId) @quest_ids.include?(questId) end def get_quest(questId) @quests[@quest_ids.index(questId)] end def play_quest_complete_me @quest_complete_me.play endend Summary With this script you can have a simple quest system for your game with a variety of quest requirements, including number of monsters killed and collecting virtual quest items, and a variety of quest rewards. The quest system can also readily support a quest journal scene or other add-ons in the future. As always, comments and/or suggestions are welcome. Edited September 24, 2013 by Reedo 1 Share this post Link to post Share on other sites
Reedo 5 Posted September 22, 2013 Please follow current developments for this script at: http://forums.rpgmakerweb.com/index.php?/topic/18205-rsqs-reedos-simple-quest-system-beta/?p=175583 I will update this thread with the final post when the script is complete. Share this post Link to post Share on other sites
Reedo 5 Posted September 24, 2013 Please follow current developments for this script at: http://forums.rpgmakerweb.com/index.php?/topic/18205-rsqs-reedos-simple-quest-system-beta/?p=175583 I will update this thread with the final post when the script is complete. A large update has been made. The initial journal scene is ready for testing and the editor contains minor bug fixes and expanded help content. Share this post Link to post Share on other sites