update win condtion: 80% non fallout tiles

This commit is contained in:
Evan
2025-01-24 08:41:19 -08:00
parent d009ef925c
commit 7a2f4210ed
11 changed files with 275 additions and 216 deletions
+13 -3
View File
@@ -3,7 +3,6 @@ import { NameLayer } from "./layers/NameLayer";
import { TerrainLayer } from "./layers/TerrainLayer";
import { TerritoryLayer } from "./layers/TerritoryLayer";
import { ClientID } from "../../core/Schemas";
import { UILayer } from "./layers/UILayer";
import { EventBus } from "../../core/EventBus";
import { TransformHandler } from "./TransformHandler";
import { Layer } from "./layers/Layer";
@@ -20,6 +19,8 @@ import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
import { consolex } from "../../core/Consolex";
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
import { GameView } from "../../core/game/GameView";
import { WinModal } from "./layers/WinModal";
import { SpawnTimer } from "./layers/SpawnTimer";
export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventBus: EventBus, clientID: ClientID): GameRenderer {
@@ -75,18 +76,27 @@ export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventB
playerInfo.game = game
const winModel = document.querySelector('win-modal') as WinModal
if (!(playerInfo instanceof WinModal)) {
console.error('win modal not found')
}
winModel.clientID = clientID
winModel.game = game
const layers: Layer[] = [
new TerrainLayer(game),
new TerritoryLayer(game, eventBus),
new StructureLayer(game, eventBus),
new UnitLayer(game, eventBus, clientID),
new NameLayer(game, game.config().theme(), transformHandler, clientID),
new UILayer(eventBus, game, clientID, transformHandler),
eventsDisplay,
new RadialMenu(eventBus, game, transformHandler, clientID, emojiTable as EmojiTable, buildMenu, uiState),
new SpawnTimer(game, transformHandler),
leaderboard,
controlPanel,
playerInfo
playerInfo,
winModel
]
return new GameRenderer(game, eventBus, canvas, transformHandler, uiState, layers)
+34
View File
@@ -0,0 +1,34 @@
import { GameView } from '../../../core/game/GameView';
import { TransformHandler } from '../TransformHandler';
import { Layer } from './Layer';
export class SpawnTimer implements Layer {
constructor(private game: GameView, private transformHandler: TransformHandler) { }
init() {
}
tick() {
}
shouldTransform(): boolean {
return false
}
renderLayer(context: CanvasRenderingContext2D) {
if (!this.game.inSpawnPhase()) {
return
}
const barHeight = 15;
const barBackgroundWidth = this.transformHandler.width();
const ratio = this.game.ticks() / this.game.config().numSpawnPhaseTurns()
// Draw bar background
context.fillStyle = 'rgba(0, 0, 0, 0.5)';
context.fillRect(0, 0, barBackgroundWidth, barHeight);
context.fillStyle = 'rgba(0, 128, 255, 0.7)';
context.fillRect(0, 0, barBackgroundWidth * ratio, barHeight);
}
}
-184
View File
@@ -1,184 +0,0 @@
import { EventBus } from "../../../core/EventBus";
import { WinEvent } from "../../../core/execution/WinCheckExecution";
import { Player } from "../../../core/game/Game";
import { ClientID } from "../../../core/Schemas";
import { Layer } from "./Layer";
import { TransformHandler } from "../TransformHandler";
import { consolex } from "../../../core/Consolex";
import { GameView } from "../../../core/game/GameView";
interface MenuOption {
label: string;
action: () => void;
}
export class UILayer implements Layer {
private exitButton: HTMLButtonElement;
private winModal: HTMLElement | null = null;
private customMenu = document.getElementById('customMenu');
constructor(
private eventBus: EventBus,
private game: GameView,
private clientID: ClientID,
private transformHandler: TransformHandler
) {
}
renderLayer(context: CanvasRenderingContext2D) {
if (!this.game.inSpawnPhase()) {
return
}
const barHeight = 15;
const barBackgroundWidth = this.transformHandler.width();
const ratio = this.game.ticks() / this.game.config().numSpawnPhaseTurns()
// Draw bar background
context.fillStyle = 'rgba(0, 0, 0, 0.5)';
context.fillRect(0, 0, barBackgroundWidth, barHeight);
context.fillStyle = 'rgba(0, 128, 255, 0.7)';
context.fillRect(0, 0, barBackgroundWidth * ratio, barHeight);
}
shouldTransform(): boolean {
return false
}
tick() {
}
init() {
this.createWinModal()
this.initRightClickMenu()
this.eventBus.on(WinEvent, (e) => this.onWinEvent(e))
}
initRightClickMenu() {
if (!this.customMenu) {
consolex.error('Custom menu not found');
return;
}
document.addEventListener('click', () => {
this.customMenu!.style.display = 'none';
});
const menuItems = this.customMenu.querySelectorAll('li');
menuItems.forEach(item => {
item.addEventListener('click', () => {
alert(`You clicked: ${item.textContent}`);
this.customMenu!.style.display = 'none';
});
});
}
createWinModal() {
consolex.log("Creating win modal");
this.winModal = document.createElement('div');
this.winModal.style.cssText = `
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
border: 2px solid black;
border-radius: 10px;
z-index: 2000;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
`;
const content = document.createElement('div');
const title = document.createElement('h2');
title.textContent = 'Game Over';
title.id = 'winTitle';
title.style.marginTop = '0';
const message = document.createElement('p');
message.id = 'winMessage';
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.justifyContent = 'space-between';
buttonContainer.style.marginTop = '20px';
const exitButton = document.createElement('button');
exitButton.textContent = 'Exit Game';
exitButton.onclick = () => this.exitGame();
this.styleButton(exitButton);
const continueButton = document.createElement('button');
continueButton.textContent = 'Keep Playing';
continueButton.onclick = () => this.closeWinModal();
this.styleButton(continueButton);
buttonContainer.appendChild(exitButton);
buttonContainer.appendChild(continueButton);
content.appendChild(title);
content.appendChild(message);
content.appendChild(buttonContainer);
this.winModal.appendChild(content);
document.body.appendChild(this.winModal);
consolex.log("Win modal appended to body");
}
styleButton(button: HTMLButtonElement) {
button.style.cssText = `
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #4A90E2;
color: white;
border: none;
border-radius: 5px;
transition: background-color 0.3s;
`;
button.onmouseover = () => button.style.backgroundColor = '#3A7BCE';
button.onmouseout = () => button.style.backgroundColor = '#4A90E2';
}
onWinEvent(event: WinEvent) {
consolex.log(`${event.winner.name()} won the game!!}`)
this.showWinModal(event.winner)
}
showWinModal(winner: Player) {
if (this.winModal) {
const message = this.winModal.querySelector('#winMessage');
if (message) {
message.textContent = `${winner.name()} won the game!`;
}
const title = this.winModal.querySelector('#winTitle')
if (winner.clientID() == this.clientID) {
title.textContent = 'You Won!!!'
} else {
title.textContent = 'You Lost!!!'
}
this.winModal.style.display = 'block';
}
}
closeWinModal() {
if (this.winModal) {
this.winModal.style.display = 'none';
}
}
exitGame() {
this.closeWinModal();
window.location.reload();
}
}
+167
View File
@@ -0,0 +1,167 @@
import { LitElement, html, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { Player } from '../../../core/game/Game';
import { ClientID } from '../../../core/Schemas';
import { GameView, PlayerView } from '../../../core/game/GameView';
import { Layer } from './Layer';
import { GameUpdateType } from '../../../core/game/GameUpdates';
@customElement('win-modal')
export class WinModal extends LitElement implements Layer {
public clientID: ClientID
public game: GameView
private winner: PlayerView
@state()
isVisible = false
static styles = css`
:host {
display: block;
}
.modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(30, 30, 30, 0.7);
padding: 25px;
border-radius: 10px;
z-index: 9999;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
color: white;
width: 300px;
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
}
.modal.visible {
display: block;
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translate(-50%, -48%);
}
to {
opacity: 1;
transform: translate(-50%, -50%);
}
}
h2 {
margin: 0 0 15px 0;
font-size: 24px;
text-align: center;
color: white;
}
p {
margin: 0 0 20px 0;
text-align: center;
background-color: rgba(0, 0, 0, 0.3);
padding: 10px;
border-radius: 5px;
}
.button-container {
display: flex;
justify-content: space-between;
gap: 10px;
}
button {
flex: 1;
padding: 12px;
font-size: 16px;
cursor: pointer;
background: rgba(0, 150, 255, 0.6);
color: white;
border: none;
border-radius: 5px;
transition: background-color 0.2s ease, transform 0.1s ease;
}
button:hover {
background: rgba(0, 150, 255, 0.8);
transform: translateY(-1px);
}
button:active {
transform: translateY(1px);
}
@media (max-width: 768px) {
.modal {
width: 90%;
max-width: 300px;
padding: 20px;
}
h2 {
font-size: 20px;
}
button {
padding: 10px;
font-size: 14px;
}
}
`;
render() {
if (!this.winner) return null;
const isWinner = this.winner.clientID() === this.clientID;
const title = isWinner ? 'You Won!!!' : 'You Lost!!!';
const message = `${this.winner.name()} won the game!`;
return html`
<div class="modal ${this.isVisible ? 'visible' : ''}">
<h2>${title}</h2>
<p>${message}</p>
<div class="button-container">
<button @click=${this._handleExit}>Exit Game</button>
<button @click=${this._handleContinue}>Keep Playing</button>
</div>
</div>
`;
}
show(winner: PlayerView) {
this.winner = winner;
this.isVisible = true;
this.requestUpdate();
}
hide() {
this.isVisible = false;
this.requestUpdate();
}
private _handleExit() {
this.hide();
window.location.reload();
}
private _handleContinue() {
this.hide();
}
init() { }
tick() {
this.game.updatesSinceLastTick()[GameUpdateType.WinUpdate]
.forEach(wu => this.show(this.game.playerBySmallID(wu.winnerID) as PlayerView))
}
renderLayer(context: CanvasRenderingContext2D) {
}
shouldTransform(): boolean {
return false
}
}
+24 -15
View File
@@ -117,19 +117,28 @@
<build-menu></build-menu>
<player-info-overlay></player-info-overlay>
<script>
window.addEventListener("DOMContentLoaded", (event) => {
document.body.style.visibility = "visible";
document.body.style.opacity = 1;
});
</script>
<single-player-modal></single-player-modal>
<host-lobby-modal></host-lobby-modal>
<join-private-lobby-modal></join-private-lobby-modal>
<emoji-table></emoji-table>
<leader-board></leader-board>
<control-panel></control-panel>
<events-display></events-display>
<build-menu></build-menu>
<player-info-overlay></player-info-overlay>
<win-modal></win-modal>
<!-- Cloudflare Web Analytics -->
<script
defer
src="https://static.cloudflareinsights.com/beacon.min.js"
data-cf-beacon='{"token": "03d93e6fefb349c28ee69b408fa25a13"}'
></script>
<!-- End Cloudflare Web Analytics -->
</body>
</html>
<script>
window.addEventListener('DOMContentLoaded', (event) => {
document.body.style.visibility = 'visible';
document.body.style.opacity = 1;
});
</script>
<!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js'
data-cf-beacon='{"token": "03d93e6fefb349c28ee69b408fa25a13"}'></script>
<!-- End Cloudflare Web Analytics -->
</body>
</html>