218 lines
6.8 KiB
TypeScript
218 lines
6.8 KiB
TypeScript
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<any | null> {
|
|
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),
|
|
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: source?.passCheckV2 ? isV2PassActive(source.passCheckV2, nowSeconds * 1000) : 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 || user.passCheckV2) {
|
|
return false;
|
|
}
|
|
const expectedNumbers: Record<string, number> = {
|
|
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]);
|
|
}
|
|
|
|
function isV2PassActive(raw: any, now: number): boolean {
|
|
try { const s = typeof raw === 'string' ? JSON.parse(raw) : raw; return s.seasons.some((p: any) => p.tier >= 2 && p.claimUntil > now); } catch { return false; }
|
|
}
|