summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/characters/rankings_controller.rb9
-rw-r--r--app/controllers/leaderboard_controller.rb9
-rw-r--r--app/models/character.rb36
-rw-r--r--app/models/character_skill.rb9
-rw-r--r--app/views/application/_header.html.erb3
-rw-r--r--app/views/application/components/text/_name_and_title.html.erb1
-rw-r--r--app/views/characters/rankings/index.html.erb36
-rw-r--r--app/views/characters/show.html.erb5
-rw-r--r--app/views/leaderboard/index.html.erb95
9 files changed, 202 insertions, 1 deletions
diff --git a/app/controllers/characters/rankings_controller.rb b/app/controllers/characters/rankings_controller.rb
new file mode 100644
index 0000000..bbae9fc
--- /dev/null
+++ b/app/controllers/characters/rankings_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class Characters::RankingsController < ApplicationController
+ skip_before_action :authenticate_user!
+
+ def index
+ @character = Character.find(params[:character_id])
+ end
+end \ No newline at end of file
diff --git a/app/controllers/leaderboard_controller.rb b/app/controllers/leaderboard_controller.rb
new file mode 100644
index 0000000..e6e8543
--- /dev/null
+++ b/app/controllers/leaderboard_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class LeaderboardController < ApplicationController
+ def index
+ @top_per_skill = Hash[Skill.all.map { |s| [s.name.to_sym, CharacterSkill.top_xp_for(s)] }]
+ @top_total_xp = Character.top_total_xp
+ @top_total_level = Character.top_total_level
+ end
+end
diff --git a/app/models/character.rb b/app/models/character.rb
index 8913f71..a5c871b 100644
--- a/app/models/character.rb
+++ b/app/models/character.rb
@@ -25,6 +25,22 @@ class Character < ApplicationRecord
after_create :create_skills, :set_combat_styles
after_create { Hearth.create(character: self) }
+ def self.sorted_by_total_xp
+ all.sort_by(&:total_xp).reverse
+ end
+
+ def self.sorted_by_total_level
+ all.sort_by(&:total_level).reverse
+ end
+
+ def self.top_total_xp
+ sorted_by_total_xp.first(5)
+ end
+
+ def self.top_total_level
+ sorted_by_total_level.first(5)
+ end
+
def beastslay_level; skill_level("beastslay"); end
def fluxseethe_level; skill_level("fluxseethe"); end
def havencast_level; skill_level("havencast"); end
@@ -41,6 +57,26 @@ class Character < ApplicationRecord
def wildscour_level; skill_level("wildscour"); end
def worldcall_level; skill_level("worldcall"); end
+ def total_xp
+ character_skills.sum(:xp).to_i
+ end
+
+ def total_level
+ count = 0
+ character_skills.each do |cs|
+ count += cs.level
+ end
+ count
+ end
+
+ def total_xp_rank
+ Character.sorted_by_total_xp.map(&:id).index(self.id) + 1
+ end
+
+ def total_level_rank
+ Character.sorted_by_total_level.map(&:id).index(self.id) + 1
+ end
+
def vestige
vestige = self.character_items.find_by(item: Item.find_by_gid("vestige"))
vestige ? vestige.quantity : 0
diff --git a/app/models/character_skill.rb b/app/models/character_skill.rb
index 20468c3..722a371 100644
--- a/app/models/character_skill.rb
+++ b/app/models/character_skill.rb
@@ -26,6 +26,11 @@ class CharacterSkill < ApplicationRecord
1459475733, 1680697391, 1935475040, 2228899094
].freeze
+ def self.top_xp_for(skill, limit: 10)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ where(skill: skill).order(xp: :desc, updated_at: :asc).limit(limit)
+ end
+
def self.level_for_xp(xp)
XP_TOTALS_PER_LEVEL.each_with_index do |total, index|
if total > xp
@@ -48,6 +53,10 @@ class CharacterSkill < ApplicationRecord
total_xp_for_next_level - self.xp
end
+ def rank
+ 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
diff --git a/app/views/application/_header.html.erb b/app/views/application/_header.html.erb
index 25067f3..38bfcf4 100644
--- a/app/views/application/_header.html.erb
+++ b/app/views/application/_header.html.erb
@@ -14,6 +14,9 @@
<%= link_to "Items", items_path %>
</li>
<li class="mr-3">
+ <%= link_to "Leaderboard", leaderboard_path %>
+ </li>
+ <li class="mr-3">
<%= link_to "Logout", logout_path %>
</li>
<% else %>
diff --git a/app/views/application/components/text/_name_and_title.html.erb b/app/views/application/components/text/_name_and_title.html.erb
new file mode 100644
index 0000000..41a4f27
--- /dev/null
+++ b/app/views/application/components/text/_name_and_title.html.erb
@@ -0,0 +1 @@
+<%= render "application/components/text/title", title: character.active_title %> <%= character.name %>
diff --git a/app/views/characters/rankings/index.html.erb b/app/views/characters/rankings/index.html.erb
new file mode 100644
index 0000000..8f41bd2
--- /dev/null
+++ b/app/views/characters/rankings/index.html.erb
@@ -0,0 +1,36 @@
+<h1 class="text-2xl">Rankings for <%= render "application/components/text/name_and_title", character: @character %></h1>
+
+<div class="my-2">
+ <%= link_to "Refresh", character_rankings_path %>
+</div>
+
+<div class="my-2">
+ <p>Total Level: <%= @character.total_level %> (Rank <%= @character.total_level_rank %>)</p>
+ <p>Total XP: <%= @character.total_xp %> (Rank <%= @character.total_xp_rank %>)</p>
+</div>
+
+<div class="my-2">
+ <div>
+ <table class="table-auto">
+ <thead>
+ <tr>
+ <th class="table-header-padded">Skill</th>
+ <th class="table-header-padded">Rank</th>
+ <th class="table-header-padded">Level</th>
+ <th class="table-header-padded">XP</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% Skill.all.each do |skill| %>
+ <% character_skill = @character.character_skills.find_by(skill: skill) %>
+ <tr>
+ <td class="table-cell-padded"><%= skill.name %></td>
+ <td class="table-cell-padded"><%= character_skill.rank %></td>
+ <td class="table-cell-padded"><%= character_skill.level %></td>
+ <td class="table-cell-padded"><%= character_skill.xp %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/app/views/characters/show.html.erb b/app/views/characters/show.html.erb
index ce1c2db..1b5439a 100644
--- a/app/views/characters/show.html.erb
+++ b/app/views/characters/show.html.erb
@@ -3,7 +3,10 @@
</h1>
<div class="text-lg mb-4">
- <%= link_to "Titles", character_titles_path(@character) %>
+ <ul class="flex flex-row">
+ <li class="mr-2"><%= link_to "Titles", character_titles_path(@character) %></li>
+ <li class="mr-2"><%= link_to "Rankings", character_rankings_path(@character) %></li>
+ </ul>
</div>
<p class="mb-4">First entered the planes
diff --git a/app/views/leaderboard/index.html.erb b/app/views/leaderboard/index.html.erb
new file mode 100644
index 0000000..006def1
--- /dev/null
+++ b/app/views/leaderboard/index.html.erb
@@ -0,0 +1,95 @@
+<h1 class="text-2xl">Leaderboard</h1>
+<p>These rankings are not meant to declare the best characters, only those
+with the most XP. XP is far from the only indicator of achievement in Esoterra.</p>
+
+<% if current_char %>
+ <div class="my-2">
+ <%= link_to "View rankings for #{current_char.name}", character_rankings_path(current_char) %>
+ </div>
+<% end %>
+
+<div class="my-2">
+ <%= link_to "Refresh", leaderboard_path %>
+</div>
+
+<div class="grid grid-cols-12 gap-2">
+ <div class="col-span-12 sm:col-span-6">
+ <div>
+ <h2 class="text-xl">Total Level</h2>
+ <table class="table-auto">
+ <thead>
+ <tr>
+ <th class="table-header-padded">Rank</th>
+ <th class="table-header-padded">Character</th>
+ <th class="table-header-padded">Total Level</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @top_total_level.each_with_index do |c, index| %>
+ <tr>
+ <td class="table-cell-padded"><%= index + 1 %></td>
+ <td class="table-cell-padded"><%= link_to c.name, character_rankings_path(c) %></td>
+ <td class="table-cell-padded"><%= c.total_level %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <div class="col-span-12 sm:col-span-6">
+ <div>
+ <h2 class="text-xl">Total XP</h2>
+ <table class="table-auto">
+ <thead>
+ <tr>
+ <th class="table-header-padded">Rank</th>
+ <th class="table-header-padded">Character</th>
+ <th class="table-header-padded">Total XP</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @top_total_xp.each_with_index do |c, index| %>
+ <tr>
+ <td class="table-cell-padded"><%= index + 1 %></td>
+ <td class="table-cell-padded"><%= link_to c.name, character_rankings_path(c) %></td>
+ <td class="table-cell-padded"><%= c.total_xp %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+
+
+ </div>
+</div>
+
+<div class="mt-4">
+ <h2 class="text-xl">Skill XP Totals</h2>
+ <div class="grid grid-cols-12 gap-2">
+ <% @top_per_skill.each do |skill_name, skill_trainings| %>
+ <div class="col-span-12 sm:col-span-6">
+ <h3 class="text-lg my-1"><%= skill_name %></h3>
+ <table class="table-auto">
+ <thead>
+ <tr>
+ <th class="table-header-padded">Rank</th>
+ <th class="table-header-padded">Character</th>
+ <th class="table-header-padded">Level</th>
+ <th class="table-header-padded">XP</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% skill_trainings.each_with_index do |st, index| %>
+ <tr>
+ <td class="table-cell-padded"><%= index + 1 %></td>
+ <td class="table-cell-padded"><%= link_to st.character.name, character_rankings_path(st.character) %></td>
+ <td class="table-cell-padded"><%= st.level %></td>
+ <td class="table-cell-padded"><%= st.xp %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+ </div>
+ <% end %>
+ </div>
+</div>