mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-21 15:25:07 +00:00
Merge branch 'main' into local-attack
This commit is contained in:
@@ -755,6 +755,32 @@ class Client {
|
||||
if (decodedHash.startsWith("#refresh")) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
// Handle requeue parameter for ranked matchmaking
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if (searchParams.has("requeue")) {
|
||||
// Remove only the requeue parameter, preserving other params and hash
|
||||
searchParams.delete("requeue");
|
||||
const newUrl =
|
||||
window.location.pathname +
|
||||
(searchParams.toString() ? "?" + searchParams.toString() : "") +
|
||||
window.location.hash;
|
||||
history.replaceState(null, "", newUrl);
|
||||
// Wait for matchmaking button to be defined, then trigger its click handler
|
||||
// This goes through username validation instead of bypassing it
|
||||
customElements.whenDefined("matchmaking-button").then(() => {
|
||||
const matchmakingButton = document.querySelector(
|
||||
"matchmaking-button button",
|
||||
) as HTMLButtonElement | null;
|
||||
if (matchmakingButton) {
|
||||
matchmakingButton.click();
|
||||
} else {
|
||||
console.warn(
|
||||
"Requeue requested, but matchmaking button not found in DOM.",
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async handleJoinLobby(event: CustomEvent<JoinLobbyEvent>) {
|
||||
|
||||
@@ -320,7 +320,7 @@ export class MatchmakingButton extends LitElement {
|
||||
window.showPage?.("page-account");
|
||||
}
|
||||
|
||||
private open() {
|
||||
public open() {
|
||||
this.matchmakingModal?.open();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@ export class GameLeftSidebar extends LitElement implements Layer {
|
||||
private isLeaderboardShow = false;
|
||||
@state()
|
||||
private isTeamLeaderboardShow = false;
|
||||
@state()
|
||||
private isVisible = false;
|
||||
@state()
|
||||
private isPlayerTeamLabelVisible = false;
|
||||
@state()
|
||||
private playerTeam: string | null = null;
|
||||
|
||||
private playerColor: Colord = new Colord("#FFFFFF");
|
||||
@@ -59,7 +62,7 @@ export class GameLeftSidebar extends LitElement implements Layer {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
if (!this.game.inSpawnPhase()) {
|
||||
if (!this.game.inSpawnPhase() && this.isPlayerTeamLabelVisible) {
|
||||
this.isPlayerTeamLabelVisible = false;
|
||||
this.requestUpdate();
|
||||
}
|
||||
@@ -91,10 +94,65 @@ export class GameLeftSidebar extends LitElement implements Layer {
|
||||
this.isVisible ? "translate-x-0" : "hidden"
|
||||
}`}
|
||||
>
|
||||
<div class="flex items-center gap-4 xl:gap-6 text-white">
|
||||
<div
|
||||
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
|
||||
@click=${this.toggleLeaderboard}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@keydown=${(e: KeyboardEvent) => {
|
||||
if (e.key === "Enter" || e.key === " " || e.code === "Space") {
|
||||
e.preventDefault();
|
||||
this.toggleLeaderboard();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src=${this.isLeaderboardShow
|
||||
? leaderboardSolidIcon
|
||||
: leaderboardRegularIcon}
|
||||
alt=${translateText("help_modal.icon_alt_player_leaderboard") ||
|
||||
"Player Leaderboard Icon"}
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
</div>
|
||||
${this.isTeamGame
|
||||
? html`
|
||||
<div
|
||||
class="cursor-pointer p-0.5 bg-gray-700/50 hover:bg-gray-600 border rounded-md border-slate-500 transition-colors"
|
||||
@click=${this.toggleTeamLeaderboard}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@keydown=${(e: KeyboardEvent) => {
|
||||
if (
|
||||
e.key === "Enter" ||
|
||||
e.key === " " ||
|
||||
e.code === "Space"
|
||||
) {
|
||||
e.preventDefault();
|
||||
this.toggleTeamLeaderboard();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src=${this.isTeamLeaderboardShow
|
||||
? teamSolidIcon
|
||||
: teamRegularIcon}
|
||||
alt=${translateText(
|
||||
"help_modal.icon_alt_team_leaderboard",
|
||||
) || "Team Leaderboard Icon"}
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
${this.isPlayerTeamLabelVisible
|
||||
? html`
|
||||
<div
|
||||
class="flex items-center w-full h-8 lg:h-10 text-white py-1 lg:p-2"
|
||||
class="flex items-center w-full text-white"
|
||||
@contextmenu=${(e: Event) => e.preventDefault()}
|
||||
>
|
||||
${translateText("help_modal.ui_your_team")}
|
||||
@@ -108,39 +166,8 @@ export class GameLeftSidebar extends LitElement implements Layer {
|
||||
`
|
||||
: null}
|
||||
<div
|
||||
class=${`flex items-center gap-2 text-white ${
|
||||
this.isLeaderboardShow || this.isTeamLeaderboardShow ? "mb-2" : ""
|
||||
}`}
|
||||
class=${`block lg:flex flex-wrap ${this.isLeaderboardShow && this.isTeamLeaderboardShow ? "gap-2" : ""}`}
|
||||
>
|
||||
<div class="cursor-pointer" @click=${this.toggleLeaderboard}>
|
||||
<img
|
||||
src=${this.isLeaderboardShow
|
||||
? leaderboardSolidIcon
|
||||
: leaderboardRegularIcon}
|
||||
alt="treeIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
</div>
|
||||
${this.isTeamGame
|
||||
? html`
|
||||
<div
|
||||
class="cursor-pointer"
|
||||
@click=${this.toggleTeamLeaderboard}
|
||||
>
|
||||
<img
|
||||
src=${this.isTeamLeaderboardShow
|
||||
? teamSolidIcon
|
||||
: teamRegularIcon}
|
||||
alt="treeIcon"
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
</div>
|
||||
`
|
||||
: null}
|
||||
</div>
|
||||
<div class="block lg:flex flex-wrap gap-2">
|
||||
<leader-board .visible=${this.isLeaderboardShow}></leader-board>
|
||||
<team-stats
|
||||
class="flex-1"
|
||||
|
||||
@@ -177,7 +177,7 @@ export class Leaderboard extends LitElement implements Layer {
|
||||
}
|
||||
return html`
|
||||
<div
|
||||
class="max-h-[35vh] overflow-y-auto text-white text-xs md:text-xs lg:text-sm md:max-h-[50vh] ${this
|
||||
class="max-h-[35vh] overflow-y-auto text-white text-xs md:text-xs lg:text-sm md:max-h-[50vh] mt-2 ${this
|
||||
.visible
|
||||
? ""
|
||||
: "hidden"}"
|
||||
@@ -265,7 +265,9 @@ export class Leaderboard extends LitElement implements Layer {
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="mt-1 px-1.5 py-0.5 md:px-2 md:py-0.5 text-xs md:text-xs lg:text-sm border border-white/20 hover:bg-white/10 text-white mx-auto block"
|
||||
class="mt-1 px-1.5 pb-0.5 md:px-2 text-xs md:text-xs lg:text-sm
|
||||
border rounded-md border-slate-500 transition-colors
|
||||
text-white mx-auto block hover:bg-white/10"
|
||||
@click=${() => {
|
||||
this.showTopFive = !this.showTopFive;
|
||||
this.updateLeaderboard();
|
||||
|
||||
@@ -132,7 +132,7 @@ export class TeamStats extends LitElement implements Layer {
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="max-h-[30vh] overflow-y-auto grid bg-slate-800/70 w-full text-white text-xs md:text-sm"
|
||||
class="max-h-[30vh] overflow-y-auto grid bg-slate-800/70 w-full text-white text-xs md:text-sm mt-2"
|
||||
@contextmenu=${(e: MouseEvent) => e.preventDefault()}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "../../../client/Utils";
|
||||
import { ColorPalette, Pattern } from "../../../core/CosmeticSchemas";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { RankedType } from "../../../core/game/Game";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { getUserMe } from "../../Api";
|
||||
@@ -37,6 +38,9 @@ export class WinModal extends LitElement implements Layer {
|
||||
@state()
|
||||
private isWin = false;
|
||||
|
||||
@state()
|
||||
private isRankedGame = false;
|
||||
|
||||
@state()
|
||||
private patternContent: TemplateResult | null = null;
|
||||
|
||||
@@ -75,11 +79,21 @@ export class WinModal extends LitElement implements Layer {
|
||||
>
|
||||
${translateText("win_modal.exit")}
|
||||
</button>
|
||||
${this.isRankedGame
|
||||
? html`
|
||||
<button
|
||||
@click=${this._handleRequeue}
|
||||
class="flex-1 px-3 py-3 text-base cursor-pointer bg-purple-600 text-white border-0 rounded-sm transition-all duration-200 hover:bg-purple-500 hover:-translate-y-px active:translate-y-px"
|
||||
>
|
||||
${translateText("win_modal.requeue")}
|
||||
</button>
|
||||
`
|
||||
: null}
|
||||
<button
|
||||
@click=${this.hide}
|
||||
class="flex-1 px-3 py-3 text-base cursor-pointer bg-blue-500/60 text-white border-0 rounded-sm transition-all duration-200 hover:bg-blue-500/80 hover:-translate-y-px active:translate-y-px"
|
||||
>
|
||||
${this.isWin
|
||||
${this.game.myPlayer()?.isAlive()
|
||||
? translateText("win_modal.keep")
|
||||
: translateText("win_modal.spectate")}
|
||||
</button>
|
||||
@@ -251,6 +265,9 @@ export class WinModal extends LitElement implements Layer {
|
||||
async show() {
|
||||
crazyGamesSDK.gameplayStop();
|
||||
await this.loadPatternContent();
|
||||
// Check if this is a ranked game
|
||||
this.isRankedGame =
|
||||
this.game.config().gameConfig().rankedType === RankedType.OneVOne;
|
||||
this.isVisible = true;
|
||||
this.requestUpdate();
|
||||
setTimeout(() => {
|
||||
@@ -270,6 +287,12 @@ export class WinModal extends LitElement implements Layer {
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
private _handleRequeue() {
|
||||
this.hide();
|
||||
// Navigate to homepage and open matchmaking modal
|
||||
window.location.href = "/?requeue";
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
tick() {
|
||||
|
||||
@@ -118,6 +118,7 @@ export enum GameMapType {
|
||||
Didier = "Didier",
|
||||
DidierFrance = "Didier France",
|
||||
AmazonRiver = "Amazon River",
|
||||
Yenisei = "Yenisei",
|
||||
}
|
||||
|
||||
export type GameMapName = keyof typeof GameMapType;
|
||||
@@ -165,6 +166,7 @@ export const mapCategories: Record<string, GameMapType[]> = {
|
||||
GameMapType.TwoLakes,
|
||||
GameMapType.StraitOfHormuz,
|
||||
GameMapType.AmazonRiver,
|
||||
GameMapType.Yenisei,
|
||||
],
|
||||
fantasy: [
|
||||
GameMapType.Pangaea,
|
||||
|
||||
@@ -988,7 +988,10 @@ export class PlayerImpl implements Player {
|
||||
}
|
||||
|
||||
const cost = this.mg.unitInfo(unitType).cost(this.mg, this);
|
||||
if (!this.isAlive() || this.gold() < cost) {
|
||||
if (
|
||||
unitType !== UnitType.MIRVWarhead &&
|
||||
(!this.isAlive() || this.gold() < cost)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
switch (unitType) {
|
||||
|
||||
@@ -66,6 +66,7 @@ const frequency: Partial<Record<GameMapName, number>> = {
|
||||
AmazonRiver: 3,
|
||||
Sierpinski: 10,
|
||||
TheBox: 3,
|
||||
Yenisei: 6,
|
||||
};
|
||||
|
||||
interface MapWithMode {
|
||||
|
||||
Reference in New Issue
Block a user