From 5ae89950fb330fd623634b98a77de259ab174b53 Mon Sep 17 00:00:00 2001 From: David Gay Date: Fri, 28 May 2021 11:26:44 -0400 Subject: Lockbox unlocking, and with it items that start activities when used --- app/controllers/activities_controller.rb | 10 +--- app/controllers/application_controller.rb | 13 ++++++ app/controllers/characters/items_controller.rb | 2 + app/controllers/game_controller.rb | 5 ++ app/models/activity.rb | 28 +---------- app/models/character.rb | 15 +++++- app/models/concerns/has_costs_and_requirements.rb | 33 +++++++++++++ app/views/characters/items/index.html.erb | 4 +- data/activities.yml | 47 +++++++++++++++++++ data/items.yml | 57 +++++++++++++++++++++++ 10 files changed, 173 insertions(+), 41 deletions(-) create mode 100644 app/models/concerns/has_costs_and_requirements.rb diff --git a/app/controllers/activities_controller.rb b/app/controllers/activities_controller.rb index c115abb..8e18ec9 100644 --- a/app/controllers/activities_controller.rb +++ b/app/controllers/activities_controller.rb @@ -5,14 +5,6 @@ class ActivitiesController < ApplicationController def start @activity = Activity.find(params[:id]) - if current_char.start_activity(@activity, queued_actions: params[:queued_actions]) - redirect_to look_path - else - message = "You can't do that." - message += " (requires #{@activity.requirements&.join(", ")})" if @activity.requirements.any? - message += " (costs #{@activity.costs&.join(", ")})" if @activity.costs.any? - flash[:alert] = message - redirect_back(fallback_location: character_path(current_char)) - end + start_activity(@activity) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 94859d1..0fc78a8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,4 +14,17 @@ class ApplicationController < ActionController::Base def roll(sides) rand(sides) + 1 end + + private + def start_activity(activity) + if current_char.start_activity(activity, queued_actions: params[:queued_actions]) + redirect_to look_path + else + message = "You can't do that." + message += " (requires #{activity.requirements&.join(", ")})" if activity.requirements.any? + message += " (costs #{activity.costs&.join(", ")})" if activity.costs.any? + flash[:alert] = message + redirect_back(fallback_location: character_path(current_char)) + end + end end diff --git a/app/controllers/characters/items_controller.rb b/app/controllers/characters/items_controller.rb index e1dfd5c..93dc683 100644 --- a/app/controllers/characters/items_controller.rb +++ b/app/controllers/characters/items_controller.rb @@ -45,6 +45,8 @@ class Characters::ItemsController < ApplicationController heal_or_gain = wounds_change.positive? ? "gain" : "heal" flash[:notice] += " You #{heal_or_gain} #{wounds_change.abs} wound(s)." end + when "activity" + start_activity(Activity.find_by_gid(effect[:gid])) and return else raise "Invalid use effect type string (#{effect[:type]})" end diff --git a/app/controllers/game_controller.rb b/app/controllers/game_controller.rb index 8b92222..bf45973 100644 --- a/app/controllers/game_controller.rb +++ b/app/controllers/game_controller.rb @@ -24,6 +24,11 @@ class GameController < ApplicationController activity.whatnot[:results].each do |result| type = result[:type] case type + when "xp" + skill = Skill.find_by_gid(result[:gid]) + amount = result[:base] + current_char.add_skill_xp(skill, amount) + @results.push({ type: "xp", skill: skill, xp: amount }) when "monster" raise TooManyWoundsError unless current_char.can_fight? next if rand > (result[:chance] || 1) diff --git a/app/models/activity.rb b/app/models/activity.rb index c557752..4a169b4 100644 --- a/app/models/activity.rb +++ b/app/models/activity.rb @@ -1,34 +1,8 @@ class Activity < ApplicationRecord - include HasWhatnot + include HasWhatnot, HasCostsAndRequirements belongs_to :location, optional: true validates :gid, :name, :description, presence: true attribute :innate, :boolean, default: false - - def costs - costs = [] - self.whatnot[:cost]&.each do |cost| - case cost[:type] - when "item" - costs.push "#{cost[:quantity]} #{Item.find_by_gid(cost[:gid]).name}" - end - end - costs - end - - def requirements - requirements = [] - self.whatnot[:requirements]&.each do |req| - case req[:type] - when "skill" - requirements.push "level #{req[:level]} #{Skill.find_by_gid(req[:gid]).name}" - when "hearth_amenity" - requirements.push "level #{req[:level]} #{HearthAmenity.find_by_gid(req[:gid]).name}" - else - raise "Invalid requirement type string (#{req[:type]})" - end - end - requirements - end end diff --git a/app/models/character.rb b/app/models/character.rb index 42f5f10..fda6868 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -60,7 +60,7 @@ class Character < ApplicationRecord activity.whatnot[:cost]&.each do |cost| case cost[:type] when "item" - self.shift_item(cost[:gid], -cost[:quantity]) + self.shift_item(cost[:gid], -(cost[:quantity] || 1)) end end end @@ -72,6 +72,11 @@ class Character < ApplicationRecord ci && ci.quantity >= quantity end + def equipment_with_gid(item) + item = Item.find_by_gid(item) if item.is_a? String + self.equipment.find_by(item: item) + end + def open_slots_for(item) full_slots = self.equipment.map { |e| e.slot } item.equip_slots.reject { |slot| full_slots.include?(slot) } @@ -134,17 +139,23 @@ class Character < ApplicationRecord activity.whatnot[:cost]&.each do |cost| case cost[:type] when "item" - return false unless self.has_item?(cost[:gid], cost[:quantity]) + return false unless self.has_item?(cost[:gid], cost[:quantity] || 1) + else + raise "Invalid cost type string (#{cost[:type]})" end end end unless ignore_requirements activity.whatnot[:requirements]&.each do |requirement| case requirement[:type] + when "equipment" + return false unless self.equipment_with_gid(requirement[:gid]) when "skill" return false unless self.skill_level(requirement[:gid]) >= requirement[:level] when "hearth_amenity" return false unless self.hearth.has_amenity?(requirement[:gid], requirement[:level]) + else + raise "Invalid requirement type string (#{requirement[:type]})" end end end diff --git a/app/models/concerns/has_costs_and_requirements.rb b/app/models/concerns/has_costs_and_requirements.rb new file mode 100644 index 0000000..34ff0f3 --- /dev/null +++ b/app/models/concerns/has_costs_and_requirements.rb @@ -0,0 +1,33 @@ +module HasCostsAndRequirements + extend ActiveSupport::Concern + + included do + def costs + costs = [] + self.whatnot[:cost]&.each do |cost| + case cost[:type] + when "item" + costs.push "#{cost[:quantity]} #{Item.find_by_gid(cost[:gid]).name}" + end + end + costs + end + + def requirements + requirements = [] + self.whatnot[:requirements]&.each do |req| + case req[:type] + when "skill" + requirements.push "level #{req[:level]} #{Skill.find_by_gid(req[:gid]).name}" + when "equipment" + requirements.push "equipped #{Item.find_by_gid(req[:gid]).name}" + when "hearth_amenity" + requirements.push "level #{req[:level]} #{HearthAmenity.find_by_gid(req[:gid]).name}" + else + raise "Invalid requirement type string (#{req[:type]})" + end + end + requirements + end + end +end diff --git a/app/views/characters/items/index.html.erb b/app/views/characters/items/index.html.erb index 14d4b13..f40e666 100644 --- a/app/views/characters/items/index.html.erb +++ b/app/views/characters/items/index.html.erb @@ -13,7 +13,7 @@ <% @character.equipment.order(:slot).each do |eq| %> - <%= eq.slot.to_s %> + <%= eq.slot.to_s.humanize %> <%= eq.item.name %> <%= button_to "Unequip", character_item_unequip_path(slot: eq.slot ) %> @@ -23,8 +23,6 @@ - -

