|
|
@@ -7,11 +7,6 @@ let lastExitGame=false;
|
|
|
let lastLevelCompleted = 0;
|
|
|
let lastGameOver = 0;
|
|
|
|
|
|
-// Keep the server-provided daily level separate from Construct Local Storage.
|
|
|
-// The event sheet may enter its "missing" branch after startup and repaint all
|
|
|
-// menu buttons as locked even though max_level was read correctly from the URL.
|
|
|
-let dailyMaxLevelFromUrl = 1;
|
|
|
-
|
|
|
runOnStartup(async runtime =>
|
|
|
{
|
|
|
runtime.addEventListener(
|
|
|
@@ -43,19 +38,6 @@ async function OnBeforeProjectStart(runtime)
|
|
|
() => Tick(runtime)
|
|
|
);
|
|
|
|
|
|
- // Apply after the event sheet so its Local Storage fallback cannot overwrite
|
|
|
- // the level state supplied by the website for the current subscriber/day.
|
|
|
- runtime.addEventListener(
|
|
|
- "tick2",
|
|
|
- () =>
|
|
|
- {
|
|
|
- // Level buttons only exist on the menu. Do not run the menu sync
|
|
|
- // while an Easy/Medium/Hard gameplay layout is active.
|
|
|
- if (runtime.layout?.name === "Menu")
|
|
|
- SyncDailyLevelMenu(runtime);
|
|
|
- }
|
|
|
- );
|
|
|
-
|
|
|
console.log("Add event success");
|
|
|
|
|
|
// Báo MVC biết game đã sẵn sàng
|
|
|
@@ -71,31 +53,6 @@ async function OnBeforeProjectStart(runtime)
|
|
|
}
|
|
|
|
|
|
|
|
|
-function SyncDailyLevelMenu(runtime)
|
|
|
-{
|
|
|
- const levelButtons = runtime.objects.btn_lvl?.getAllInstances() ?? [];
|
|
|
-
|
|
|
- for (const button of levelButtons)
|
|
|
- {
|
|
|
- const level = Number(button.instVars.level);
|
|
|
- if (!Number.isFinite(level))
|
|
|
- continue;
|
|
|
-
|
|
|
- const isOpen = level <= dailyMaxLevelFromUrl;
|
|
|
- const animation = isOpen ? "open" : "locked";
|
|
|
-
|
|
|
- if (button.animationName !== animation)
|
|
|
- button.setAnimation(animation);
|
|
|
-
|
|
|
- // The open animation contains one frame per menu number (1-50).
|
|
|
- // Selecting the animation resets it to frame 0, so restore the frame
|
|
|
- // that belongs to this button's level after changing its lock state.
|
|
|
- if (isOpen && button.animationFrame !== level - 1)
|
|
|
- button.animationFrame = level - 1;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
|
|
|
function LoadGameConfigFromUrl(runtime)
|
|
|
{
|
|
|
@@ -105,23 +62,33 @@ function LoadGameConfigFromUrl(runtime)
|
|
|
window.location.search
|
|
|
);
|
|
|
|
|
|
- const requestedGameType = params.get("gameType");
|
|
|
- const requestedMaxLevel = Number.parseInt(params.get("max_level"), 10);
|
|
|
+ const gameType =
|
|
|
+ params.get("gameType");
|
|
|
+
|
|
|
+
|
|
|
+ if (gameType)
|
|
|
+ {
|
|
|
+ runtime.globalVars.gameType = gameType;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ runtime.globalVars.gameType = "Easy";
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- // Website calculates today's progress for the current subscriber and
|
|
|
- // passes it in the iframe URL. Apply both values before the menu event
|
|
|
- // sheet starts, so the game does not briefly use Easy/local progress.
|
|
|
- runtime.globalVars.gameType = ["Easy", "Medium", "Hard"].includes(requestedGameType)
|
|
|
- ? requestedGameType
|
|
|
- : "Easy";
|
|
|
+ const maxLevel = parseInt(params.get("max_level"), 10);
|
|
|
|
|
|
- runtime.globalVars.unlocked_level = Number.isFinite(requestedMaxLevel)
|
|
|
- ? Math.min(50, Math.max(1, requestedMaxLevel))
|
|
|
- : 1;
|
|
|
- dailyMaxLevelFromUrl = runtime.globalVars.unlocked_level;
|
|
|
+ if (Number.isInteger(maxLevel) && maxLevel >= 1)
|
|
|
+ {
|
|
|
+ runtime.globalVars.unlocked_level = maxLevel;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ runtime.globalVars.unlocked_level = 1;
|
|
|
+ }
|
|
|
|
|
|
- runtime.globalVars.InitGameTypeSuccess = 1;
|
|
|
- runtime.globalVars.InitUnLockSucess = 1;
|
|
|
+
|
|
|
+ runtime.globalVars.InitGameTypeSuccess =1;
|
|
|
|
|
|
// Sau khi có gameType thì set cấu hình game
|
|
|
SetGameConfig(runtime);
|
|
|
@@ -130,10 +97,10 @@ function LoadGameConfigFromUrl(runtime)
|
|
|
console.log(
|
|
|
"GameType:",
|
|
|
runtime.globalVars.gameType,
|
|
|
- "MaxLevel:",
|
|
|
- runtime.globalVars.unlocked_level,
|
|
|
"TotalTime:",
|
|
|
- runtime.globalVars.totaltime
|
|
|
+ runtime.globalVars.totaltime,
|
|
|
+ "max_level:",
|
|
|
+ runtime.globalVars.unlocked_level
|
|
|
);
|
|
|
|
|
|
}
|
|
|
@@ -145,10 +112,6 @@ function LoadGameConfigFromUrl(runtime)
|
|
|
);
|
|
|
|
|
|
runtime.globalVars.gameType = "Easy";
|
|
|
- runtime.globalVars.unlocked_level = 1;
|
|
|
- dailyMaxLevelFromUrl = 1;
|
|
|
- runtime.globalVars.InitGameTypeSuccess = 1;
|
|
|
- runtime.globalVars.InitUnLockSucess = 1;
|
|
|
|
|
|
SetGameConfig(runtime);
|
|
|
}
|
|
|
@@ -304,6 +267,14 @@ function Tick(runtime)
|
|
|
//Set showPrizePopup = 0
|
|
|
async function SaveLevelResult(runtime)
|
|
|
{
|
|
|
+ if (levelSending)
|
|
|
+ {
|
|
|
+ console.warn("SaveLevelResult ignored because a request is already in progress.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ levelSending = true;
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
console.log("Calling SaveLevelResult...");
|
|
|
@@ -318,8 +289,6 @@ async function SaveLevelResult(runtime)
|
|
|
gameOver: 0
|
|
|
};
|
|
|
|
|
|
- console.log("Request Body:", body);
|
|
|
-
|
|
|
const response = await fetch(
|
|
|
runtime.globalVars.root + "/Game/SaveLevelResult",
|
|
|
{
|
|
|
@@ -335,10 +304,19 @@ async function SaveLevelResult(runtime)
|
|
|
|
|
|
console.log("Level Result:", result);
|
|
|
|
|
|
+ if (!response.ok || result.success !== true)
|
|
|
+ {
|
|
|
+ throw new Error(result.message || `Save level failed (${response.status})`);
|
|
|
+ }
|
|
|
+
|
|
|
// Lưu dữ liệu gốc
|
|
|
- runtime.globalVars.point = Number(result.point ?? 0);
|
|
|
- runtime.globalVars.data = Number(result.data ?? 0);
|
|
|
- runtime.globalVars.score = Number(result.score ?? 0);
|
|
|
+ const point = Number(result.point ?? 0);
|
|
|
+ const data = Number(result.data ?? 0);
|
|
|
+ const score = Number(result.score ?? 0);
|
|
|
+
|
|
|
+ runtime.globalVars.point = Number.isFinite(point) ? point : 0;
|
|
|
+ runtime.globalVars.data = Number.isFinite(data) ? data : 0;
|
|
|
+ runtime.globalVars.score = Number.isFinite(score) ? score : 0;
|
|
|
runtime.globalVars.transId = result.transId ?? "";
|
|
|
|
|
|
// Xác định phần thưởng
|
|
|
@@ -348,19 +326,30 @@ async function SaveLevelResult(runtime)
|
|
|
if (runtime.globalVars.point > 0)
|
|
|
{
|
|
|
runtime.globalVars.gGiftValues = runtime.globalVars.point;
|
|
|
- runtime.globalVars.gGiftText = "POINTS";
|
|
|
+ runtime.globalVars.gGiftText = "Loyalty";
|
|
|
}
|
|
|
else if (runtime.globalVars.data > 0)
|
|
|
{
|
|
|
runtime.globalVars.gGiftValues = runtime.globalVars.data;
|
|
|
- runtime.globalVars.gGiftText = "DATA";
|
|
|
+ runtime.globalVars.gGiftText = "M";
|
|
|
}
|
|
|
else if (runtime.globalVars.score > 0)
|
|
|
{
|
|
|
runtime.globalVars.gGiftValues = runtime.globalVars.score;
|
|
|
- runtime.globalVars.gGiftText = "SCORE";
|
|
|
+ runtime.globalVars.gGiftText = "Score";
|
|
|
}
|
|
|
|
|
|
+ // Update the visible fields immediately as well as notifying the event sheet.
|
|
|
+ // This prevents one stale frame when the response arrives between game ticks.
|
|
|
+ const giftValueText = runtime.objects.txtGiftValues?.getFirstInstance();
|
|
|
+ const giftTypeText = runtime.objects.txtGiftText?.getFirstInstance();
|
|
|
+
|
|
|
+ if (giftValueText)
|
|
|
+ giftValueText.text = String(runtime.globalVars.gGiftValues);
|
|
|
+
|
|
|
+ if (giftTypeText)
|
|
|
+ giftTypeText.text = runtime.globalVars.gGiftText;
|
|
|
+
|
|
|
runtime.globalVars.showPrizePopup = 1;
|
|
|
|
|
|
console.log("Gift Type:", runtime.globalVars.gGiftText);
|
|
|
@@ -523,3 +512,4 @@ function MovePlayer(offsetX, offsetY)
|
|
|
player.x += offsetX;
|
|
|
player.y += offsetY;
|
|
|
}
|
|
|
+
|