diff options
-rw-r--r-- | CHANGELOG.md | 19 | ||||
-rw-r--r-- | app/controllers/characters/spells_controller.rb | 4 | ||||
-rw-r--r-- | app/errors/too_many_monster_spawn_combats_error.rb | 2 | ||||
-rw-r--r-- | app/lib/activity_processor.rb | 26 | ||||
-rw-r--r-- | app/models/character.rb | 6 | ||||
-rw-r--r-- | app/models/hearth.rb | 1 | ||||
-rw-r--r-- | app/models/location.rb | 1 | ||||
-rw-r--r-- | app/models/monster_spawn.rb | 8 | ||||
-rw-r--r-- | app/views/application/_results.html.erb | 8 | ||||
-rw-r--r-- | app/views/look/look.html.erb | 4 | ||||
-rw-r--r-- | data/activities/floret.yml | 532 | ||||
-rw-r--r-- | data/activities/general.yml (renamed from data/activities.yml) | 747 | ||||
-rw-r--r-- | data/activities/havencast.yml | 211 | ||||
-rw-r--r-- | data/activities/worldcall.yml | 65 | ||||
-rw-r--r-- | data/items/general.yml (renamed from data/items.yml) | 0 | ||||
-rw-r--r-- | data/locations.yml | 4 | ||||
-rw-r--r-- | db/migrate/20210711195205_add_location_to_hearth.rb | 9 | ||||
-rw-r--r-- | db/schema.rb | 5 | ||||
-rw-r--r-- | db/seeds.rb | 20 |
19 files changed, 912 insertions, 760 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ef753db..873be09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,25 @@ # Changelog All notable changes to this project will be documented in this file. +## [Unreleased] + +### Skills +- Worldcall has been implemented. + - New spells: Hearth Passage, Project Thought + +### Leviathans +- A location can now only have one living leviathan at a time. +- A character can now only hunt up to two different leviathans in a 24 hour period. + +### Activities +- Changed references to "Floret Region" in leviathan hunting activity to just "Floret", as per the rename. + +### Hearth +- Hearths now have locations, like characters do. All existing hearths are now located at Floret. + +### Engine +- Some improvements/tweaks. + ## [0.1.13.3] - 2021-07-08 ### Skills diff --git a/app/controllers/characters/spells_controller.rb b/app/controllers/characters/spells_controller.rb index a0e6913..b98c1c3 100644 --- a/app/controllers/characters/spells_controller.rb +++ b/app/controllers/characters/spells_controller.rb @@ -1,6 +1,8 @@ class Characters::SpellsController < ApplicationController def index - @spell_activities = Activity.where("gid like ?", "havencast_%").where(innate: true).order(:name) + @spell_activities = Activity.where("gid like ?", "havencast_%") + .or(Activity.where("gid like ?", "worldcall_%")) + .where(innate: true).order(:name) # TODO: Don't load into memory @spell_activities = @spell_activities.to_a + current_char.learned_activities .map { |la| la.activity } diff --git a/app/errors/too_many_monster_spawn_combats_error.rb b/app/errors/too_many_monster_spawn_combats_error.rb new file mode 100644 index 0000000..51153c8 --- /dev/null +++ b/app/errors/too_many_monster_spawn_combats_error.rb @@ -0,0 +1,2 @@ +class TooManyMonsterSpawnCombatsError < StandardError +end diff --git a/app/lib/activity_processor.rb b/app/lib/activity_processor.rb index 72aa85d..d14282e 100644 --- a/app/lib/activity_processor.rb +++ b/app/lib/activity_processor.rb @@ -40,14 +40,17 @@ class ActivityProcessor puts "Result: #{result}" handle_xp_result(result) when "monster_spawn" + monster_spawn = MonsterSpawn.where(location: Location.find_by_gid(result[:location])).select(&:alive?).first + raise MonsterSpawnError unless monster_spawn + raise TooManyWoundsError unless @character.can_fight? + unless @character.monster_spawns_attacked_in_past_24_hours.count < 2 || @character.monster_spawns_attacked_in_past_24_hours.include?(monster_spawn) + raise TooManyMonsterSpawnCombatsError + end next if rand > (result[:chance] || 1) @results.push({ type: "br" }) - monster_spawn = MonsterSpawn.where(location: Location.find_by_gid(result[:location])).select(&:alive?).first - raise MonsterSpawnError unless monster_spawn - @results.push({ type: type, monster_spawn: monster_spawn }) resolve_combat_with(monster_spawn) break @@ -111,6 +114,19 @@ class ActivityProcessor end end end + when "hearth_location" + location = @character.hearth&.location || Location.find_by_gid("floret") + @character.update(location: location) + @results.push({ type: type, location: location }) + when "create_monster_spawn" + next if rand > (result[:chance] || 1) + monster = Monster.find_by_gid(result[:gid]) + monster_spawn = MonsterSpawn.new(monster: monster, location: @character.location) + if monster_spawn.save + @results.push({ type: type, monster: monster }) + else + @results.push({ type: "message", body: "A leviathan did not appear since there is already a leviathan at #{@character.location.name}." }) + end else raise "Invalid result type (#{type})" # TODO: Improve this. end @@ -173,6 +189,10 @@ class ActivityProcessor @character.stop_activity @results.replace([{ type: "error", message: "There are no living leviathans here." }]) + rescue TooManyMonsterSpawnCombatsError + @character.stop_activity + @results.replace([{ type: "error", + message: "You're too worn out to hunt any more leviathans right now. You can only hunt two different leviathans in a 24 hour period." }]) end private diff --git a/app/models/character.rb b/app/models/character.rb index f6ddb92..b3d8c25 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -16,6 +16,7 @@ class Character < ApplicationRecord has_many :states has_many :chat_messages has_many :monster_kills + has_many :monster_spawn_combats has_many :bazaar_orders validates :name, presence: true # TODO: Make defaults better. This has to allow nil so the `attribute` default works, and I don't like that. @@ -459,6 +460,11 @@ class Character < ApplicationRecord base end + def monster_spawns_attacked_in_past_24_hours + # TODO: Don't load into memory + monster_spawn_combats.where(created_at: 24.hours.ago..).map { |msc| msc.monster_spawn }.uniq + end + private def create_skills Skill.all.each { |skill| self.character_skills.create(skill: skill, xp: 0) } diff --git a/app/models/hearth.rb b/app/models/hearth.rb index ee00c0c..cbd98dc 100644 --- a/app/models/hearth.rb +++ b/app/models/hearth.rb @@ -1,5 +1,6 @@ class Hearth < ApplicationRecord belongs_to :character + belongs_to :location has_many :built_hearth_amenities has_many :hearth_amenities, through: :built_hearth_amenities has_many :hearth_plantings diff --git a/app/models/location.rb b/app/models/location.rb index 7bd1386..e0aaf9b 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -3,6 +3,7 @@ class Location < ApplicationRecord has_many :activities has_many :characters + has_many :hearths has_many :monster_spawns validates :gid, :name, presence: true end diff --git a/app/models/monster_spawn.rb b/app/models/monster_spawn.rb index 5162cc6..42db98a 100644 --- a/app/models/monster_spawn.rb +++ b/app/models/monster_spawn.rb @@ -7,6 +7,7 @@ class MonsterSpawn < ApplicationRecord after_create :send_chat_message validates :starting_hp, presence: true, numericality: { greater_than_or_equal_to: 1, only_integer: true } + validate :one_living_leviathan_per_location, on: :create def alive? self.remaining_hp > 0 @@ -28,4 +29,11 @@ class MonsterSpawn < ApplicationRecord ChatRoomChannel.broadcast_chat_message(chat_message) end end + + def one_living_leviathan_per_location + # TODO: Don't load into memory + if location.monster_spawns.find { |ms| ms.alive? && ms != self } + errors.add(:chat, "A location can only have one monster spawn at a time.") + end + end end diff --git a/app/views/application/_results.html.erb b/app/views/application/_results.html.erb index a7dc002..71d6992 100644 --- a/app/views/application/_results.html.erb +++ b/app/views/application/_results.html.erb @@ -12,6 +12,12 @@ <% when "hearth_planting" %> <p>You planted <%= link_to result[:hearth_planting].item.name, item_path(result[:hearth_planting].item) %> in the loam.</p> + <% when "hearth_location" %> + <% if current_char.hearth&.location %> + <p>You appear in <%= result[:location].name %>.</p> + <% else %> + <p>Lacking a hearth to return to, you appear in an empty patch of land in <%= result[:location].name %>.</p> + <% end %> <% when "activity" %> <p>You learned how to <%= result[:activity].name %>!</p> <% when "monster" %> @@ -20,6 +26,8 @@ <% when "monster_spawn" %> <p>You found the <%= result[:monster_spawn].monster.name %>!</p> <p class="text-xs italic"><%= result[:monster_spawn].monster.description %></p> + <% when "create_monster_spawn" %> + <p>You've called a <%= result[:monster].name %>!</p> <% when "xp" %> <p class="text-xs">You gained <%= result[:xp] %> <%= result[:skill].name %> XP.</p> <% when "title" %> diff --git a/app/views/look/look.html.erb b/app/views/look/look.html.erb index 2f1074a..ef0f6c4 100644 --- a/app/views/look/look.html.erb +++ b/app/views/look/look.html.erb @@ -3,10 +3,10 @@ <p class="italic"><%= @location.description %></p> </div> +<%# TODO: Don't load into memory %> <% @location.monster_spawns.select(&:alive?).each do |ms| %> <p class="text-yellow-400">A <%= ms.monster.name %> is ravaging this location! (<%= ms.remaining_hp %> HP)</p> - <%# TODO: HACK %> - <% activity = Activity.find_by_gid("beastslay_leviathan_floret") %> + <% activity = Activity.find_by_gid("beastslay_leviathan_#{@location.gid}") %> <%= form_with url: start_activity_path(activity) do |f| %> <%= f.hidden_field :id, value: activity.id %> <%= f.submit "Hunt" %> diff --git a/data/activities/floret.yml b/data/activities/floret.yml new file mode 100644 index 0000000..71b6136 --- /dev/null +++ b/data/activities/floret.yml @@ -0,0 +1,532 @@ +planequarry_floret_mines: + name: "Quarry Floret Mines" + description: "Planequarry at the Floret Mines." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "planequarry" + level: 1 + - type: "equipment" + tag: "pickaxe" + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "planequarry" + scale_value: 0.5 + - type: "stat" + gid: "planequarry_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "stone" + score: 0 + - type: "item" + chance: 1 + table: + - gid: "crude_iron_ore" + score: 0 + xp: + - gid: "planequarry" + value: 5 + - gid: "iron_ore" + score: 0.95 + xp: + - gid: "planequarry" + value: 6 + - gid: "pure_iron_ore" + score: 0.996 + xp: + - gid: "planequarry" + value: 7 + - type: "item" + chance: 0.02 + table: + - gid: "red_beryl" + score: 0 + xp: + - gid: "planequarry" + value: 5 + - gid: "tourmaline" + score: 0.45 + xp: + - gid: "planequarry" + value: 5 + - gid: "yellow_beryl" + score: 0.90 + xp: + - gid: "planequarry" + value: 7 + titles: + - gid: "beryly" + - gid: "paraiba_tourmaline" + score: 0.95 + xp: + - gid: "planequarry" + value: 7 +planequarry_deepshaft: + name: "Quarry Deepshaft" + description: "Descend far below the the Floret Mines into the labyrinth of shafts left behind by the ancients." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "planequarry" + level: 10 + - type: "equipment" + tag: "pickaxe" + duration: + base: 80 + minimum: 35 + scaling: + - type: "skill" + gid: "planequarry" + scale_value: 0.5 + - type: "stat" + gid: "planequarry_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "stone" + score: 0 + - type: "item" + chance: 1 + table: + - gid: "crude_iron_ore" + score: 0 + xp: + - gid: "planequarry" + value: 5 + - gid: "iron_ore" + score: 0.20 + xp: + - gid: "planequarry" + value: 6 + - gid: "pure_iron_ore" + score: 0.90 + xp: + - gid: "planequarry" + value: 7 + - gid: "gaian_ore" + score: 0.995 + xp: + - gid: "planequarry" + value: 9 + - type: "item" + chance: 0.03 + table: + - gid: "red_beryl" + score: 0 + xp: + - gid: "planequarry" + value: 5 + - gid: "tourmaline" + score: 0.45 + xp: + - gid: "planequarry" + value: 5 + - gid: "yellow_beryl" + score: 0.90 + xp: + - gid: "planequarry" + value: 7 + titles: + - gid: "beryly" + - gid: "paraiba_tourmaline" + score: 0.95 + xp: + - gid: "planequarry" + value: 7 +planequarry_brine_trench: + name: "Quarry Brine Trench" + description: "Planequarry in the south Floret brine trench." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "planequarry" + level: 1 + - type: "equipment" + tag: "pickaxe" + duration: + base: 50 + minimum: 25 + scaling: + - type: "skill" + gid: "planequarry" + scale_value: 0.5 + - type: "stat" + gid: "planequarry_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + gid: "salt" + max_quantity: 3 + xp: + - gid: "planequarry" + value: 2 + - type: "item" + chance: 0.0133 + gid: "seas_tear" + xp: + - gid: "planequarry" + value: 5 +beastslay_killing_fields: + name: "Slay in the Killing Fields" + description: "Hunt monsters in the Killing Fields." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "beastslay" + level: 1 + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "beastslay" + scale_value: 0.5 + results: + - type: "monster" + chance: 1 + table: + - gid: "pit_leech" + score: 0 + - gid: "stalk_beast" + score: 0.40 + - gid: "grinpad" + score: 0.70 + - gid: "lesser_trodgeathomp" + score: 0.98 +beastslay_hopegraves: + name: "Slay in the Hopegraves" + description: "Hunt monsters in the Hopegraves." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "beastslay" + level: 1 + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "beastslay" + scale_value: 1 + results: + - type: "monster" + chance: 1 + table: + - gid: "grinpad" + score: 0 + - gid: "bollyrot" + score: 0.45 + - gid: "crypt_writhe" + score: 0.96 +wealdreap_twil_woods: + name: "Reap Twil Woods" + description: "Wealdreap within Twil Woods." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "wealdreap" + level: 1 + - type: "equipment" + tag: "axe" + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "wealdreap" + scale_value: 0.5 + - type: "stat" + gid: "wealdreap_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "wood" + score: 0 + - type: "item" + chance: 1 + table: + - gid: "pluma_moss" + score: 0.10 + xp: + - gid: "wealdreap" + value: 1 + - gid: "burstshroom" + score: 0.40 + xp: + - gid: "wealdreap" + value: 5 + - gid: "aseas_leaf" + score: 0.70 + xp: + - gid: "wealdreap" + value: 5 + - gid: "shrine_hassock" + score: 0.98 + xp: + - gid: "wealdreap" + value: 8 + - gid: "discord_pome" + score: 0.996 + xp: + - gid: "wealdreap" + value: 9 + - type: "item" + chance: 0.02 + table: + - gid: "mudtub_seed" + score: 0 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 5 + - gid: "midoras_seed" + score: 0.45 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 6 + - gid: "templis_seed" + score: 0.90 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 7 +wealdreap_twil_grove: + name: "Reap Twil Grove" + description: "Wealdreap within the hidden woodways of the Twil Woods Grove." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "wealdreap" + level: 10 + - type: "equipment" + tag: "axe" + duration: + base: 90 + minimum: 35 + scaling: + - type: "skill" + gid: "wealdreap" + scale_value: 0.5 + - type: "stat" + gid: "wealdreap_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "laris_strand" + score: 0.10 + xp: + - gid: "wealdreap" + value: 2 + - gid: "woodrun_bloom" + score: 0.40 + xp: + - gid: "wealdreap" + value: 6 + - gid: "last_breath" + score: 0.70 + xp: + - gid: "wealdreap" + value: 6 + - gid: "silver_iris" + score: 0.98 + xp: + - gid: "wealdreap" + value: 9 + - gid: "claritas_flower" + score: 0.996 + xp: + - gid: "wealdreap" + value: 10 + - type: "item" + chance: 0.02 + table: + - gid: "mudtub_seed" + score: 0 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 5 + - gid: "midoras_seed" + score: 0.30 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 6 + - gid: "templis_seed" + score: 0.60 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 7 + - gid: "enzon_seed" + score: 0.90 + max_quantity: 3 + xp: + - gid: "wealdreap" + value: 8 +manatrawl_sor_well: + name: "Trawl Sor Well" + description: "Manatrawl within Sor Well." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "manatrawl" + level: 1 + - type: "equipment" + tag: "aethermesh" + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "manatrawl" + scale_value: 0.5 + - type: "stat" + gid: "manatrawl_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "arcane_dust" + score: 0 + max_quantity: 2 + xp: + - gid: "manatrawl" + value: 2 + - type: "item" + chance: 1 + table: + - gid: "shimmering_essence" + score: 0.934 + xp: + - gid: "manatrawl" + value: 7 + - gid: "wisp_of_the_current" + score: 0.996 + xp: + - gid: "manatrawl" + value: 10 +manatrawl_sor_well_depths: + name: "Trawl Sor Well Depths" + description: "Manatrawl deep within Sor Well." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "manatrawl" + level: 7 + - type: "equipment" + tag: "aethermesh" + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "manatrawl" + scale_value: 0.5 + - type: "stat" + gid: "manatrawl_speed" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "arcane_dust" + score: 0 + max_quantity: 3 + xp: + - gid: "manatrawl" + value: 2 + - type: "item" + chance: 1 + table: + - gid: "shimmering_essence" + score: 0.934 + max_quantity: 2 + xp: + - gid: "manatrawl" + value: 7 + - gid: "wisp_of_the_current" + score: 0.995 + xp: + - gid: "manatrawl" + value: 10 +wildscour_crumbling_ruins: + name: "Scour Crumbling Ruins" + description: "Wildscour within the crumbling ruins." + location: "floret" + whatnot: + requirements: + - type: "skill" + gid: "wildscour" + level: 1 + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "wildscour" + scale_value: 1 + results: + - type: "item" + chance: 1 + table: + - gid: "vestige" + score: 0.35 + max_quantity: 5 + xp: + - gid: "wildscour" + value: 2 + - gid: "aethermesh" + score: 0.50 + xp: + - gid: "wildscour" + value: 2 + - gid: "stone_spade" + score: 0.60 + xp: + - gid: "wildscour" + value: 2 + - gid: "stone_pickaxe" + score: 0.70 + xp: + - gid: "wildscour" + value: 2 + - gid: "stone_axe" + score: 0.80 + xp: + - gid: "wildscour" + value: 2 + - gid: "simple_spellpage" + score: 0.99 + xp: + - gid: "wildscour" + value: 7 + - gid: "disturbing_doodad" + score: 0.998 + xp: + - gid: "wildscour" + value: 10 diff --git a/data/activities.yml b/data/activities/general.yml index 06f385c..e9ed163 100644 --- a/data/activities.yml +++ b/data/activities/general.yml @@ -2236,482 +2236,6 @@ craft_mercuria_potion: xp: - gid: "fluxseethe" value: 38 -planequarry_floret_mines: - name: "Quarry Floret Mines" - description: "Planequarry at the Floret Mines." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "planequarry" - level: 1 - - type: "equipment" - tag: "pickaxe" - duration: - base: 70 - minimum: 35 - scaling: - - type: "skill" - gid: "planequarry" - scale_value: 0.5 - - type: "stat" - gid: "planequarry_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "stone" - score: 0 - - type: "item" - chance: 1 - table: - - gid: "crude_iron_ore" - score: 0 - xp: - - gid: "planequarry" - value: 5 - - gid: "iron_ore" - score: 0.95 - xp: - - gid: "planequarry" - value: 6 - - gid: "pure_iron_ore" - score: 0.996 - xp: - - gid: "planequarry" - value: 7 - - type: "item" - chance: 0.02 - table: - - gid: "red_beryl" - score: 0 - xp: - - gid: "planequarry" - value: 5 - - gid: "tourmaline" - score: 0.45 - xp: - - gid: "planequarry" - value: 5 - - gid: "yellow_beryl" - score: 0.90 - xp: - - gid: "planequarry" - value: 7 - titles: - - gid: "beryly" - - gid: "paraiba_tourmaline" - score: 0.95 - xp: - - gid: "planequarry" - value: 7 -planequarry_deepshaft: - name: "Quarry Deepshaft" - description: "Descend far below the the Floret Mines into the labyrinth of shafts left behind by the ancients." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "planequarry" - level: 10 - - type: "equipment" - tag: "pickaxe" - duration: - base: 80 - minimum: 35 - scaling: - - type: "skill" - gid: "planequarry" - scale_value: 0.5 - - type: "stat" - gid: "planequarry_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "stone" - score: 0 - - type: "item" - chance: 1 - table: - - gid: "crude_iron_ore" - score: 0 - xp: - - gid: "planequarry" - value: 5 - - gid: "iron_ore" - score: 0.20 - xp: - - gid: "planequarry" - value: 6 - - gid: "pure_iron_ore" - score: 0.90 - xp: - - gid: "planequarry" - value: 7 - - gid: "gaian_ore" - score: 0.995 - xp: - - gid: "planequarry" - value: 9 - - type: "item" - chance: 0.03 - table: - - gid: "red_beryl" - score: 0 - xp: - - gid: "planequarry" - value: 5 - - gid: "tourmaline" - score: 0.45 - xp: - - gid: "planequarry" - value: 5 - - gid: "yellow_beryl" - score: 0.90 - xp: - - gid: "planequarry" - value: 7 - titles: - - gid: "beryly" - - gid: "paraiba_tourmaline" - score: 0.95 - xp: - - gid: "planequarry" - value: 7 -planequarry_brine_trench: - name: "Quarry Brine Trench" - description: "Planequarry in the south Floret brine trench." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "planequarry" - level: 1 - - type: "equipment" - tag: "pickaxe" - duration: - base: 50 - minimum: 25 - scaling: - - type: "skill" - gid: "planequarry" - scale_value: 0.5 - - type: "stat" - gid: "planequarry_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - gid: "salt" - max_quantity: 3 - xp: - - gid: "planequarry" - value: 2 - - type: "item" - chance: 0.0133 - gid: "seas_tear" - xp: - - gid: "planequarry" - value: 5 -beastslay_killing_fields: - name: "Slay in the Killing Fields" - description: "Hunt monsters in the Killing Fields." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "beastslay" - level: 1 - duration: - base: 60 - minimum: 35 - scaling: - - type: "skill" - gid: "beastslay" - scale_value: 0.5 - results: - - type: "monster" - chance: 1 - table: - - gid: "pit_leech" - score: 0 - - gid: "stalk_beast" - score: 0.40 - - gid: "grinpad" - score: 0.70 - - gid: "lesser_trodgeathomp" - score: 0.98 -beastslay_hopegraves: - name: "Slay in the Hopegraves" - description: "Hunt monsters in the Hopegraves." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "beastslay" - level: 1 - duration: - base: 70 - minimum: 35 - scaling: - - type: "skill" - gid: "beastslay" - scale_value: 1 - results: - - type: "monster" - chance: 1 - table: - - gid: "grinpad" - score: 0 - - gid: "bollyrot" - score: 0.45 - - gid: "crypt_writhe" - score: 0.96 -wealdreap_twil_woods: - name: "Reap Twil Woods" - description: "Wealdreap within Twil Woods." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "wealdreap" - level: 1 - - type: "equipment" - tag: "axe" - duration: - base: 60 - minimum: 35 - scaling: - - type: "skill" - gid: "wealdreap" - scale_value: 0.5 - - type: "stat" - gid: "wealdreap_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "wood" - score: 0 - - type: "item" - chance: 1 - table: - - gid: "pluma_moss" - score: 0.10 - xp: - - gid: "wealdreap" - value: 1 - - gid: "burstshroom" - score: 0.40 - xp: - - gid: "wealdreap" - value: 5 - - gid: "aseas_leaf" - score: 0.70 - xp: - - gid: "wealdreap" - value: 5 - - gid: "shrine_hassock" - score: 0.98 - xp: - - gid: "wealdreap" - value: 8 - - gid: "discord_pome" - score: 0.996 - xp: - - gid: "wealdreap" - value: 9 - - type: "item" - chance: 0.02 - table: - - gid: "mudtub_seed" - score: 0 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 5 - - gid: "midoras_seed" - score: 0.45 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 6 - - gid: "templis_seed" - score: 0.90 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 7 -wealdreap_twil_grove: - name: "Reap Twil Grove" - description: "Wealdreap within the hidden woodways of the Twil Woods Grove." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "wealdreap" - level: 10 - - type: "equipment" - tag: "axe" - duration: - base: 90 - minimum: 35 - scaling: - - type: "skill" - gid: "wealdreap" - scale_value: 0.5 - - type: "stat" - gid: "wealdreap_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "laris_strand" - score: 0.10 - xp: - - gid: "wealdreap" - value: 2 - - gid: "woodrun_bloom" - score: 0.40 - xp: - - gid: "wealdreap" - value: 6 - - gid: "last_breath" - score: 0.70 - xp: - - gid: "wealdreap" - value: 6 - - gid: "silver_iris" - score: 0.98 - xp: - - gid: "wealdreap" - value: 9 - - gid: "claritas_flower" - score: 0.996 - xp: - - gid: "wealdreap" - value: 10 - - type: "item" - chance: 0.02 - table: - - gid: "mudtub_seed" - score: 0 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 5 - - gid: "midoras_seed" - score: 0.30 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 6 - - gid: "templis_seed" - score: 0.60 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 7 - - gid: "enzon_seed" - score: 0.90 - max_quantity: 3 - xp: - - gid: "wealdreap" - value: 8 -manatrawl_sor_well: - name: "Trawl Sor Well" - description: "Manatrawl within Sor Well." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "manatrawl" - level: 1 - - type: "equipment" - tag: "aethermesh" - duration: - base: 60 - minimum: 35 - scaling: - - type: "skill" - gid: "manatrawl" - scale_value: 0.5 - - type: "stat" - gid: "manatrawl_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "arcane_dust" - score: 0 - max_quantity: 2 - xp: - - gid: "manatrawl" - value: 2 - - type: "item" - chance: 1 - table: - - gid: "shimmering_essence" - score: 0.934 - xp: - - gid: "manatrawl" - value: 7 - - gid: "wisp_of_the_current" - score: 0.996 - xp: - - gid: "manatrawl" - value: 10 -manatrawl_sor_well_depths: - name: "Trawl Sor Well Depths" - description: "Manatrawl deep within Sor Well." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "manatrawl" - level: 7 - - type: "equipment" - tag: "aethermesh" - duration: - base: 70 - minimum: 35 - scaling: - - type: "skill" - gid: "manatrawl" - scale_value: 0.5 - - type: "stat" - gid: "manatrawl_speed" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "arcane_dust" - score: 0 - max_quantity: 3 - xp: - - gid: "manatrawl" - value: 2 - - type: "item" - chance: 1 - table: - - gid: "shimmering_essence" - score: 0.934 - max_quantity: 2 - xp: - - gid: "manatrawl" - value: 7 - - gid: "wisp_of_the_current" - score: 0.995 - xp: - - gid: "manatrawl" - value: 10 synthsever_rusted_lockbox: name: "Unlock Rusted Lockbox" description: "Unseal the lock on a rusted lockbox." @@ -2773,62 +2297,6 @@ open_unlocked_rusted_lockbox: score: 0.90 - gid: "granite_ring" score: 0.95 -wildscour_crumbling_ruins: - name: "Scour Crumbling Ruins" - description: "Wildscour within the crumbling ruins." - location: "floret" - whatnot: - requirements: - - type: "skill" - gid: "wildscour" - level: 1 - duration: - base: 60 - minimum: 35 - scaling: - - type: "skill" - gid: "wildscour" - scale_value: 1 - results: - - type: "item" - chance: 1 - table: - - gid: "vestige" - score: 0.35 - max_quantity: 5 - xp: - - gid: "wildscour" - value: 2 - - gid: "aethermesh" - score: 0.50 - xp: - - gid: "wildscour" - value: 2 - - gid: "stone_spade" - score: 0.60 - xp: - - gid: "wildscour" - value: 2 - - gid: "stone_pickaxe" - score: 0.70 - xp: - - gid: "wildscour" - value: 2 - - gid: "stone_axe" - score: 0.80 - xp: - - gid: "wildscour" - value: 2 - - gid: "simple_spellpage" - score: 0.99 - xp: - - gid: "wildscour" - value: 7 - - gid: "disturbing_doodad" - score: 0.998 - xp: - - gid: "wildscour" - value: 10 craft_gem_dust_from_red_beryl: name: "Crush red beryl" description: "Crush a red beryl into gem dust." @@ -3056,8 +2524,8 @@ craft_dusted_templis: - gid: "spicework" value: 14 beastslay_leviathan_floret: - name: "Hunt a Leviathan in the Floret Region" - description: "You are hunting down a leviathan ravaging the Floret Region." + name: "Hunt a Leviathan in Floret" + description: "You are hunting down a leviathan ravaging Floret." whatnot: requirements: - type: "skill" @@ -3318,214 +2786,3 @@ craft_minor_mana: xp: - gid: "omenbind" value: 16 -havencast_light: - name: "Cast Light" - description: "Risk a little light." - whatnot: - tags: - - "spell" - - "cantrip" - requirements: - - type: "skill" - gid: "havencast" - level: 1 - - type: "stat" - gid: "mana" - value: 1 - duration: - base: 62 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - results: - - type: "condition" - gid: "light" - duration: 3600 # 1 Hour - message: "A ball of light glows before you." - - type: "xp" - gid: "havencast" - base: 2 -havencast_dazzle: - name: "Cast Dazzle" - description: "Cast the Dazzle cantrip." - whatnot: - tags: - - "spell" - - "cantrip" - duration: - base: 62 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - requirements: - - type: "skill" - gid: "havencast" - level: 2 - - type: "stat" - gid: "mana" - value: 1 - results: - - type: "condition" - gid: "dazzle" - duration: 600 # 10 minutes - message: "Sparkling lights distract your enemies." - - type: "xp" - gid: "havencast" - base: 3 -havencast_decipher_simple_magicscript: - name: "Cast Decipher Simple Magicscript" - description: "Cast the Decipher Simple Magicscript cantrip." - whatnot: - tags: - - "spell" - - "cantrip" - duration: - base: 64 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - requirements: - - type: "skill" - gid: "havencast" - level: 3 - - type: "stat" - gid: "mana" - value: 1 - cost: - - type: "item" - gid: "simple_spellpage" - quantity: 1 - results: - - type: "xp" - gid: "havencast" - base: 5 - - type: "activity" - chance: 1 - table: - - gid: "havencast_stinging_rays" - score: 0 - - gid: "havencast_flame_whirl" - score: .50 -havencast_enchant_apprentice_wand: - name: "Cast Enchant Apprentice Wand" - description: "Cast the Enchant Apprentice Wand spell." - whatnot: - tags: - - "spell" - - "cantrip" - duration: - base: 70 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - requirements: - - type: "skill" - gid: "havencast" - level: 5 - - type: "stat" - gid: "mana" - value: 1 - cost: - - type: "item" - gid: "wood" - quantity: 1 - - type: "item" - gid: "arcane_dust" - quantity: 10 - - type: "item" - gid: "shimmering_essence" - quantity: 1 - results: - - type: "item" - gid: "apprentice_wand" - - type: "xp" - gid: "havencast" - base: 8 -havencast_stinging_rays: - name: "Cast Stinging Rays" - description: "Cast the Stinging Rays spell." - innate: false - whatnot: - tags: - - "spell" - duration: - base: 70 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - requirements: - - type: "skill" - gid: "havencast" - level: 5 - - type: "stat" - gid: "mana" - value: 1 - - type: "equipment" - tag: "focus" - results: - - type: "condition" - gid: "stinging_rays" - duration: 600 # 10 minutes - message: "Beams of arcane energy appear in the air around you." - - type: "xp" - gid: "havencast" - base: 7 -havencast_flame_whirl: - name: "Cast Flame Whirl" - description: "Cast the Flame Whirl spell." - innate: false - whatnot: - tags: - - "spell" - duration: - base: 80 - minimum: 35 - scaling: - - type: "skill" - gid: "havencast" - scale_value: 0.5 - - type: "stat" - gid: "havencast_speed" - scale_value: 1 - requirements: - - type: "skill" - gid: "havencast" - level: 10 - - type: "stat" - gid: "mana" - value: 2 - - type: "equipment" - tag: "focus" - results: - - type: "condition" - gid: "flame_whirl" - duration: 600 # 10 minutes - message: "A thin disc of fire encircles you." - - type: "xp" - gid: "havencast" - base: 9 diff --git a/data/activities/havencast.yml b/data/activities/havencast.yml new file mode 100644 index 0000000..ce84d24 --- /dev/null +++ b/data/activities/havencast.yml @@ -0,0 +1,211 @@ +havencast_light: + name: "Cast Light" + description: "Risk a little light." + whatnot: + tags: + - "spell" + - "cantrip" + requirements: + - type: "skill" + gid: "havencast" + level: 1 + - type: "stat" + gid: "mana" + value: 1 + duration: + base: 62 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + results: + - type: "condition" + gid: "light" + duration: 3600 # 1 Hour + message: "A ball of light glows before you." + - type: "xp" + gid: "havencast" + base: 2 +havencast_dazzle: + name: "Cast Dazzle" + description: "Cast the Dazzle cantrip." + whatnot: + tags: + - "spell" + - "cantrip" + duration: + base: 62 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 2 + - type: "stat" + gid: "mana" + value: 1 + results: + - type: "condition" + gid: "dazzle" + duration: 600 # 10 minutes + message: "Sparkling lights distract your enemies." + - type: "xp" + gid: "havencast" + base: 3 +havencast_decipher_simple_magicscript: + name: "Cast Decipher Simple Magicscript" + description: "Cast the Decipher Simple Magicscript cantrip." + whatnot: + tags: + - "spell" + - "cantrip" + duration: + base: 64 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 3 + - type: "stat" + gid: "mana" + value: 1 + cost: + - type: "item" + gid: "simple_spellpage" + quantity: 1 + results: + - type: "xp" + gid: "havencast" + base: 5 + - type: "activity" + chance: 1 + table: + - gid: "havencast_stinging_rays" + score: 0 + - gid: "havencast_flame_whirl" + score: .50 +havencast_enchant_apprentice_wand: + name: "Cast Enchant Apprentice Wand" + description: "Cast the Enchant Apprentice Wand spell." + whatnot: + tags: + - "spell" + - "cantrip" + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 5 + - type: "stat" + gid: "mana" + value: 1 + cost: + - type: "item" + gid: "wood" + quantity: 1 + - type: "item" + gid: "arcane_dust" + quantity: 10 + - type: "item" + gid: "shimmering_essence" + quantity: 1 + results: + - type: "item" + gid: "apprentice_wand" + - type: "xp" + gid: "havencast" + base: 8 +havencast_stinging_rays: + name: "Cast Stinging Rays" + description: "Cast the Stinging Rays spell." + innate: false + whatnot: + tags: + - "spell" + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 5 + - type: "stat" + gid: "mana" + value: 1 + - type: "equipment" + tag: "focus" + results: + - type: "condition" + gid: "stinging_rays" + duration: 600 # 10 minutes + message: "Beams of arcane energy appear in the air around you." + - type: "xp" + gid: "havencast" + base: 7 +havencast_flame_whirl: + name: "Cast Flame Whirl" + description: "Cast the Flame Whirl spell." + innate: false + whatnot: + tags: + - "spell" + duration: + base: 80 + minimum: 35 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 0.5 + - type: "stat" + gid: "havencast_speed" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 10 + - type: "stat" + gid: "mana" + value: 2 + - type: "equipment" + tag: "focus" + results: + - type: "condition" + gid: "flame_whirl" + duration: 600 # 10 minutes + message: "A thin disc of fire encircles you." + - type: "xp" + gid: "havencast" + base: 9 diff --git a/data/activities/worldcall.yml b/data/activities/worldcall.yml new file mode 100644 index 0000000..bec622f --- /dev/null +++ b/data/activities/worldcall.yml @@ -0,0 +1,65 @@ +worldcall_hearth_passage: + name: "Cast Hearth Passage" + description: "Teleport to the location of your hearth." + whatnot: + tags: + - "spell" + - "worldcall" + requirements: + - type: "skill" + gid: "worldcall" + level: 1 + cost: + - type: "item" + gid: "stone" + quantity: 5 + - type: "item" + gid: "wood" + quantity: 5 + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "worldcall" + scale_value: 0.5 + - type: "stat" + gid: "worldcall_speed" + scale_value: 1 + results: + - type: "hearth_location" + - type: "xp" + gid: "worldcall" + base: 4 +worldcall_project_thought: + name: "Cast Project Thought" + description: "Open brief, faint rifts to random places at your current location, possibly attracting a balgoloth." + whatnot: + tags: + - "spell" + - "worldcall" + requirements: + - type: "skill" + gid: "worldcall" + level: 5 + cost: + - type: "item" + gid: "gem_dust" + quantity: 1 + duration: + base: 62 + minimum: 35 + scaling: + - type: "skill" + gid: "worldcall" + scale_value: 0.5 + - type: "stat" + gid: "worldcall_speed" + scale_value: 1 + results: + - type: "create_monster_spawn" + gid: "balgoloth" + chance: 0.04 + - type: "xp" + gid: "worldcall" + base: 6 diff --git a/data/items.yml b/data/items/general.yml index cf475e5..cf475e5 100644 --- a/data/items.yml +++ b/data/items/general.yml diff --git a/data/locations.yml b/data/locations.yml index 00b48c0..2f1b6f8 100644 --- a/data/locations.yml +++ b/data/locations.yml @@ -2,3 +2,7 @@ floret: name: "Floret" description: "A relatively safe haven nestled against the great Sor River." whatnot: +bloodmarch: + name: "Bloodmarch" + description: "Wild lands of treacherous terrain and deadly beasts, far from the safety of Floret." + whatnot: diff --git a/db/migrate/20210711195205_add_location_to_hearth.rb b/db/migrate/20210711195205_add_location_to_hearth.rb new file mode 100644 index 0000000..c8031d6 --- /dev/null +++ b/db/migrate/20210711195205_add_location_to_hearth.rb @@ -0,0 +1,9 @@ +class AddLocationToHearth < ActiveRecord::Migration[6.1] + def change + add_reference :hearths, :location, foreign_key: true + Hearth.all.each do |hearth| + hearth.update(location: Location.find_by_gid("floret")) + end + change_column :hearths, :location_id, :bigint, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 3c6cc28..2263181 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_07_06_000053) do +ActiveRecord::Schema.define(version: 2021_07_11_195205) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -155,7 +155,9 @@ ActiveRecord::Schema.define(version: 2021_07_06_000053) do t.bigint "character_id", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.bigint "location_id", null: false t.index ["character_id"], name: "index_hearths_on_character_id" + t.index ["location_id"], name: "index_hearths_on_location_id" end create_table "item_infixes", force: :cascade do |t| @@ -332,6 +334,7 @@ ActiveRecord::Schema.define(version: 2021_07_06_000053) do add_foreign_key "hearth_plantings", "hearths" add_foreign_key "hearth_plantings", "items" add_foreign_key "hearths", "characters" + add_foreign_key "hearths", "locations" add_foreign_key "item_infixes", "characters" add_foreign_key "item_infixes", "items" add_foreign_key "item_infixes", "skills" diff --git a/db/seeds.rb b/db/seeds.rb index 1e2888a..a513ee1 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -25,9 +25,11 @@ load_data_file("data/skills.yml").map do |gid, hash| skill.update(hash) end -load_data_file("data/items.yml").map do |gid, hash| - item = Item.find_or_create_by(gid: gid) - item.update(hash) +Dir["data/items/*"].each do |file_name| + load_data_file(file_name).map do |gid, hash| + item = Item.find_or_create_by(gid: gid) + item.update(hash) + end end load_data_file("data/locations.yml").map do |gid, hash| @@ -35,11 +37,13 @@ load_data_file("data/locations.yml").map do |gid, hash| location.update(hash) end -load_data_file("data/activities.yml").map do |gid, hash| - activity = Activity.find_or_create_by(gid: gid) - activity.assign_attributes(hash.except(:location)) - activity.location = Location.find_by_gid(hash[:location]) - activity.save +Dir["data/activities/*"].each do |file_name| + load_data_file(file_name).map do |gid, hash| + activity = Activity.find_or_create_by(gid: gid) + activity.assign_attributes(hash.except(:location)) + activity.location = Location.find_by_gid(hash[:location]) + activity.save + end end load_data_file("data/hearth_amenities.yml").map do |gid, hash| |