diff --git a/api/db.js b/api/db.js
index 813a5a4..5710ff3 100644
--- a/api/db.js
+++ b/api/db.js
@@ -358,7 +358,7 @@ export async function get_character_batch_for_stats(batch, sort, order) {
try {
const char_count = await get_row_count(CHARACTER.THIS);
- const chars = await pool.query(`SELECT id, name, faction_id, bep, cep FROM avatar ORDER BY ${to_sql(sort)} ${to_sql(order)} OFFSET $1*1000 LIMIT 1000`, values);
+ const chars = await pool.query(`SELECT id, name, faction_id, bep, cep FROM avatar ORDER BY ${to_sql(sort)} ${to_sql(order)} OFFSET $1*500 LIMIT 500`, values);
return chars.rows;
} catch (e) {
@@ -380,9 +380,16 @@ export async function get_weaponstats_by_avatar(id) {
}
export async function get_avatar(id) {
- try {
- const avatar = await pool.query('SELECT id, name, faction_id, bep, cep, gender_id, head_id FROM avatar WHERE id=$1', [id])
- return avatar.rows[0];
+ try {
+ const avatar = await pool.query(
+ 'SELECT a.id, a.name, a.faction_id, a.bep, a.cep, a.gender_id, a.head_id,' +
+ ' o.id AS outfit_id, o.name AS outfit_name' +
+ ' FROM avatar a' +
+ ' LEFT JOIN outfitmember om ON om.avatar_id = a.id' +
+ ' LEFT JOIN outfit o ON o.id = om.outfit_id' +
+ ' WHERE a.id = $1',
+ [id])
+ return avatar.rows[0];
} catch (e) {
if (e.code)
e.code = pg_error_inv[e.code]
@@ -398,7 +405,8 @@ export async function get_top_kills() {
' INNER JOIN avatar ON killactivity.killer_id = avatar.id' +
' WHERE exp > 0' +
' GROUP BY killactivity.killer_id, avatar.name, avatar.bep, avatar.cep, avatar.faction_id, avatar.gender_id, avatar.head_id' +
- ' ORDER BY count(killer_id) DESC')
+ ' ORDER BY count(killer_id) DESC' +
+ ' LIMIT 500')
return kills.rows;
} catch (e) {
if (e.code)
@@ -438,6 +446,92 @@ export async function get_top_kills_byDate() {
}
}
+export async function get_top_outfits() {
+ try {
+ const outfits = await pool.query(
+ 'WITH OutfitData AS (' +
+ ' SELECT o.id AS outfit_id,' +
+ ' o.faction,' +
+ ' o.name AS outfit_name,' +
+ ' a.id AS leader_id, a.name AS leader_name,' +
+ ' COUNT(om.avatar_id)::int AS members,' +
+ ' (op.points / 100.0)::int AS points' +
+ ' FROM outfit o' +
+ ' JOIN avatar a ON a.id = o.owner_id' +
+ ' LEFT JOIN outfitmember om ON om.outfit_id = o.id' +
+ ' LEFT JOIN outfitpoint_mv op ON op.outfit_id = o.id' +
+ ' GROUP BY o.id, o.faction, o.name, a.name, a.id, op.points' +
+ ') ' +
+ 'SELECT outfit_id, faction, outfit_name, leader_name, leader_id, members, points ' +
+ 'FROM OutfitData ' +
+ 'ORDER BY points DESC')
+ return outfits.rows;
+ } catch (e) {
+ if (e.code)
+ e.code = pg_error_inv[e.code]
+ throw e;
+ }
+}
+
+export async function get_outfit(id) {
+ try {
+const outfit = await pool.query(
+ 'WITH OutfitData AS (' +
+ ' SELECT o.id AS outfit_id, o.faction, o.name AS outfit_name, o.created,' +
+ ' a.id AS leader_id,' +
+ ' a.name AS leader_name,' +
+ ' COUNT(om.avatar_id)::int AS members,' +
+ ' (op.points / 100.0)::int AS points' +
+ ' FROM outfit o ' +
+ ' JOIN avatar a ON a.id = o.owner_id ' +
+ ' LEFT JOIN outfitmember om ON om.outfit_id = o.id ' +
+ ' LEFT JOIN outfitpoint_mv op ON op.outfit_id = o.id ' +
+ ' WHERE o.id = $1 ' +
+ ' GROUP BY o.created, o.id, o.faction, o.name, a.id, a.name, op.points) ' +
+ 'SELECT outfit_id, faction, outfit_name, leader_id, leader_name, members, points, created ' +
+ 'FROM OutfitData',
+ [id])
+ return outfit.rows[0];
+ } catch (e) {
+ if (e.code)
+ e.code = pg_error_inv[e.code];
+ throw e;
+ }
+}
+
+export async function get_outfit_members(id) {
+ try {
+const members = await pool.query(
+ 'SELECT av.id AS avatar_id, av.bep, av.cep,' +
+ ' av.name AS avatar_name,' +
+ ' om.rank AS rank_num,' +
+ ' CASE om.rank ' +
+ ' WHEN 0 THEN COALESCE(o.rank0, \'Fodder\') ' +
+ ' WHEN 1 THEN COALESCE(o.rank1, \'Soldier\') ' +
+ ' WHEN 2 THEN COALESCE(o.rank2, \'Commando\') ' +
+ ' WHEN 3 THEN COALESCE(o.rank3, \'Master at Arms\') ' +
+ ' WHEN 4 THEN COALESCE(o.rank4, \'Tactical Officer\') ' +
+ ' WHEN 5 THEN COALESCE(o.rank5, \'Strategic Officer\') ' +
+ ' WHEN 6 THEN COALESCE(o.rank6, \'Chief Officer\') ' +
+ ' WHEN 7 THEN COALESCE(o.rank7, \'Outfit Leader\') ' +
+ ' END AS rank_title,' +
+ ' COALESCE((op.points / 100.0)::int, 0) AS points,' +
+ ' om.created AS joined' +
+ ' FROM outfitmember om ' +
+ ' JOIN avatar av ON av.id = om.avatar_id ' +
+ ' JOIN outfit o ON o.id = om.outfit_id ' +
+ ' LEFT JOIN outfitpoint op ON op.avatar_id = om.avatar_id ' +
+ ' WHERE om.outfit_id = $1 ' +
+ ' ORDER BY points DESC, avatar_name ASC',
+ [id])
+ return members.rows;
+ } catch (e) {
+ if (e.code)
+ e.code = pg_error_inv[e.code];
+ throw e;
+ }
+}
+
export async function get_characters_by_account(account_id) {
try {
const characters = await pool.query('SELECT a.*, b.* FROM avatar a LEFT JOIN avatarmodepermission b ON a.id = b.avatar_id WHERE a.account_id = $1 AND a.deleted = false', [account_id])
diff --git a/api/stats.js b/api/stats.js
index 594bf6a..f67fc97 100644
--- a/api/stats.js
+++ b/api/stats.js
@@ -78,6 +78,38 @@ api.get('/top_kills_byDate', async (req, res, next) => {
}
});
+api.get('/top_outfits', async (req, res, next) => {
+ try {
+ const outfits = await db.get_top_outfits();
+ res.status(200).json({ outfits: outfits });
+ } catch (e) {
+ console.log(e);
+ res.status(500).json({ message: 'error' });
+ }
+});
+
+api.get('/outfit/:outfit', async (req, res, next) => {
+ const fit = req.params.outfit
+ try {
+ const outfit = await db.get_outfit(fit);
+ res.status(200).json(outfit);
+ } catch (e) {
+ console.log(e);
+ res.status(500).json({ message: 'error' });
+ }
+});
+
+api.get('/outfit/:outfit/members', async (req, res, next) => {
+ const fit = req.params.outfit
+ try {
+ const members = await db.get_outfit_members(fit);
+ res.status(200).json({ members: members });
+ } catch (e) {
+ console.log(e);
+ res.status(500).json({ message: 'error' });
+ }
+});
+
api.get('/weaponstats/:avatar', async (req, res, next) => {
const avatar = req.params.avatar;
@@ -102,7 +134,9 @@ api.get('/avatar/:avatar', async (req, res, next) => {
cep: avatarData.cep,
faction: avatarData.faction_id,
gender: avatarData.gender_id,
- head: avatarData.head_id
+ head: avatarData.head_id,
+ outfit: avatarData.outfit_name,
+ outfit_id: avatarData.outfit_id
});
} catch (e) {
console.log(e);
diff --git a/app/App.svelte b/app/App.svelte
index 696d445..a266d0b 100644
--- a/app/App.svelte
+++ b/app/App.svelte
@@ -28,6 +28,7 @@ import AdminPanel from './views/AdminPanel.svelte';
import CharacterList from './views/CharacterList.svelte';
import Leaderboard from './views/Leaderboard.svelte';
import Avatar from './views/Avatar.svelte'
+import Outfit from './views/Outfit.svelte'
// Defined by webpack
let APP_VERSION = __VERSION__;
@@ -106,6 +107,7 @@ page("/avatar/:id", setRoute(Avatar));
page("/admin", setRoute(AdminPanel));
page("/profile", setRoute(Profile, true));
page("/user/:id", setRoute(Profile, true));
+page("/outfit/:id", setRoute(Outfit));
if (process.env.NODE_ENV !== 'production') {
console.log("Development mode active");
const cc = await import('./views/components.svelte');
diff --git a/app/views/Avatar.svelte b/app/views/Avatar.svelte
index 519e57a..fae5f3f 100644
--- a/app/views/Avatar.svelte
+++ b/app/views/Avatar.svelte
@@ -138,7 +138,11 @@
Character Name: {avatar.name}
- Empire: {getFactionName(avatar.faction)}
+ Empire: {getFactionName(avatar.faction)}
+ Outfit:
+ {#if avatar.outfit_id}
+ {avatar.outfit}
+ {/if}
|
}) |
diff --git a/app/views/Leaderboard.svelte b/app/views/Leaderboard.svelte
index 0dff3e0..f47f4fb 100644
--- a/app/views/Leaderboard.svelte
+++ b/app/views/Leaderboard.svelte
@@ -8,12 +8,14 @@
get_BEPleaderboard();
get_CEPleaderboard();
get_kills();
+ get_outfits();
get_topDateKills();
});
let bepPlayers = [];
let cepPlayers = [];
let kills = [];
+ let outfits = [];
let dateKills = [];
let alert;
@@ -34,7 +36,7 @@
try {
const resp = await axios.get("/api/char_stats_cep/0");
const stats = resp.data;
- cepPlayers = stats.players;
+ cepPlayers = stats.players.filter(p => p.cep > 0);
// Reset alert message if needed
alert.message("");
} catch (e) {
@@ -56,6 +58,19 @@
}
}
+ async function get_outfits() {
+ try {
+ const resp = await axios.get("/api/top_outfits");
+ const stats = resp.data;
+ outfits = stats.outfits;
+ // Reset alert message if needed
+ alert.message("");
+ } catch (e) {
+ console.log(e);
+ alert.message("Failed to fetch stats from server");
+ }
+ }
+
async function get_topDateKills() {
try {
const resp = await axios.get("/api/top_kills_byDate");
@@ -86,6 +101,9 @@
Command Rank
+
+ Outfits
+
Top X
@@ -166,7 +184,32 @@
-
+
+
+
+ | # |
+ Name |
+ Leader |
+ Members |
+ Points |
+
+
+ {#each outfits as outfit, $index}
+
+ | {$index + 1} |
+
+
+ {outfit.outfit_name} |
+ {outfit.leader_name} |
+ {outfit.members} |
+ {outfit.points} |
+
+ {/each}
+
+
+
+
+
Top 50 Characters Most Daily Kills
diff --git a/app/views/Outfit.svelte b/app/views/Outfit.svelte
new file mode 100644
index 0000000..fc77490
--- /dev/null
+++ b/app/views/Outfit.svelte
@@ -0,0 +1,117 @@
+
+
+
+Outfit Stats
+
+
+
+
+
+
+
+
+
+
+ })
+ Outfit Name: {outfit.outfit_name}
+ Created:
+ {new Date(outfit.created).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ })}
+ Leader: {outfit.leader_name}
+ Points: {outfit.points}
+ Members: {outfit.members}
+ |
+
+
+ |
+
+
+
+
+
+
+
+ |
+ Name |
+ Title |
+ Points |
+ BR |
+ CR |
+ Joined |
+
+
+ {#each outfitMembers as member, $index}
+
+ | {$index + 1} |
+ {member.avatar_name} |
+ {stripColorCode(member.rank_title)} |
+ {member.points} |
+ {calculateBr(member.bep)} |
+ {calculateCr(member.cep)} |
+
+ {new Date(member.joined).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+ })}
+ |
+
+ {/each}
+
+