mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:10:24 +00:00
add spawn ads (#1228)
## Description: Adds a bottom rail add during the spawn phase if player has played over 5 games. Also only show the death screen ad if player has played a couple of games. This keeps the experience ad-free for the first few games. <img width="1003" alt="74fb6676-273d-4b58-9fcb-50ec438c4e27" src="https://github.com/user-attachments/assets/fedca20f-7b31-4a06-be57-bde5bd0118f0" /> ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
+2
-1
@@ -24,7 +24,7 @@ import { SinglePlayerModal } from "./SinglePlayerModal";
|
||||
import { UserSettingModal } from "./UserSettingModal";
|
||||
import "./UsernameInput";
|
||||
import { UsernameInput } from "./UsernameInput";
|
||||
import { generateCryptoRandomUUID } from "./Utils";
|
||||
import { generateCryptoRandomUUID, incrementGamesPlayed } from "./Utils";
|
||||
import "./components/NewsButton";
|
||||
import { NewsButton } from "./components/NewsButton";
|
||||
import "./components/baseComponents/Button";
|
||||
@@ -365,6 +365,7 @@ class Client {
|
||||
() => {
|
||||
this.joinModal.close();
|
||||
this.publicLobby.stop();
|
||||
incrementGamesPlayed();
|
||||
|
||||
try {
|
||||
window.PageOS.session.newPageView();
|
||||
|
||||
@@ -168,3 +168,20 @@ export function getAltKey(): string {
|
||||
return "Alt";
|
||||
}
|
||||
}
|
||||
|
||||
export function getGamesPlayed(): number {
|
||||
try {
|
||||
return parseInt(localStorage.getItem("gamesPlayed") || "0", 10) || 0;
|
||||
} catch (error) {
|
||||
console.warn("Failed to read games played from localStorage:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function incrementGamesPlayed(): void {
|
||||
try {
|
||||
localStorage.setItem("gamesPlayed", (getGamesPlayed() + 1).toString());
|
||||
} catch (error) {
|
||||
console.warn("Failed to increment games played in localStorage:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import { GutterAdModal } from "./layers/GutterAdModal";
|
||||
import { HeadsUpMessage } from "./layers/HeadsUpMessage";
|
||||
import { Layer } from "./layers/Layer";
|
||||
import { Leaderboard } from "./layers/Leaderboard";
|
||||
import { LeftInGameAd } from "./layers/LeftInGameAd";
|
||||
import { MainRadialMenu } from "./layers/MainRadialMenu";
|
||||
import { MultiTabModal } from "./layers/MultiTabModal";
|
||||
import { NameLayer } from "./layers/NameLayer";
|
||||
@@ -24,6 +23,7 @@ import { OptionsMenu } from "./layers/OptionsMenu";
|
||||
import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
|
||||
import { PlayerPanel } from "./layers/PlayerPanel";
|
||||
import { ReplayPanel } from "./layers/ReplayPanel";
|
||||
import { SpawnAd } from "./layers/SpawnAd";
|
||||
import { SpawnTimer } from "./layers/SpawnTimer";
|
||||
import { StructureLayer } from "./layers/StructureLayer";
|
||||
import { TeamStats } from "./layers/TeamStats";
|
||||
@@ -198,13 +198,11 @@ export function createRenderer(
|
||||
unitInfoModal.structureLayer = structureLayer;
|
||||
// unitInfoModal.eventBus = eventBus;
|
||||
|
||||
const leftInGameAd = document.querySelector(
|
||||
"left-in-game-ad",
|
||||
) as LeftInGameAd;
|
||||
if (!(leftInGameAd instanceof LeftInGameAd)) {
|
||||
console.error("left in game ad not found");
|
||||
const spawnAd = document.querySelector("spawn-ad") as SpawnAd;
|
||||
if (!(spawnAd instanceof SpawnAd)) {
|
||||
console.error("spawn ad not found");
|
||||
}
|
||||
leftInGameAd.g = game;
|
||||
spawnAd.g = game;
|
||||
|
||||
const gutterAdModal = document.querySelector(
|
||||
"gutter-ad-modal",
|
||||
@@ -249,7 +247,7 @@ export function createRenderer(
|
||||
headsUpMessage,
|
||||
unitInfoModal,
|
||||
multiTabModal,
|
||||
leftInGameAd,
|
||||
spawnAd,
|
||||
gutterAdModal,
|
||||
];
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { EventBus, GameEvent } from "../../../core/EventBus";
|
||||
import { getGamesPlayed } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
export class GutterAdModalEvent implements GameEvent {
|
||||
@@ -29,13 +30,15 @@ export class GutterAdModal extends LitElement implements Layer {
|
||||
}
|
||||
|
||||
init() {
|
||||
this.eventBus.on(GutterAdModalEvent, (event) => {
|
||||
if (event.isVisible) {
|
||||
this.show();
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
if (getGamesPlayed() > 1) {
|
||||
this.eventBus.on(GutterAdModalEvent, (event) => {
|
||||
if (event.isVisible) {
|
||||
this.show();
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tick() {}
|
||||
|
||||
+24
-25
@@ -1,18 +1,14 @@
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { getGamesPlayed } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
const BREAKPOINT = {
|
||||
width: 1000,
|
||||
height: 800,
|
||||
};
|
||||
const AD_TYPE = "bottom_rail";
|
||||
const AD_CONTAINER_ID = "bottom-rail-ad-container";
|
||||
|
||||
const AD_TYPE = "standard_iab_modl2"; // 320x50/320x100 - better for bottom positioning
|
||||
const AD_CONTAINER_ID = "bottom-left-ad-container";
|
||||
|
||||
@customElement("left-in-game-ad")
|
||||
export class LeftInGameAd extends LitElement implements Layer {
|
||||
@customElement("spawn-ad")
|
||||
export class SpawnAd extends LitElement implements Layer {
|
||||
public g: GameView;
|
||||
|
||||
@state()
|
||||
@@ -21,6 +17,8 @@ export class LeftInGameAd extends LitElement implements Layer {
|
||||
@state()
|
||||
private adLoaded: boolean = false;
|
||||
|
||||
private gamesPlayed: number = 0;
|
||||
|
||||
// Override createRenderRoot to disable shadow DOM
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
@@ -32,39 +30,40 @@ export class LeftInGameAd extends LitElement implements Layer {
|
||||
super();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.gamesPlayed = getGamesPlayed();
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
this.isVisible = true;
|
||||
this.loadAd();
|
||||
this.requestUpdate();
|
||||
// Load the ad when showing (with small delay to ensure DOM is ready)
|
||||
setTimeout(() => this.loadAd(), 100);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
// Destroy the ad when hiding
|
||||
this.destroyAd();
|
||||
this.isVisible = false;
|
||||
this.adLoaded = false;
|
||||
this.requestUpdate();
|
||||
// Destroy the ad when hiding
|
||||
this.destroyAd();
|
||||
}
|
||||
|
||||
public async tick() {
|
||||
if (!this.isVisible && !this.g.inSpawnPhase() && this.screenLargeEnough()) {
|
||||
if (
|
||||
!this.isVisible &&
|
||||
this.g.inSpawnPhase() &&
|
||||
this.g.ticks() > 10 &&
|
||||
this.gamesPlayed > 5
|
||||
) {
|
||||
console.log("showing bottom left ad");
|
||||
this.show();
|
||||
}
|
||||
if (this.isVisible && !this.screenLargeEnough()) {
|
||||
if (this.isVisible && !this.g.inSpawnPhase()) {
|
||||
console.log("hiding bottom left ad");
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private screenLargeEnough(): boolean {
|
||||
return (
|
||||
window.innerWidth > BREAKPOINT.width &&
|
||||
window.innerHeight > BREAKPOINT.height
|
||||
);
|
||||
}
|
||||
|
||||
private loadAd(): void {
|
||||
if (!window.ramp) {
|
||||
console.warn("Playwire RAMP not available");
|
||||
@@ -96,8 +95,8 @@ export class LeftInGameAd extends LitElement implements Layer {
|
||||
}
|
||||
try {
|
||||
window.ramp.que.push(() => {
|
||||
window.ramp.destroyUnits(AD_TYPE);
|
||||
console.log("Playwire ad destroyed:", AD_TYPE);
|
||||
window.ramp.destroyUnits("all");
|
||||
console.log("Playwire spawn ad destroyed");
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to destroy Playwire ad:", error);
|
||||
@@ -117,7 +116,7 @@ export class LeftInGameAd extends LitElement implements Layer {
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="w-[320px] min-h-[100px] bg-gray-900 border border-gray-600 flex items-center justify-center"
|
||||
class="fixed bottom-0 left-0 w-full min-h-[100px] bg-gray-900 border border-gray-600 flex items-center justify-center z-50"
|
||||
>
|
||||
<div
|
||||
id="${AD_CONTAINER_ID}"
|
||||
@@ -283,7 +283,6 @@
|
||||
style="pointer-events: auto"
|
||||
>
|
||||
<control-panel></control-panel>
|
||||
<left-in-game-ad></left-in-game-ad>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -368,6 +367,7 @@
|
||||
<unit-info-modal></unit-info-modal>
|
||||
<news-modal></news-modal>
|
||||
<game-left-sidebar></game-left-sidebar>
|
||||
<spawn-ad></spawn-ad>
|
||||
<div
|
||||
id="language-modal"
|
||||
class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex justify-center items-center"
|
||||
|
||||
Reference in New Issue
Block a user