+
+
+
+
+
+
+ πΎ
+
+
+
+ Galaxy Event
+
+
+
+
+
+
+
+
+ π
+
+
+
+ Season 1
+
+
+
+
+
+ Fleet Status
@@ -350,7 +479,13 @@
Experience
- 0 / 100
+ 0 / 500
+
+
+
+
+
+
Skill Points
@@ -426,10 +561,10 @@
-
+
-
-
-
-
+
+
+
+
@@ -460,58 +595,77 @@
-
-
Your Ships
- -
-
-
-
Current Ship
-
-
-
+
+
+
-
-
-
-
-
- Starter Cruiser
-
-
-
- Class:
- Light
-
-
- Level:
- 1
-
-
- Health:
- 100/100
-
-
- Attack:
- 10
-
-
- Defense:
- 5
-
-
- Speed:
- 15
-
-
+
+
+ π Shipyard
+ Shipyard Level: 1 | Queue: 0/3 +
+
+
+
+
+
+ π Available Blueprints
+
+
+ Loading blueprintsβ¦
+
+
+
-
-
- β Construction Queue
+
+
Slot 1 β Empty
+ Slot 2 β Empty
+ Slot 3 β Empty
-
Ships Collected
-
-
+
@@ -560,6 +714,11 @@
+
πΈ Your Fleet (0)
+
+
No ships yet
+
+
@@ -667,6 +836,26 @@
+
+
+
+
+
+
Ship Modules
+Loading modules...
+Equipment
@@ -617,24 +776,34 @@
- Crafting Level:
- 1
+ Level 1
- Experience:
- 0/100
+ 0 XP
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
+
+ Loading recipes...
+
+
+
+
+ Select a recipe
+Choose a recipe from the list to see requirements and craft.
+π Fleet Missions
+Send your ships on missions to earn resources, XP and loot. Missions run in real-time β check back to collect rewards.
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ π Mission Types
+Loadingβ¦
+
+
+ πΈ Select Ships
+ + +
+
+ + β± Active Missions + +
+
+
+ No active missions
+
+
+
+
+
+
+ π Available Faction Missions
+Build reputation with NPC factions by completing their missions. Higher reputation unlocks better missions and discounts.
+
+
+ Loadingβ¦
+
+
+ β± Active Faction Missions
+
+
+ No active faction missions
+
+
+
+
+
+
+ π‘ Alliance
+ + +
+
+
+
+
+
+
+
+ β Create Alliance
+Found your own alliance for 10,000 credits. Choose a unique name and 2β4 character tag.
+
+
+
+
+
+
+
+
+
+ π Find Alliance
+
+
+
+
+ Search for alliances above
+
+
+
+
+
+
+
+ + My Alliance + TAG +
+ + + +
+
+ π¦ Alliance Warehouse
+ +
+
+
+ Deposit Resources
+
+
+
+
+
+
+
+
+
+
+
+ πͺ Player Market
+Trade resources and items with other commanders. 2% listing fee. Listings expire after 24β72 hours.
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading marketβ¦
+
+
+
+
+
+
+
+
+ π¦ List a Resource
+
+
+
+
+
+
+
+
+
+
+ π List an Item
+ +
+
+
+
+
+
+
+
+ Loading your listingsβ¦
+
+
+
+
+
+
+
+
+
+
+ β Settings
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reduced Motion (disables particles)
+
+
+
+
+
+
+
+
+
+
+
@@ -959,8 +1540,24 @@
case 'leaderboard':
GSO_Leaderboard.load(GSO_Leaderboard.currentCat || 'level');
break;
+ case 'missions':
+ GSO_Missions.load();
+ break;
+ case 'alliance':
+ GSO_Alliance.load();
+ break;
+ case 'market':
+ GSO_Market.load();
+ break;
+ case 'social':
+ GSO_Social.load();
+ break;
+ case 'crafting':
+ GSO_Crafting.init();
+ break;
case 'inventory':
GSO_Inventory.render(window.gameInitializer?.serverPlayerData);
+ GSO_Modules.load();
break;
case 'base':
// load buildings when switching to base overview
@@ -987,8 +1584,8 @@
// Stop galaxy canvas if navigating away
if (tabName !== 'galaxy' && window.GSO_Galaxy) GSO_Galaxy.stop();
- // Remove active class from all nav buttons
- document.querySelectorAll('.nav-btn').forEach(btn => {
+ // Remove active class from all nav surfaces
+ document.querySelectorAll('.nav-btn, .bottom-nav-btn, .nav-drawer-btn').forEach(btn => {
btn.classList.remove('active');
});
@@ -1003,7 +1600,48 @@
if (targetButton) {
targetButton.classList.add('active');
}
+ // Sync all nav surfaces
+ _syncAllNavActive(tabName);
}
+
+ // ββ Bottom nav drawer toggle βββββββββββββββββββββββββββββββββββββ
+ function toggleNavDrawer() {
+ const drawer = document.getElementById('navDrawer');
+ const overlay = document.getElementById('navDrawerOverlay');
+ const btn = document.getElementById('bottomNavMore');
+ const isOpen = drawer && drawer.classList.contains('open');
+ if (!drawer) return;
+ if (isOpen) { closeNavDrawer(); }
+ else {
+ drawer.classList.add('open');
+ overlay && overlay.classList.add('open');
+ btn && btn.classList.add('open');
+ btn && btn.setAttribute('aria-expanded','true');
+ }
+ }
+ function closeNavDrawer() {
+ const drawer = document.getElementById('navDrawer');
+ const overlay = document.getElementById('navDrawerOverlay');
+ const btn = document.getElementById('bottomNavMore');
+ drawer && drawer.classList.remove('open');
+ overlay && overlay.classList.remove('open');
+ btn && btn.classList.remove('open');
+ btn && btn.setAttribute('aria-expanded','false');
+ }
+ // Sync active state across top nav, bottom nav, and drawer
+ function _syncAllNavActive(tabName) {
+ document.querySelectorAll('.nav-btn, .bottom-nav-btn, .nav-drawer-btn').forEach(b => {
+ b.classList.toggle('active', b.dataset.tab === tabName);
+ });
+ }
+ // Close drawer on swipe-down
+ (function(){
+ let startY = 0;
+ document.addEventListener('touchstart', e => { startY = e.touches[0].clientY; }, {passive:true});
+ document.addEventListener('touchend', e => {
+ if (e.changedTouches[0].clientY - startY > 60) closeNavDrawer();
+ }, {passive:true});
+ })();
function switchShopCategory(category) {
// Update ItemSystem activeCategory so Economy.updateShopUI renders the right items
@@ -1321,6 +1959,11 @@
GSO_Base.load();
}
+ // Load shipyard when switching to ships
+ if (view === 'ships' && window.GSO_Shipyard) {
+ setTimeout(() => GSO_Shipyard.load(), 50);
+ }
+
// Try to use BaseSystem first
if (window.game && window.game.systems && window.game.systems.base) {
window.game.systems.base.switchBaseView(view);
@@ -1742,9 +2385,26 @@
? this.research
: this.research.filter(r => r.branch === this.currentBranch);
if (!items.length) { tree.innerHTML = '
No technologies in this branch.
'; return; } - // Sort by tier - items.sort((a,b) => a.tier - b.tier); - tree.innerHTML = items.map(r => this._card(r)).join(''); + items.sort((a,b) => (a.tier - b.tier) || a.name.localeCompare(b.name)); + + // Group by tier for visual tree layout (GDD Β§16.4) + const tiers = {}; + items.forEach(r => { const t = r.tier||1; (tiers[t]||(tiers[t]=[])).push(r); }); + const tierNums = Object.keys(tiers).map(Number).sort((a,b)=>a-b); + + // Build SVG arrow overlay + node grid + let html = ``;
+ // Tier rows
+ tierNums.forEach(t => {
+ html += `
';
+ tree.innerHTML = html;
},
_card(r) {
@@ -1930,15 +2590,26 @@
}
},
+ _costLabel(cost) {
+ if (!cost) return '';
+ const parts = [];
+ if (cost.credits) parts.push(`π°${cost.credits.toLocaleString()}`);
+ if (cost.metal) parts.push(`β${cost.metal.toLocaleString()}`);
+ if (cost.gas) parts.push(`β${cost.gas.toLocaleString()}`);
+ if (cost.crystal) parts.push(`π${cost.crystal.toLocaleString()}`);
+ return parts.join(' ');
+ },
+
_buildingCard(b) {
const now = Date.now();
const inProgress = b.buildQueue && now < b.buildQueue.completesAt;
const pct = inProgress ? Math.min(100, ((now - b.buildQueue.startedAt) / (b.buildQueue.completesAt - b.buildQueue.startedAt)) * 100) : 0;
const secLeft = inProgress ? Math.max(0, Math.round((b.buildQueue.completesAt - now) / 1000)) : 0;
const effect = Object.entries(b.effects || {}).map(([k,v]) => `+${v} ${k.replace(/([A-Z])/g,' $1').toLowerCase()}`).join(', ');
- return `
+
`;
+ });
+ html += 'Tier ${t}
+
+ ${tiers[t].map(r => this._card(r)).join('')}
+
+
+ const costLabel = this._costLabel(b.nextCost);
+ return `
-
+
${b.name}
Level ${b.level} / ${b.maxLevel}
@@ -1947,14 +2618,14 @@
${b.description}
${effect ? `${effect} per level
` : ''}
${inProgress ? `
-
+
` :
b.level < b.maxLevel ? `
+
+
+
+
+
+
+
+
+
Upgrading⦠${secLeft}s
- ${(b.nextCost?.credits||0).toLocaleString()} credits
-
+ ${costLabel}
+
` :
`β Max Level
`
}
@@ -1963,16 +2634,17 @@
_availableCard(b) {
const effect = Object.entries(b.effects || {}).map(([k,v]) => `+${v} ${k.replace(/([A-Z])/g,' $1').toLowerCase()}`).join(', ');
- return `
+ const costLabel = this._costLabel(b.cost);
+ return `
`;
},
@@ -1991,7 +2663,14 @@
const s = pd.stats || {};
const set = (id, val) => { const el = document.getElementById(id); if (el) el.textContent = val; };
set('playerLevelDisplay', s.level || 1);
- set('playerXP', `${(s.experience||0).toLocaleString()} / ${(s.experienceToNextLevel||100).toLocaleString()}`);
+ // GDD Β§3.2: XP_required(L) = 500 Γ L^1.65
+ const xpForLevel = L => Math.floor(500 * Math.pow(L, 1.65));
+ const nextLvl = s.experienceToNextLevel || xpForLevel((s.level||1) + 1);
+ const pct = Math.min(100, Math.round((s.experience||0) / nextLvl * 100));
+ set('playerXP', `${(s.experience||0).toLocaleString()} / ${nextLvl.toLocaleString()} (${pct}%)`);
+ // Update XP bar if present
+ const xpBar = document.getElementById('xpBarFill');
+ if (xpBar) xpBar.style.width = pct + '%';
set('skillPoints', s.skillPoints || 0);
set('totalXP', (s.totalExperience||s.experience||0).toLocaleString());
set('questsCompleted', s.questsCompleted || 0);
@@ -2244,6 +2923,882 @@
};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
${b.name}
${b.description}
${effect ? `${effect}
` : ''}
- ${(b.cost?.credits||0).toLocaleString()} cr
-
+ ${costLabel}
+
@@ -2258,5 +3813,407 @@
π₯ Social
+ +π€ Add Friend
+π¬ Friend Requests (0)
+πΎ Friends (0 online)
++ π Faction Reputation (GDD Β§15.3) + +
++ β Combat Log (GDD Β§9.5) + +
+