Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5cfe865
Refactor Research Tree: Remove Economy, update UI with icons and tool…
El-Magico777 Dec 12, 2025
c859e43
chore: refine tech tooltips and effects
El-Magico777 Dec 13, 2025
2b51407
Clarify tech descriptions and tooltips
El-Magico777 Dec 13, 2025
66a040a
feat: implement structure stacking system with functional multipliers
El-Magico777 Dec 13, 2025
cff23ef
feat: Complete structure stacking system with proper counts and unlim…
El-Magico777 Dec 13, 2025
604033e
refactor: Shorten submarine level 1 name in build menu to 'Diesel Sub'
El-Magico777 Dec 13, 2025
c064032
fix: gate diesel subs behind Sea-1 and allow research labs by default
El-Magico777 Dec 13, 2025
755b029
chore: show tech short description in unlock toast
El-Magico777 Dec 13, 2025
f0cf9d6
ui: move stack chip and swap stack controls
El-Magico777 Dec 13, 2025
4da71bd
feat: cap structure stacking at 25 across client+server\n\n- Add MAX_…
El-Magico777 Dec 13, 2025
20d802a
feat: add multi-priority research system with category-level controls
El-Magico777 Dec 13, 2025
b2a7f92
Update tests for new tech tree structure (Land/Sea/Air/Nuclear)
El-Magico777 Dec 13, 2025
41efa56
Remove dead code: policy directives, insurance, and scorched earth
El-Magico777 Dec 14, 2025
44ddd80
chore: remove economy category from HelpModal tech tree
El-Magico777 Dec 14, 2025
4d7d16a
fix: paratroopers not showing in radial menu after researching Air-1
El-Magico777 Dec 14, 2025
9074d01
feat: replace Bombers tab with radial menu control and enable auto-bo…
El-Magico777 Dec 14, 2025
6761394
feat: make disabled radial menu options visible with color-coded states
El-Magico777 Dec 14, 2025
571bf4c
UI: Diplomacy relation icons
El-Magico777 Dec 14, 2025
7e80e55
UI: Remove Diplomacy tab from ControlPanel2
El-Magico777 Dec 14, 2025
925f5da
Fix: Diplomacy icon sizing and filtering
El-Magico777 Dec 14, 2025
18f1438
perf: Optimize cluster calculation with DFS and zero-allocation patterns
El-Magico777 Dec 14, 2025
2701cf1
feat: Add lobby chat with vertical side panel layout and profanity fi…
El-Magico777 Dec 14, 2025
7a7079b
feat(ui): Remove Trade tab and migrate Trade Demand to Build tab toolbar
El-Magico777 Dec 14, 2025
59321e4
fix: Remove viewport clipping from TerritoryLayer putImageData to fix…
El-Magico777 Dec 14, 2025
ac0d2d7
Fix infinite gold not applying to fighter jets and airfield bomber up…
El-Magico777 Dec 14, 2025
a8daff6
Improve unit selection grid layout in singleplayer lobby
El-Magico777 Dec 14, 2025
a341f91
feat(artillery): implement land-based Artillery unit system with GPU …
El-Magico777 Dec 15, 2025
04b536e
feat(artillery): integrate artillery into tech tree with auto-upgrade…
El-Magico777 Dec 18, 2025
f6731fb
feat(ui): add artillery to player info overlay
El-Magico777 Dec 18, 2025
93577e8
feat(hotkeys): add artillery hotkey with default key '4'
El-Magico777 Dec 18, 2025
f719dde
docs(help): add artillery to help modal units tab
El-Magico777 Dec 18, 2025
c7c7ffc
feat(combat): add warship targeting for coastal artillery
El-Magico777 Dec 18, 2025
7cd3174
Merge PR #158: Research tree redesign (stacking and cleanup follow-ons)
El-Magico777 Dec 18, 2025
2da0660
Merge PR #159: replace Bombers tab with radial menu control and enabl…
El-Magico777 Dec 18, 2025
daeb5f4
Merge PR #160: make disabled radial menu options visible with color-c…
El-Magico777 Dec 18, 2025
385828c
Merge PR #161: Remove Diplomacy Tab and Add Map-Based Diplomacy Icons
El-Magico777 Dec 18, 2025
55f8142
Merge PR #164: Remove Trade tab and migrate Trade Demand to Build tab…
El-Magico777 Dec 18, 2025
38e5b4f
Merge PR #165: Remove viewport clipping from TerritoryLayer putImageD…
El-Magico777 Dec 18, 2025
b0acca9
Merge PR #168: Artillery Unit System - Complete Feature Implementation
El-Magico777 Dec 18, 2025
23a6de3
Merge PR #140: add Tech Unlocked mode to public lobby rotation
El-Magico777 Dec 18, 2025
0b07055
Merge PR #162:
El-Magico777 Dec 18, 2025
5eae64c
Merge PR #163: Add lobby chat with vertical side panel layout and pro…
El-Magico777 Dec 18, 2025
05f569e
Merge PR #166: Fix infinite gold not applying to fighter jets and air…
El-Magico777 Dec 18, 2025
59c5243
Merge PR #167: Improve unit selection grid layout in singleplayer lobby
El-Magico777 Dec 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default {
"^src/client/InputHandler$": "<rootDir>/tests/__mocks__/InputHandler.ts",
"\\.(svg|png|jpe?g|gif|webp)$": "<rootDir>/tests/__mocks__/fileMock.ts",
"^nanoid$": "<rootDir>/tests/__mocks__/nanoid.cjs",
"^bad-words$": "<rootDir>/tests/__mocks__/bad-words.ts",
},
transform: {
"^.+\\.tsx?$": ["@swc/jest"],
Expand Down
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"@opentelemetry/sdk-metrics": "^2.0.0",
"@opentelemetry/semantic-conventions": "^1.32.0",
"@opentelemetry/winston-transport": "^0.11.0",
"bad-words": "^4.0.0",
"colord": "^2.9.3",
"colorjs.io": "^0.5.2",
"dompurify": "^3.1.7",
Expand All @@ -127,8 +128,8 @@
"prom-client": "^15.1.3",
"protobufjs": "^7.3.2",
"pureimage": "^0.4.13",
"sharp": "^0.34.2",
"seedrandom": "^3.0.5",
"sharp": "^0.34.2",
"ts-node": "^10.9.2",
"uuid": "^11.1.0",
"winston": "^3.17.0",
Expand Down
Binary file added proprietary/images/artillery-battery.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/research/air.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/research/land.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/research/nuclear.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/research/sea.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 22 additions & 2 deletions resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"build_port_desc": "Can only be built near water. Allows building Cruisers. Automatically sends cargo ships between ports of your country and other countries (except when trade is stopped), giving gold to both sides. Trade stops automatically when you attack or are attacked by a player. It resumes after 5 minutes or if you become allies. You can manually toggle trading with \"Stop trading\" or \"Start trading\".",
"build_warship": "Cruiser",
"build_warship_desc": "Patrols in an area, capturing enemy cargo ships and destroying their Boats (transport ships) and Cruisers. Spawns from the nearest Port and patrols the area you first clicked to build it. You can control Cruisers by attack-clicking on them (see action Attack under Hotkeys) and then attack-clicking the new area you want them to move to.",
"build_artillery": "Artillery",
"build_artillery_desc": "Land-based heavy artillery that patrols an area and bombards enemy structures within range. Spawns from the nearest Factory and patrols the area you first clicked to build it. You can redirect Artillery by attack-clicking on them and then attack-clicking the new area you want them to move to.",
"build_silo": "Missile Silo",
"build_silo_desc": "Allows launching missiles.",
"build_sam": "SAM Launcher",
Expand Down Expand Up @@ -210,7 +212,9 @@
"teams_Duos": "Duos (teams of 2)",
"teams_Trios": "Trios (teams of 3)",
"teams_Quads": "Quads (teams of 4)",
"teams": "{num} teams"
"teams": "{num} teams",
"tech_unlocked": "Tech Unlocked",
"tech_unlocked_tooltip": "All technologies unlocked from the start!"
},
"username": {
"enter_username": "Enter your username",
Expand Down Expand Up @@ -239,6 +243,7 @@
"infinite_gold_tooltip": "Never run out of gold",
"infinite_troops": "Infinite Troops",
"infinite_troops_tooltip": "Unlimited troop capacity",
"enable_chat": "Enable Lobby Chat",
"peace_timer": "Protected Start",
"peace_timer_tooltip": "Players cannot attack each other for this duration at game start",
"peace_timer_none": "None",
Expand Down Expand Up @@ -291,6 +296,7 @@
"fighter_jet": "Fast air unit for intercepting bombers and scouting.",
"warship": "Patrols in an area, capturing enemy cargo ships and destroying their Boats and Cruisers.",
"submarine": "Stealthy naval unit. Can launch nukes if researched. Invisible to enemies unless they have detection.",
"artillery": "Land-based heavy artillery that patrols an area and bombards enemy structures within range. Spawns from the nearest Factory.",
"city": "Increases your max population. Useful when you can't expand your territory.",
"port": "Allows building Cruisers and Submarines. Automatically sends cargo ships to trade with other players.",
"airfield": "Automatically deploys bombers that fly out to strike enemy structures then return to base.",
Expand All @@ -310,6 +316,7 @@
"defense_post": "Defense Post",
"port": "Port",
"warship": "Cruiser",
"artillery": "Artillery",
"submarine": "Submarine",
"missile_silo": "Missile Silo",
"sam_launcher": "SAM Launcher",
Expand Down Expand Up @@ -430,6 +437,8 @@
"build_warship_desc": "Set the hotkey to build a Cruiser.",
"build_submarine": "Build Submarine",
"build_submarine_desc": "Set the hotkey to build a Submarine.",
"build_artillery": "Build Artillery",
"build_artillery_desc": "Set the hotkey to build Artillery.",
"reset": "Reset",
"unbind": "Unbind",
"on": "On",
Expand Down Expand Up @@ -571,6 +580,7 @@
"missile_launchers": "Missile launchers",
"sams": "SAMs",
"warships": "Cruisers",
"artillery": "Artillery",
"fighter_jets": "Fighter Jets",
"health": "Health",
"attitude": "Attitude",
Expand Down Expand Up @@ -699,7 +709,10 @@
"international_trade_origin": "Your cargo truck successfully delivered goods to {destinationName}. You received {goldAmount} gold.",
"international_trade_destination": "A cargo truck from {originName} arrived. You received {goldAmount} gold.",
"insurance_refund": "Insurance refund {amount} gold.",
"insurance_refund_conquest": "Insurance refund {amount} gold for conquered structure."
"insurance_refund_conquest": "Insurance refund {amount} gold for conquered structure.",
"artillery_out_of_range_1": "Artillery is out of range (max 60 tiles for level 1)",
"artillery_out_of_range_2": "Artillery is out of range (max 75 tiles for level 2)",
"artillery_out_of_range_3": "Artillery is out of range (max 90 tiles for level 3)"
},
"research_tree": {
"title": "Research Tree",
Expand Down Expand Up @@ -1023,6 +1036,13 @@
"desc": "'<strong>'Requirement:'</strong>' Port<br />Generates gold by trading between your ports and other players' ports (not between your own ports). Passive income source. '<strong>'Tip:'</strong>' Protect trade routes from pirates and enemy submarines."
}
},
"land": {
"title": "Land Units",
"artillery": {
"name": "Artillery",
"desc": "'<strong>'Requirement:'</strong>' Factory<br />Land-based heavy artillery that patrols territory and bombards enemy structures within range. Spawns from nearest Factory. '<strong>'Range:'</strong>' 60/75/90 tiles (levels 1/2/3). '<strong>'Upgrades:'</strong>' Higher levels increase range, damage, and durability. '<strong>'Tip:'</strong>' Excellent for softening enemy defenses before ground assault."
}
},
"air": {
"title": "Air Units",
"bomber": {
Expand Down
38 changes: 28 additions & 10 deletions src/client/HelpModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,13 +390,6 @@ export class HelpModal extends LitElement {
altKey: "ui_guide.command_center_economy_alt",
icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>`,
},
{
titleKey: "ui_guide.command_center_trade_title",
descKey: "ui_guide.command_center_trade_desc",
img: "/images/HelpModalScreenshots/CC-Trade.png",
altKey: "ui_guide.command_center_trade_alt",
icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 21c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1 .6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/><path d="M19.38 20A11.6 11.6 0 0 0 21 14l-9-4-9 4c0 2.9.9 5.8 2.5 8"/><path d="M12 10V4"/><path d="M8 8v2"/><path d="M16 8v2"/></svg>`,
},
{
titleKey: "ui_guide.command_center_diplomacy_title",
descKey: "ui_guide.command_center_diplomacy_desc",
Expand Down Expand Up @@ -889,6 +882,15 @@ export class HelpModal extends LitElement {
},
];

const landUnits = [
{
nameKey: "units.land.artillery.name",
iconClass: "artillery-icon",
hotkey: "4",
descKey: "units.land.artillery.desc",
},
];

const airUnits = [
{
nameKey: "units.air.bomber.name",
Expand Down Expand Up @@ -978,6 +980,25 @@ export class HelpModal extends LitElement {
</table>
</div>

<div class="help-subsection">
<div class="text-xl font-bold mb-3 mt-6">
${this.t("units.land.title")}
</div>
<table class="help-table">
<thead>
<tr>
<th>${this.t("labels.name")}</th>
<th class="icon-col">${this.t("labels.icon")}</th>
<th>${this.t("labels.hotkey")}</th>
<th>${this.t("labels.description")}</th>
</tr>
</thead>
<tbody class="text-left">
${renderUnitRows(landUnits)}
</tbody>
</table>
</div>

<div class="help-subsection">
<div class="text-xl font-bold mb-3 mt-6">
${this.t("units.air.title")}
Expand Down Expand Up @@ -1153,7 +1174,6 @@ export class HelpModal extends LitElement {
Sea: [],
Air: [],
Nuclear: [],
Economy: [],
};

for (const node of nodes) {
Expand Down Expand Up @@ -1188,15 +1208,13 @@ export class HelpModal extends LitElement {
Sea: this.t("tech_tree.categories.sea"),
Air: this.t("tech_tree.categories.air"),
Nuclear: this.t("tech_tree.categories.nuclear"),
Economy: this.t("tech_tree.categories.economy"),
};

const categoryDescriptions: Record<string, string> = {
Land: this.t("tech_tree.categories.land_desc"),
Sea: this.t("tech_tree.categories.sea_desc"),
Air: this.t("tech_tree.categories.air_desc"),
Nuclear: this.t("tech_tree.categories.nuclear_desc"),
Economy: this.t("tech_tree.categories.economy_desc"),
};

return html`
Expand Down
77 changes: 76 additions & 1 deletion src/client/HostLobbyModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
ClientInfo,
GameConfig,
GameInfo,
LobbyMessage,
TeamCountConfig,
} from "../core/Schemas";
import {
Expand All @@ -31,6 +32,7 @@ import { generateID } from "../core/Util";
import "./components/baseComponents/Modal";
import "./components/Difficulties";
import { DifficultyDescription } from "./components/Difficulties";
import "./components/LobbyChatPanel";
import "./components/Maps";
import type { JoinLobbyEvent } from "./Main";
import { renderUnitTypeOptions } from "./utilities/RenderUnitTypeOptions";
Expand Down Expand Up @@ -77,6 +79,8 @@ export class HostLobbyModal extends LitElement {
@state() private playerTeamAssignments: Record<string, number | null> = {};
@state() private updatingTeamForClients: Set<string> = new Set();
@state() private showUnitSettings = false; // Closed by default for Host
@state() private chatEnabled: boolean = false;
@state() private lobbyMessages: LobbyMessage[] = [];

private playersInterval: NodeJS.Timeout | null = null;
private botsUpdateTimer: number | null = null;
Expand All @@ -97,6 +101,9 @@ export class HostLobbyModal extends LitElement {
height: 75vh;
overflow: hidden;
}
.sp-layout.with-chat {
grid-template-columns: 1fr 1fr 280px; /* Add chat column */
}

@media (max-width: 1024px) {
.sp-layout {
Expand All @@ -105,11 +112,52 @@ export class HostLobbyModal extends LitElement {
max-height: 85vh;
overflow-y: auto;
}
.sp-layout.with-chat {
grid-template-columns: 1fr;
}
.sp-map-col {
height: 40vh;
}
}

/* Chat Column (Right) */
.sp-chat-col {
background: rgba(0, 0, 0, 0.2);
border-radius: 12px;
padding: 16px;
display: flex;
flex-direction: column;
max-height: 75vh;
overflow: hidden;
}
.sp-chat-col .sp-title {
margin-bottom: 12px;
flex-shrink: 0;
}
.sp-chat-col lobby-chat-panel {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.sp-chat-col .lcp-container {
flex: 1;
display: flex;
flex-direction: column;
max-height: none;
height: 100%;
min-height: 0;
}
.sp-chat-col .lcp-messages {
flex: 1;
height: auto;
min-height: 200px;
overflow-y: auto;
}
.sp-chat-col .lcp-input-row {
flex-shrink: 0;
}

/* Map Column (Left) */
.sp-map-col {
background: rgba(0, 0, 0, 0.2);
Expand Down Expand Up @@ -590,7 +638,7 @@ export class HostLobbyModal extends LitElement {
max-height="85vh"
content-overflow="hidden"
>
<div class="sp-layout">
<div class="sp-layout ${this.chatEnabled ? "with-chat" : ""}">
<!-- LEFT COLUMN: Maps -->
<div class="sp-map-col">
<!-- Lobby ID Header -->
Expand Down Expand Up @@ -944,6 +992,14 @@ export class HostLobbyModal extends LitElement {
"host_modal.infinite_troops",
this.handleInfiniteTroopsChange,
)}
${this.renderToggle(
this.chatEnabled,
"host_modal.enable_chat",
(e: any) => {
this.chatEnabled = e.target.checked;
this.putGameConfig();
},
)}
</div>
</div>

Expand Down Expand Up @@ -1014,6 +1070,21 @@ export class HostLobbyModal extends LitElement {
</div>
</div>
<!-- End Right Col -->

<!-- Chat Column (Third Col) -->
${this.chatEnabled
? html`<div class="sp-chat-col">
<div class="sp-title">${translateText("chat")}</div>
<lobby-chat-panel
.messages=${this.lobbyMessages}
.clientID=${this.lobbyCreatorClientID}
.gameID=${this.lobbyId}
.username=${(
document.querySelector("username-input") as any
)?.getCurrentUsername?.() ?? "Host"}
></lobby-chat-panel>
</div>`
: nothing}
</div>
</o-modal>
`;
Expand Down Expand Up @@ -1514,6 +1585,7 @@ export class HostLobbyModal extends LitElement {
peaceTimerDurationMinutes: this.selectedPeaceTimerDuration,
startingGold: this.startingGold,
goldMultiplier: this.goldMultiplier,
chatEnabled: this.chatEnabled,
} satisfies Partial<GameConfig>),
},
);
Expand Down Expand Up @@ -1628,6 +1700,9 @@ export class HostLobbyModal extends LitElement {
if (data.gameConfig?.researchAllTechs !== undefined) {
this.researchAllTechs = Boolean(data.gameConfig.researchAllTechs);
}

// Update lobby messages
this.lobbyMessages = data.messages ?? [];
});
}

Expand Down
Loading
Loading