export const WUCAI_TYPE_NONE = -1; export const WUCAI_TYPE_AUTO_MIGRATED = 0; export const WUCAI_TYPE_PENDING_CHOICE = 1; export const WUCAI_TYPE_CHOSE_WUCAI = 2; export const WUCAI_TYPE_CHOSE_CURRENT = 3; export const WUCAI_REWARD = { coinAmount: 2000, freezeAmount: 3, hammerAmount: 3, magicAmount: 3, }; export default async function main() { return { code: 1, data: null, msg: "wucaiMigration ready" }; } const DEFAULT_HEAD_ARR = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; const DEFAULT_CAT_ARR = [1, 2, 3]; export async function fetchWucaiUser(unionid: string): Promise { if (!unionid) { return null; } try { const response = await fetch("https://laf.nika4games.com/getUserInfoByUnionid", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ unionid }), }); if (response.ok === false) { return null; } const result = await response.json(); const user = result?.data; if (!user || typeof user !== "object" || !Object.prototype.hasOwnProperty.call(user, "levelAmount")) { return null; } return user; } catch (error) { console.error("Failed to read Wucai user", error); return null; } } export function normalizeWucaiUser(source: any): any { return { levelAmount: numberOr(source?.levelAmount, 0), coinAmount: numberOr(source?.coinAmount, 0), healthAmount: numberOr(source?.healthAmount, 5), healthtimestamp: numberOr(source?.healthtimestamp, 0), freezeAmount: numberOr(source?.freezeAmount, 3), hammerAmount: numberOr(source?.hammerAmount, 3), magicAmount: numberOr(source?.magicAmount, 3), userPowerTime: numberOr(source?.userPowerTime, 0), monthCardReward: numberOr(source?.monthCardReward, 0), monthCardTime: numberOr(source?.monthCardTime, 0), pay_user: booleanOrFalse(source?.pay_user), starter_pack: numberOr(source?.starter_pack, 0), starter_packState: numberOr(source?.starter_packState, 0), starterPackVersion: numberOr(source?.starterPackVersion, 1), starterPackRound: numberOr(source?.starterPackRound, 0), winStreak: numberOr(source?.winStreak, 0), passCheck: cloneSerializable(source?.passCheck ?? null), endLevelNum: numberOr(source?.endLevelNum, 0), totalLevel: numberOr(source?.totalLevel, 0), userLevel: numberOr(source?.userLevel, 0), film: numberOr(source?.film, 0), headArr: numberArrayOr(source?.headArr, DEFAULT_HEAD_ARR), catArr: numberArrayOr(source?.catArr, DEFAULT_CAT_ARR), }; } export function buildWucaiPreview(source: any, nowSeconds = Math.floor(Date.now() / 1000)): any { const user = normalizeWucaiUser(source); return { levelAmount: user.levelAmount, coinAmount: user.coinAmount, healthAmount: user.healthAmount, freezeAmount: user.freezeAmount, hammerAmount: user.hammerAmount, magicAmount: user.magicAmount, film: user.film, winStreak: user.winStreak, headCount: user.headArr.length, catCount: user.catArr.length, monthCardActive: user.monthCardTime > nowSeconds, passCheckActive: isPassCheckActive(user.passCheck), }; } export function addWucaiReward(user: any): any { return { coinAmount: numberOr(user?.coinAmount, 0) + WUCAI_REWARD.coinAmount, freezeAmount: numberOr(user?.freezeAmount, 0) + WUCAI_REWARD.freezeAmount, hammerAmount: numberOr(user?.hammerAmount, 0) + WUCAI_REWARD.hammerAmount, magicAmount: numberOr(user?.magicAmount, 0) + WUCAI_REWARD.magicAmount, }; } export function isPristineWucaiTarget(user: any, hasOrder: boolean): boolean { if (!user || hasOrder) { return false; } const expectedNumbers: Record = { levelAmount: 0, coinAmount: 0, healthAmount: 5, healthtimestamp: 0, freezeAmount: 3, hammerAmount: 3, magicAmount: 3, userPowerTime: 0, monthCardReward: 0, monthCardTime: 0, rebornGiftCount: 0, rebornGiftTime: 0, starter_pack: 0, starter_packState: 0, winStreak: 0, endLevelNum: 0, totalLevel: 0, userLevel: 0, film: 0, careerAmount: 0, addLevel: 0, }; for (const key of Object.keys(expectedNumbers)) { if (numberOr(user[key], expectedNumbers[key]) !== expectedNumbers[key]) { return false; } } if (booleanOrFalse(user.pay_user)) { return false; } if (user.passCheck != null && user.passCheck !== "null" && user.passCheck !== "") { return false; } if (hasMeaningfulJungleState(user.jungleTreasureState)) { return false; } return arraysEqual(numberArrayOr(user.headArr, DEFAULT_HEAD_ARR), DEFAULT_HEAD_ARR) && arraysEqual(numberArrayOr(user.catArr, DEFAULT_CAT_ARR), DEFAULT_CAT_ARR); } export function isValidWucaiType(value: any): boolean { const type = Number(value); return Number.isInteger(type) && type >= WUCAI_TYPE_NONE && type <= WUCAI_TYPE_CHOSE_CURRENT; } function numberOr(value: any, fallback: number): number { if (value === null || value === undefined || value === "") { return fallback; } const number = Number(value); return Number.isFinite(number) ? number : fallback; } function booleanOrFalse(value: any): boolean { return value === true || value === 1 || value === "1" || value === "true"; } function numberArrayOr(value: any, fallback: number[]): number[] { if (!Array.isArray(value)) { return [...fallback]; } return value.map(item => Number(item)).filter(item => Number.isFinite(item)); } function cloneSerializable(value: any): any { if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") { return value; } return JSON.parse(JSON.stringify(value)); } function isPassCheckActive(value: any): boolean { let passCheck = value; if (typeof passCheck === "string") { try { passCheck = JSON.parse(passCheck); } catch { return false; } } if (Array.isArray(passCheck)) { return passCheck.some(item => item?.activate === true || item?.activate === 1); } return passCheck?.activate === true || passCheck?.activate === 1; } function hasMeaningfulJungleState(value: any): boolean { if (value == null || value === "" || value === "null") { return false; } let state = value; if (typeof state === "string") { try { state = JSON.parse(state); } catch { return true; } } if (!state || !Array.isArray(state.tierStates)) { return true; } return state.tierStates.some(item => Number(item) > 0); } function arraysEqual(left: number[], right: number[]): boolean { return left.length === right.length && left.every((item, index) => item === right[index]); }