Inventory

diff --git a/data/activities.yml b/data/activities.yml index 59689e8..df93c62 100644 --- a/data/activities.yml +++ b/data/activities.yml @@ -525,3 +525,50 @@ manatrawl_sor_well_depths: xp: - gid: "manatrawl" value: 50 +synthsever_rusted_lockbox: + name: "Unlock Rusted Lockbox" + description: "Unseal the lock on a rusted lockbox." + innate: true + whatnot: + duration: + base: 180 + minimum: 35 + scaling: + - type: "skill" + gid: "synthsever" + scale_value: 1 + requirements: + - type: "equipment" + gid: "iron_lockpicks" + cost: + - type: "item" + gid: "rusted_lockbox" + results: + - type: "item" + chance: 1 + table: + - gid: "vestige" + score: 0 + min_quantity: 20 + max_quantity: 100 + - gid: "red_beryl" + score: 0.30 + - gid: "tourmaline" + score: 0.45 + - gid: "yellow_beryl" + score: 0.60 + titles: + - gid: "beryly" + - gid: "paraiba_tourmaline" + score: 0.70 + - gid: "slate_ring" + score: 0.80 + - gid: "iron_ring" + score: 0.85 + - gid: "quartz_ring" + score: 0.90 + - gid: "granite_ring" + score: 0.95 + - type: "xp" + gid: "synthsever" + base: 25 diff --git a/data/items.yml b/data/items.yml index c153b57..1e48293 100644 --- a/data/items.yml +++ b/data/items.yml @@ -138,6 +138,10 @@ waning_light: rusted_lockbox: name: "rusted lockbox" description: "A small, rusty, metal box with a lock on it." + whatnot: + use_effects: + - type: "activity" + gid: "synthsever_rusted_lockbox" warm_diadem: name: "warm diadem" description: "A thin, blood-colored circlet giving off a faint warmth." @@ -163,3 +167,56 @@ grinpad_trophy: lesser_trodgeathomp_trophy: name: "lesser trodgeathomp trophy" description: "A trophy from a lesser trodgeathomp." +slate_ring: + name: "slate ring" + description: "A brittle ring made of slate. It's flat, inside and out." + whatnot: + equip_slots: + - "left_ring" + - "right_ring" + equip_effects: + - type: "stat_change" + gid: "accuracy" + modifier: 1 +iron_ring: + name: "iron ring" + description: "A strong, iron ring." + whatnot: + equip_slots: + - "left_ring" + - "right_ring" + equip_effects: + - type: "stat_change" + gid: "power" + modifier: 1 +quartz_ring: + name: "quartz ring" + description: "A small ring, strangely made entirely of quartz." + whatnot: + equip_slots: + - "left_ring" + - "right_ring" + equip_effects: + - type: "stat_change" + gid: "evasion" + modifier: 1 +granite_ring: + name: "granite ring" + description: "A heavy ring made of granite." + whatnot: + equip_slots: + - "left_ring" + - "right_ring" + equip_effects: + - type: "stat_change" + gid: "block" + modifier: 1 +enzon_seed: + name: "enzon seed" + description: "The seed of an enzon plant." +iron_lockpicks: + name: "iron lockpicks" + description: "Tools for getting into places other people -- or things -- don't want you to be." + whatnot: + equip_slots: + - "mainhand" -- cgit v1.2.3