e
This commit is contained in:
parent
f657b6a4a4
commit
d163ceb291
76 changed files with 1385 additions and 524 deletions
|
|
@ -33,6 +33,7 @@
|
|||
const STATISTICIAN_TARGET = 30;
|
||||
const LIVELY_MAKING_TARGET = 100;
|
||||
const MEMENTO_MORI_TARGET = 10000;
|
||||
const MAD_SCIENTIST_TARGET = 10;
|
||||
const FULL_SEASON_CYCLE_DAYS = 20;
|
||||
const PRE_UNLOCK_DESCRIPTION_IDS = new Set([
|
||||
"natural_zunchi_slave",
|
||||
|
|
@ -64,6 +65,7 @@
|
|||
"elite_few",
|
||||
"lively_making",
|
||||
"memento_mori",
|
||||
"mad_scientist",
|
||||
]);
|
||||
const ACHIEVEMENT_CATEGORIES = Object.freeze([
|
||||
Object.freeze({
|
||||
|
|
@ -81,7 +83,7 @@
|
|||
}),
|
||||
Object.freeze({
|
||||
id: "population",
|
||||
title: "\u7e41\u6b96\u30fb\u4eba\u53e3",
|
||||
title: "\u4eba\u53e3",
|
||||
ids: Object.freeze([
|
||||
"first_birth", "natural_zunchi_slave_5_generations", "natural_tarinai_king_3_generations",
|
||||
"birth_50_in_60_seconds", "great_mother_1000_births", "eternal_history_generation_10",
|
||||
|
|
@ -97,7 +99,7 @@
|
|||
"fight_pair_danger_kill", "ignite_during_birth_ritual", "laxative_starvation",
|
||||
"ants_killed_100", "below_absolute_zero_item", "sauna_cold_plunge",
|
||||
"mercury_lifespan", "revolution", "fuel_to_fire",
|
||||
"chaos_seeker_666_fights", "sticky_bomb_15_passes", "wire_shock_7_tarinai",
|
||||
"chaos_seeker_666_fights", "sticky_bomb_15_passes", "wire_shock_7_tarinai", "mad_scientist",
|
||||
]),
|
||||
}),
|
||||
Object.freeze({
|
||||
|
|
@ -202,7 +204,8 @@
|
|||
Object.freeze({ id: "statistician", title: "\u7d71\u8a08\u5b66\u8005", description: "\u7d71\u8a08\u306e\u500b\u4f53\u6570\u30fb\u6b32\u6c42\u30fb\u74b0\u5883\u30fb\u30b0\u30e9\u30d5\u8868\u793a\u5207\u66ff\u30dc\u30bf\u30f3\u3092\u7d2f\u8a0830\u56de\u62bc\u3059\u3002" }),
|
||||
Object.freeze({ id: "well_informed", title: "\u60c5\u5831\u901a", description: "\u30d7\u30c3\u30b7\u30e5\u901a\u77e5\u3092ON\u306b\u3059\u308b\u3002" }),
|
||||
Object.freeze({ id: "lively_making", title: "\u8cd1\u308f\u3044\u3065\u304f\u308a", description: "\u300c\u305f\u308a\u306a\u3044\u3092\u8ffd\u52a0\u300d\u3067100\u4f53\u8ffd\u52a0\u3059\u308b\u3002" }),
|
||||
Object.freeze({ id: "memento_mori", title: "\u30e1\u30e1\u30f3\u30c8\u30fb\u30e2\u30ea", description: "\u305f\u308a\u306a\u3044\u304c\u5408\u8a0810000\u4f53\u6b7b\u4ea1\u3059\u308b\u3002" }),
|
||||
Object.freeze({ id: "memento_mori", title: "\u591a\u6570\u306e\u6b7b\u306f\u7d71\u8a08\u4e0a\u306e\u6570\u5b57\u3067\u3057\u304b\u306a\u3044", description: "\u305f\u308a\u306a\u3044\u304c\u5408\u8a0810000\u4f53\u6b7b\u4ea1\u3059\u308b\u3002" }),
|
||||
Object.freeze({ id: "mad_scientist", title: "\u30de\u30c3\u30c9\u30b5\u30a4\u30a8\u30f3\u30c6\u30a3\u30b9\u30c8", description: "\u7570\u306a\u308b10\u5339\u306e\u305f\u308a\u306a\u3044\u306b\u602a\u3057\u3044\u85ac\u3092\u6295\u4e0e\u3059\u308b\u3002" }),
|
||||
]);
|
||||
const definitionById = new Map(DEFINITIONS.map(def => [def.id, def]));
|
||||
const CATEGORY_DEFINITIONS = new Map(ACHIEVEMENT_CATEGORIES.map(category => [
|
||||
|
|
@ -246,7 +249,7 @@
|
|||
let scheduledProgressSaveTimer = 0;
|
||||
|
||||
function blankState() {
|
||||
return { unlocked: {}, pending: [], resetPending: false, debugUnlocked: [], progress: { placementCount: 0, linkTypes: [], signalActivated: false, antKills: 0, birthCount: 0, quickDeleteCount: 0, undoCount: 0, redoCount: 0, medicineTypes: [], firstAidHeals: 0, fightMochiFightCount: 0, shotCount: 0, loveMochiBirthCount: 0, dailyPlayStreak: 0, dailyPlayLastDay: 0, statsButtonPressCount: 0, totalDeathCount: 0, manualTarinaiAddedCount: 0 } };
|
||||
return { unlocked: {}, pending: [], resetPending: false, debugUnlocked: [], progress: { placementCount: 0, linkTypes: [], signalActivated: false, antKills: 0, birthCount: 0, quickDeleteCount: 0, undoCount: 0, redoCount: 0, medicineTypes: [], firstAidHeals: 0, fightMochiFightCount: 0, shotCount: 0, loveMochiBirthCount: 0, dailyPlayStreak: 0, dailyPlayLastDay: 0, statsButtonPressCount: 0, totalDeathCount: 0, manualTarinaiAddedCount: 0, mysteryDrugTarinaiIds: [] } };
|
||||
}
|
||||
|
||||
function loadState() {
|
||||
|
|
@ -299,6 +302,7 @@
|
|||
statsButtonPressCount: Math.min(STATISTICIAN_TARGET, Math.max(0, Math.floor(Number(progressSource.statsButtonPressCount || 0) || 0))),
|
||||
totalDeathCount: Math.min(MEMENTO_MORI_TARGET, Math.max(0, Math.floor(Number(progressSource.totalDeathCount || 0) || 0))),
|
||||
manualTarinaiAddedCount: Math.min(LIVELY_MAKING_TARGET, Math.max(0, Math.floor(Number(progressSource.manualTarinaiAddedCount || 0) || 0))),
|
||||
mysteryDrugTarinaiIds: [...new Set((Array.isArray(progressSource.mysteryDrugTarinaiIds) ? progressSource.mysteryDrugTarinaiIds : []).map(id => String(id || "")).filter(Boolean))].slice(0, MAD_SCIENTIST_TARGET),
|
||||
};
|
||||
const missingCompletionRequirement = DEFINITIONS.some(definition => definition.id !== COMPLETIONIST_ID && !unlocked[definition.id]);
|
||||
if (unlocked[COMPLETIONIST_ID] && missingCompletionRequirement) {
|
||||
|
|
@ -449,6 +453,10 @@
|
|||
const count = state.unlocked[id] ? MEMENTO_MORI_TARGET : Math.min(MEMENTO_MORI_TARGET, Math.max(0, Math.floor(Number(state.progress?.totalDeathCount || 0) || 0)));
|
||||
return `\u73fe\u5728\u306e\u9054\u6210\u7387 ${(count / MEMENTO_MORI_TARGET * 100).toFixed(1)}%\uff08${count} / ${MEMENTO_MORI_TARGET}\u4f53\uff09`;
|
||||
}
|
||||
if (id === "mad_scientist") {
|
||||
const count = state.unlocked[id] ? MAD_SCIENTIST_TARGET : Math.min(MAD_SCIENTIST_TARGET, state.progress?.mysteryDrugTarinaiIds?.length || 0);
|
||||
return `\u73fe\u5728 ${count} / ${MAD_SCIENTIST_TARGET}\u5339`;
|
||||
}
|
||||
if (id === "continuous_play_1_hour") {
|
||||
const elapsed = Math.min(CONTINUOUS_PLAY_TARGET_MS, continuousPlayElapsedMs());
|
||||
return `\u73fe\u5728\u306e\u9054\u6210\u7387 ${(elapsed / CONTINUOUS_PLAY_TARGET_MS * 100).toFixed(1)}%\uff08${formatElapsed(elapsed)} / 60:00\uff09`;
|
||||
|
|
@ -487,6 +495,7 @@
|
|||
Math.min(STATISTICIAN_TARGET, Math.max(0, Number(state.progress?.statsButtonPressCount || 0) || 0)),
|
||||
Math.min(MEMENTO_MORI_TARGET, Math.max(0, Number(state.progress?.totalDeathCount || 0) || 0)),
|
||||
Math.min(LIVELY_MAKING_TARGET, Math.max(0, Number(state.progress?.manualTarinaiAddedCount || 0) || 0)),
|
||||
Math.min(MAD_SCIENTIST_TARGET, state.progress?.mysteryDrugTarinaiIds?.length || 0),
|
||||
Math.floor(Math.max(0, (Number(global.world?.time || 0) || 0) - Math.max(0, Number(global.world?.achievementEliteFewStartAt || 0) || 0)) / Math.max(1, Number(global.world?.config?.dayLength ?? global.CONFIG?.dayLength ?? 120) || 120) * 10),
|
||||
].join(":");
|
||||
return `${unlocks}|${rates}|${local}`;
|
||||
|
|
@ -656,6 +665,7 @@
|
|||
function runNextUnlockToast() {
|
||||
if (toastActive || !toastQueue.length) return;
|
||||
const definition = toastQueue.shift();
|
||||
global.TarinaiAudio?.achievementUnlock?.();
|
||||
if (!dom.toast || !dom.toastTitle) {
|
||||
global.showToast?.(`\u5b9f\u7e3e\u89e3\u9664: ${definition.title} \u2014 ${definition.description || ""}`);
|
||||
global.setTimeout(runNextUnlockToast, 80);
|
||||
|
|
@ -919,6 +929,8 @@
|
|||
state.progress.statsButtonPressCount = Math.min(STATISTICIAN_TARGET, Math.max(0, Math.floor(Number(state.progress.statsButtonPressCount || 0) || 0)));
|
||||
state.progress.totalDeathCount = Math.min(MEMENTO_MORI_TARGET, Math.max(0, Math.floor(Number(state.progress.totalDeathCount || 0) || 0)));
|
||||
state.progress.manualTarinaiAddedCount = Math.min(LIVELY_MAKING_TARGET, Math.max(0, Math.floor(Number(state.progress.manualTarinaiAddedCount || 0) || 0)));
|
||||
if (!Array.isArray(state.progress.mysteryDrugTarinaiIds)) state.progress.mysteryDrugTarinaiIds = [];
|
||||
state.progress.mysteryDrugTarinaiIds = [...new Set(state.progress.mysteryDrugTarinaiIds.map(id => String(id || "")).filter(Boolean))].slice(0, MAD_SCIENTIST_TARGET);
|
||||
return state.progress;
|
||||
}
|
||||
|
||||
|
|
@ -990,6 +1002,7 @@
|
|||
state.unlocked.statistician ? 0 : Math.min(STATISTICIAN_TARGET, progress.statsButtonPressCount),
|
||||
state.unlocked.memento_mori ? 0 : Math.min(MEMENTO_MORI_TARGET, progress.totalDeathCount),
|
||||
state.unlocked.lively_making ? 0 : Math.min(LIVELY_MAKING_TARGET, progress.manualTarinaiAddedCount),
|
||||
state.unlocked.mad_scientist ? 0 : Math.min(MAD_SCIENTIST_TARGET, progress.mysteryDrugTarinaiIds.length),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
@ -1083,6 +1096,10 @@
|
|||
progress.statsButtonPressCount = Math.max(progress.statsButtonPressCount, Math.min(STATISTICIAN_TARGET, Math.max(0, Math.floor(Number(packed[14] || 0) || 0))));
|
||||
progress.totalDeathCount = Math.max(progress.totalDeathCount, Math.min(MEMENTO_MORI_TARGET, Math.max(0, Math.floor(Number(packed[15] || 0) || 0))));
|
||||
progress.manualTarinaiAddedCount = Math.max(progress.manualTarinaiAddedCount, Math.min(LIVELY_MAKING_TARGET, Math.max(0, Math.floor(Number(packed[16] || 0) || 0))));
|
||||
const importedMysteryDrugCount = Math.min(MAD_SCIENTIST_TARGET, Math.max(0, Math.floor(Number(packed[17] || 0) || 0)));
|
||||
while (progress.mysteryDrugTarinaiIds.length < importedMysteryDrugCount) {
|
||||
progress.mysteryDrugTarinaiIds.push(`imported:${progress.mysteryDrugTarinaiIds.length + 1}`);
|
||||
}
|
||||
const progressChanged = previousProgress !== JSON.stringify(progress);
|
||||
changed = changed || progressChanged;
|
||||
|
||||
|
|
@ -1570,6 +1587,19 @@
|
|||
tarinai._achievementFightMochiSerial = serial;
|
||||
tarinai._achievementFightMochiWorld = world;
|
||||
}
|
||||
if (type === "mystery_drug" && tarinai && !state.unlocked.mad_scientist) {
|
||||
const progress = ensureProgress();
|
||||
const identity = String(tarinai.familyKey || tarinai.id || "");
|
||||
if (identity && !progress.mysteryDrugTarinaiIds.includes(identity)) {
|
||||
progress.mysteryDrugTarinaiIds = [...progress.mysteryDrugTarinaiIds, identity].slice(0, MAD_SCIENTIST_TARGET);
|
||||
if (progress.mysteryDrugTarinaiIds.length >= MAD_SCIENTIST_TARGET) {
|
||||
changed = unlock("mad_scientist", { ...detail, world, tarinai, count: progress.mysteryDrugTarinaiIds.length }) || changed;
|
||||
} else {
|
||||
saveState();
|
||||
renderIfDialogOpen();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MEDICINE_LEDGER_TYPES.includes(type) && !state.unlocked.medicine_ledger_all) {
|
||||
const progress = ensureProgress();
|
||||
if (!progress.medicineTypes.includes(type)) {
|
||||
|
|
@ -1857,6 +1887,9 @@
|
|||
}
|
||||
|
||||
function recordManualTarinaiAdded(detail = {}) {
|
||||
// Adding a Tarinai is a direct player intervention and must invalidate
|
||||
// the no-operation window used by the surveillance-camera achievement.
|
||||
recordIntervention({ ...detail, tool: detail.tool || "new-tarinai" });
|
||||
if (state.unlocked.lively_making) return false;
|
||||
const progress = ensureProgress();
|
||||
progress.manualTarinaiAddedCount = Math.min(LIVELY_MAKING_TARGET, progress.manualTarinaiAddedCount + 1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue