diff options
-rw-r--r-- | CHANGELOG.md | 22 | ||||
-rw-r--r-- | app/controllers/characters/items_controller.rb | 12 | ||||
-rw-r--r-- | app/controllers/characters/rankings_controller.rb | 2 | ||||
-rw-r--r-- | app/controllers/characters/skills_controller.rb | 15 | ||||
-rw-r--r-- | app/controllers/characters_controller.rb | 15 | ||||
-rw-r--r-- | app/models/character.rb | 6 | ||||
-rw-r--r-- | app/models/character_skill.rb | 16 | ||||
-rw-r--r-- | app/models/item_infix.rb | 13 | ||||
-rw-r--r-- | app/views/application/_navbar.html.erb | 3 | ||||
-rw-r--r-- | app/views/characters/show.html.erb | 25 | ||||
-rw-r--r-- | app/views/characters/skills/index.html.erb | 24 | ||||
-rw-r--r-- | config/routes.rb | 1 | ||||
-rw-r--r-- | data/activities.yml | 262 | ||||
-rw-r--r-- | data/conditions.yml | 14 | ||||
-rw-r--r-- | data/hearth_amenities.yml | 11 | ||||
-rw-r--r-- | data/items.yml | 24 | ||||
-rw-r--r-- | data/skills.yml | 2 | ||||
-rw-r--r-- | db/migrate/20210614004827_create_item_infixes.rb | 11 | ||||
-rw-r--r-- | db/schema.rb | 16 | ||||
-rw-r--r-- | test/fixtures/item_infixes.yml | 11 | ||||
-rw-r--r-- | test/models/item_infix_test.rb | 7 |
21 files changed, 466 insertions, 46 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e3d9d..86a9fc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Changelog All notable changes to this project will be documented in this file. +## [Unreleased] + +### Activities +- Planequarry XP award changes + - Pure iron ore 25 -> 18 + - Gaian ore 50 -> 25 +- Otherforge + - XP award changes + - Purify crude iron ingot 105 -> 60 + - Purify iron ingot 115 -> 70 + - Level requirements changes + - Arcanite longsword 15 -> 17 (setting it to 15 was a programming error) + +### Items +- The first omens: faint hope, fleeting glimpse, bright token, sign of solace + +### Hearth +- New amenity: binding array (level 1, level 2) + +### UI +- Character skills were moved to their own view, which features a new interface with XP bars. + ## [0.1.10.3] - 2021-06-14 ### Fixed diff --git a/app/controllers/characters/items_controller.rb b/app/controllers/characters/items_controller.rb index 470e21c..e38b69a 100644 --- a/app/controllers/characters/items_controller.rb +++ b/app/controllers/characters/items_controller.rb @@ -1,6 +1,7 @@ class Characters::ItemsController < ApplicationController + before_action :set_character, only: :index + def index - @character = Character.find(params[:character_id]) end def equip @@ -66,4 +67,13 @@ class Characters::ItemsController < ApplicationController redirect_to character_items_path(current_char) end end + + private + def set_character + @character = Character.find(params[:character_id]) + unless current_char == @character + flash[:alert] = "You can only look at your own items." + redirect_to character_path(@character) + end + end end diff --git a/app/controllers/characters/rankings_controller.rb b/app/controllers/characters/rankings_controller.rb index bbae9fc..429b487 100644 --- a/app/controllers/characters/rankings_controller.rb +++ b/app/controllers/characters/rankings_controller.rb @@ -6,4 +6,4 @@ class Characters::RankingsController < ApplicationController def index @character = Character.find(params[:character_id]) end -end
\ No newline at end of file +end diff --git a/app/controllers/characters/skills_controller.rb b/app/controllers/characters/skills_controller.rb new file mode 100644 index 0000000..6fcf417 --- /dev/null +++ b/app/controllers/characters/skills_controller.rb @@ -0,0 +1,15 @@ +class Characters::SkillsController < ApplicationController + before_action :set_character, only: :index + + def index + end + + private + def set_character + @character = Character.find(params[:character_id]) + unless current_char == @character + flash[:alert] = "You can only look at your own skills." + redirect_to character_path(@character) + end + end +end diff --git a/app/controllers/characters_controller.rb b/app/controllers/characters_controller.rb index 77e1a94..2eb906b 100644 --- a/app/controllers/characters_controller.rb +++ b/app/controllers/characters_controller.rb @@ -1,8 +1,8 @@ class CharactersController < ApplicationController skip_before_action :redirect_if_no_active_character, only: [:new, :create] + before_action :set_character, only: [:show, :set_combat_styles] def show - @character = Character.find(params[:id]) end def new @@ -22,11 +22,6 @@ class CharactersController < ApplicationController end def set_combat_styles - @character = Character.find(params[:character_id]) - unless @character == current_char - flash[:alert] = "You can't set the combat styles of another character." - redirect_to character_path(@character) and return - end if @character.update(offensive_style: params[:offensive_style], defensive_style: params[:defensive_style]) flash[:notice] = "Changed combat styles to #{@character.offensive_style} and #{@character.defensive_style}." @@ -40,4 +35,12 @@ class CharactersController < ApplicationController def character_params params.require(:character).permit(:name) end + + def set_character + @character = Character.find(params[:id]) + unless current_char == @character + flash[:alert] = "You can only manage your own character." + redirect_to character_path(@character) + end + end end diff --git a/app/models/character.rb b/app/models/character.rb index d386002..03bd510 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -9,6 +9,7 @@ class Character < ApplicationRecord has_many :character_items has_many :learned_activities has_many :items, through: :character_items + has_many :item_infixes has_many :character_skills has_many :conditions, through: :states has_many :states @@ -182,6 +183,11 @@ class Character < ApplicationRecord end end + def max_infixes(skill) + skill = Skill.find_by_gid(skill) if skill.is_a? String + 1 + (skill_level(skill) / 20).floor + end + def add_skill_xp(skill, amount) skill = Skill.find_by_gid(skill) if skill.is_a? String Character.transaction do diff --git a/app/models/character_skill.rb b/app/models/character_skill.rb index 368cc28..406cade 100644 --- a/app/models/character_skill.rb +++ b/app/models/character_skill.rb @@ -39,6 +39,10 @@ class CharacterSkill < ApplicationRecord end end + def self.xp_required_for_level(level) + level <= 120 ? XP_TOTALS_PER_LEVEL[level - 1] : nil + end + def level XP_TOTALS_PER_LEVEL.each_with_index do |total, index| return index if total > self.xp @@ -46,7 +50,7 @@ class CharacterSkill < ApplicationRecord end def total_xp_for_next_level - xp_required_for_level(level + 1) + CharacterSkill.xp_required_for_level(level + 1) end def xp_to_next_level @@ -57,11 +61,13 @@ class CharacterSkill < ApplicationRecord CharacterSkill.top_xp_for(self.skill, limit: nil).map(&:character).map(&:id).index(self.character.id) + 1 end - private - def xp_required_for_level(level) - level <= 120 ? XP_TOTALS_PER_LEVEL[level - 1] : nil - end + def percentage_of_skill_level_completed + xp_gained_this_level = xp - CharacterSkill.xp_required_for_level(level) + total_xp_gain_neeeded_for_entire_level = total_xp_for_next_level - CharacterSkill.xp_required_for_level(level) + (xp_gained_this_level.to_f / total_xp_gain_neeeded_for_entire_level) * 100 + end + private def send_chat_message_if_leveled_up if CharacterSkill.level_for_xp(self.xp_was) < CharacterSkill.level_for_xp(self.xp) chat_message = ChatMessage.new(body: "reached #{self.skill.name} level #{self.level}!", diff --git a/app/models/item_infix.rb b/app/models/item_infix.rb new file mode 100644 index 0000000..cc99ee7 --- /dev/null +++ b/app/models/item_infix.rb @@ -0,0 +1,13 @@ +class ItemInfix < ApplicationRecord + belongs_to :character + belongs_to :item + belongs_to :skill + + before_create :check_max_infixes + + private + def check_max_infixes + current_infixes = character.item_infixes.where(skill: skill) + raise :abort if current_infixes.count >= character.max_infixes(skill) + end +end diff --git a/app/views/application/_navbar.html.erb b/app/views/application/_navbar.html.erb index be2d9f2..3436619 100644 --- a/app/views/application/_navbar.html.erb +++ b/app/views/application/_navbar.html.erb @@ -7,6 +7,9 @@ <%= link_to "Character", character_path(current_char) %> </li> <li class="mr-6 inline"> + <%= link_to "Skills", character_skills_path(current_char) %> + </li> + <li class="mr-6 inline"> <%= link_to "Inventory", character_items_path(current_char) %> </li> <li class="mr-6 inline"> diff --git a/app/views/characters/show.html.erb b/app/views/characters/show.html.erb index a7b7c0e..02f2f55 100644 --- a/app/views/characters/show.html.erb +++ b/app/views/characters/show.html.erb @@ -149,31 +149,6 @@ </div> </div> -<div class="my-6"> - <h2 class="text-xl mb-4">Skills</h2> - - <table class="table-auto mb-8"> - <thead> - <tr> - <th class="table-header-padded">Skill</th> - <th class="table-header-padded">Level</th> - <th class="table-header-padded">XPTNL</th> - <th class="table-header-padded">Total XP</th> - </tr> - </thead> - <tbody> - <% @character.character_skills.ordered_by_skill_name.each do |cs| %> - <tr> - <td class="table-cell-padded"><%= cs.skill.name %></td> - <td class="table-cell-padded"><%= cs.level %></td> - <td class="table-cell-padded"><%= cs.xp_to_next_level %></td> - <td class="table-cell-padded"><%= cs.xp %></td> - </tr> - <% end %> - </tbody> - </table> -</div> - <% if @character == current_char %> <%= link_to "Manage account", edit_user_registration_path, class: "text-sm" %> <% end %> diff --git a/app/views/characters/skills/index.html.erb b/app/views/characters/skills/index.html.erb new file mode 100644 index 0000000..fd53870 --- /dev/null +++ b/app/views/characters/skills/index.html.erb @@ -0,0 +1,24 @@ +<h2 class="text-3xl mb-2">Skills</h2> +<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> + <% @character.character_skills.ordered_by_skill_name.each do |cs| %> + <div class="rounded border border-gray-700"> + <div class="flex p-1"> + <div class="flex-grow"> + <div class="text-xl text-display mb-1"> + <%= cs.skill.name %> + </div> + <div class="flex items-center text-xs"> + <span class="bg-gray-700 px-1 py-0.5 rounded mr-1">XP</span><%= cs.xp %> + </div> + </div> + <div class="text-xl m-2 text-display"> + <%= cs.level %> + </div> + </div> + <div class="border border-gray-800 h-2 my-1"> + <div class="bg-gray-600 h-full" style="width: <%= cs.percentage_of_skill_level_completed %>%"> + </div> + </div> + </div> + <% end %> +</div> diff --git a/config/routes.rb b/config/routes.rb index fa6d748..22b8299 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,6 +32,7 @@ Rails.application.routes.draw do post "/equip", to: "items#equip" post "/use", to: "items#use" end + resources :skills, only: [:index] resources :titles, only: [:index] do post "/activate", to: "titles#activate" end diff --git a/data/activities.yml b/data/activities.yml index 3d3dc7b..525905a 100644 --- a/data/activities.yml +++ b/data/activities.yml @@ -251,6 +251,69 @@ construct_spicebench_level2: - type: "hearth_amenity" gid: "spicebench" level: 2 +construct_binding_array_level1: + name: "Construct Binding Array Level 1" + description: "Build a level 1 binding array." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "foundation" + level: 1 + duration: + base: 1000 + cost: + - type: "item" + gid: "stone" + quantity: 200 + - type: "item" + gid: "wood" + quantity: 400 + - type: "item" + gid: "iron_ingot" + quantity: 4 + - type: "item" + gid: "red_beryl" + quantity: 2 + - type: "item" + gid: "tourmaline" + quantity: 2 + results: + - type: "hearth_amenity" + gid: "binding_array" + level: 1 +construct_binding_array_level2: + name: "Construct Binding Array Level 2" + description: "Upgrade your binding array to level 2." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "binding_array" + level: 1 + duration: + base: 3600 + cost: + - type: "item" + gid: "stone" + quantity: 200 + - type: "item" + gid: "wood" + quantity: 300 + - type: "item" + gid: "red_beryl" + quantity: 2 + - type: "item" + gid: "tourmaline" + quantity: 2 + - type: "item" + gid: "paraiba tourmaline" + quantity: 1 + - type: "item" + gid: "yellow_beryl" + quantity: 1 + results: + - type: "hearth_amenity" + gid: "binding_array" + level: 2 plant_mudtub_seed: name: "Plant Mudtub Seed" description: "Plant a mudtub seed." @@ -595,7 +658,7 @@ craft_purify_crude_iron_ingot: gid: "forge" level: 1 duration: - base: 105 + base: 60 minimum: 35 scaling: - type: "skill" @@ -626,7 +689,7 @@ craft_purify_iron_ingot: gid: "otherforge" level: 5 duration: - base: 115 + base: 70 minimum: 35 scaling: - type: "skill" @@ -1049,7 +1112,7 @@ craft_arcanite_longsword: level: 2 - type: "skill" gid: "otherforge" - level: 15 + level: 17 duration: base: 215 minimum: 35 @@ -1912,7 +1975,7 @@ planequarry_floret_mines: score: 0.996 xp: - gid: "planequarry" - value: 25 + value: 18 - type: "item" chance: 0.02 table: @@ -1980,12 +2043,12 @@ planequarry_deepshaft: score: 0.90 xp: - gid: "planequarry" - value: 25 + value: 18 - gid: "gaian_ore" score: 0.995 xp: - gid: "planequarry" - value: 50 + value: 25 - type: "item" chance: 0.03 table: @@ -2647,3 +2710,190 @@ beastslay_leviathan_floret_region: - type: "monster_spawn" location: "floret_region" chance: 1 +craft_faint_hope: + name: "Bind faint hope" + description: "Bind an omen of faint hope." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "binding_array" + level: 1 + duration: + base: 60 + minimum: 35 + scaling: + - type: "skill" + gid: "omenbind" + scale_value: 1 + - type: "stat" + gid: "omenbind_speed" + scale_value: 1 + cost: + - type: "item" + gid: "vestige" + quantity: 5 + - type: "item" + gid: "arcane_dust" + quantity: 10 + results: + - type: "item" + gid: "faint_hope" + xp: + - gid: "omenbind" + value: 6 +craft_fleeting_glimpse: + name: "Bind fleeting glimpse" + description: "Bind a fleeting glimpse omen." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "binding_array" + level: 1 + - type: "skill" + gid: "omenbind" + level: 3 + duration: + base: 65 + minimum: 35 + scaling: + - type: "skill" + gid: "omenbind" + scale_value: 1 + - type: "stat" + gid: "omenbind_speed" + scale_value: 1 + cost: + - type: "item" + gid: "vestige" + quantity: 8 + - type: "item" + gid: "shimmering_essence" + quantity: 1 + results: + - type: "item" + gid: "fleeting_glimpse" + xp: + - gid: "omenbind" + value: 12 +craft_bright_token: + name: "Bind bright token" + description: "Bind a bright token omen." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "binding_array" + level: 1 + - type: "skill" + gid: "omenbind" + level: 6 + duration: + base: 70 + minimum: 35 + scaling: + - type: "skill" + gid: "omenbind" + scale_value: 1 + - type: "stat" + gid: "omenbind_speed" + scale_value: 1 + cost: + - type: "item" + gid: "vestige" + quantity: 12 + - type: "item" + gid: "gem_dust" + quantity: 1 + results: + - type: "item" + gid: "bright_token" + xp: + - gid: "omenbind" + value: 16 +craft_sign_of_solace: + name: "Bind sign of solace" + description: "Bind a sign of solace." + whatnot: + requirements: + - type: "hearth_amenity" + gid: "binding_array" + level: 2 + - type: "skill" + gid: "omenbind" + level: 10 + duration: + base: 80 + minimum: 35 + scaling: + - type: "skill" + gid: "omenbind" + scale_value: 1 + - type: "stat" + gid: "omenbind_speed" + scale_value: 1 + cost: + - type: "item" + gid: "vestige" + quantity: 25 + - type: "item" + gid: "claritas_flower" + quantity: 1 + results: + - type: "item" + gid: "sign_of_solace" + xp: + - gid: "omenbind" + value: 22 +havencast_light: + name: "Cast Light" + description: "Cast the Light cantrip." + whatnot: + tags: + - "cantrip" + duration: + base: 30 + minimum: 10 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 1 + cost: + - type: "mana" + gid: "clear" + quantity: 1 + results: + - type: "condition" + gid: "light" + - type: "xp" + gid: "havencast" + base: 3 +havencast_dazzle: + name: "Cast Dazzle" + description: "Cast the Dazzle cantrip." + whatnot: + tags: + - "cantrip" + duration: + base: 32 + minimum: 10 + scaling: + - type: "skill" + gid: "havencast" + scale_value: 1 + requirements: + - type: "skill" + gid: "havencast" + level: 2 + cost: + - type: "mana" + gid: "clear" + quantity: 2 + results: + - type: "condition" + gid: "dazzle" + - type: "xp" + gid: "havencast" + base: 6 diff --git a/data/conditions.yml b/data/conditions.yml index b691254..11dcede 100644 --- a/data/conditions.yml +++ b/data/conditions.yml @@ -96,3 +96,17 @@ mercuria: - type: "stat_change" gid: "evasion" modifier: 1 +light: + name: "light" + description: "Allows seeing in dark areas." + whatnot: + effects: + - type: "special" + gid: "darkvision" +dazzle: + name: "dazzle" + description: "Reduces enemies' accuracy." + effects: + - type: "enemy_stat_change" + gid: "accuracy" + modifier: -1 diff --git a/data/hearth_amenities.yml b/data/hearth_amenities.yml index 6ab8021..e58aa1c 100644 --- a/data/hearth_amenities.yml +++ b/data/hearth_amenities.yml @@ -85,3 +85,14 @@ spicebench: level: 2 gid: "spicework_speed" modifier: 4 +binding_array: + name: "Binding Array" + description: >- + A apparatus for binding magical energy into a physical form, creating an omen. + whatnot: + construct_activities: + - level: 1 + gid: "construct_binding_array_level1" + - level: 2 + gid: "construct_binding_array_level2" + diff --git a/data/items.yml b/data/items.yml index 0aac500..1f0be2c 100644 --- a/data/items.yml +++ b/data/items.yml @@ -1094,3 +1094,27 @@ balgoloth_claw: gid: "pierce" min: 1 max: 6 +faint_hope: + name: "faint hope" + description: "A weak omen made from compressed arcane energy." + whatnot: + tags: + - "omen" +fleeting_glimpse: + name: "fleeting glimpse" + description: "A weak omen that shows vague images in its ethereal surface." + whatnot: + tags: + - "omen" +bright_token: + name: "bright token" + description: "An omen with promising magical potential." + whatnot: + tags: + - "omen" +sign_of_solace: + name: "sign of solace" + description: "A sign that shines radiantly from a pinpoint at its center." + whatnot: + tags: + - "omen" diff --git a/data/skills.yml b/data/skills.yml index 68de599..0bbd63a 100644 --- a/data/skills.yml +++ b/data/skills.yml @@ -52,7 +52,7 @@ omenbind: ago developed a technique for harnessing magical power and spells within physical objects like crystalline batteries and gem-laden crowns. These power-imbued objects are called omens. The practice of omenbinding flourishes to this day, and indeed the world would not be the same without its providing for saving and storing up power to be - used at a later time, or in greater mass. The most powerful omenbinders have been known to bind energy even within + used at a later time, or in greater mass. The most powerful omenbinding have been known to bind energy even within flesh, though this practice is as risky as it is dangerous. otherforge: name: "Otherforge" diff --git a/db/migrate/20210614004827_create_item_infixes.rb b/db/migrate/20210614004827_create_item_infixes.rb new file mode 100644 index 0000000..5b49892 --- /dev/null +++ b/db/migrate/20210614004827_create_item_infixes.rb @@ -0,0 +1,11 @@ +class CreateItemInfixes < ActiveRecord::Migration[6.1] + def change + create_table :item_infixes do |t| + t.references :character, null: false, foreign_key: true + t.references :item, null: false, foreign_key: true + t.references :skill, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 75ebad0..f3992ee 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_06_10_010413) do +ActiveRecord::Schema.define(version: 2021_06_14_004827) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -156,6 +156,17 @@ ActiveRecord::Schema.define(version: 2021_06_10_010413) do t.index ["character_id"], name: "index_hearths_on_character_id" end + create_table "item_infixes", force: :cascade do |t| + t.bigint "character_id", null: false + t.bigint "item_id", null: false + t.bigint "skill_id", null: false + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["character_id"], name: "index_item_infixes_on_character_id" + t.index ["item_id"], name: "index_item_infixes_on_item_id" + t.index ["skill_id"], name: "index_item_infixes_on_skill_id" + end + create_table "items", force: :cascade do |t| t.string "gid" t.string "name" @@ -308,6 +319,9 @@ ActiveRecord::Schema.define(version: 2021_06_10_010413) do add_foreign_key "hearth_plantings", "hearths" add_foreign_key "hearth_plantings", "items" add_foreign_key "hearths", "characters" + add_foreign_key "item_infixes", "characters" + add_foreign_key "item_infixes", "items" + add_foreign_key "item_infixes", "skills" add_foreign_key "learned_activities", "activities" add_foreign_key "learned_activities", "characters" add_foreign_key "messages", "characters", column: "recipient_id" diff --git a/test/fixtures/item_infixes.yml b/test/fixtures/item_infixes.yml new file mode 100644 index 0000000..535831c --- /dev/null +++ b/test/fixtures/item_infixes.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + character: one + item: one + skill: one + +two: + character: two + item: two + skill: two diff --git a/test/models/item_infix_test.rb b/test/models/item_infix_test.rb new file mode 100644 index 0000000..a6f63a3 --- /dev/null +++ b/test/models/item_infix_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ItemInfixTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end |