【赛博徒步】生死鳌太线-附修改脚本
- 内容介绍
- 文章标签
- 相关推荐
上一个帖子不能编辑了 特开新帖
游戏地址:赛博徒步:生死鳌太线 | 一场关于意志与生存的终极考验
image1552×852 108 KB
image791×592 41.4 KB
很久之前就有佬友推荐过 作者一直在更新 随着细节丰富 越来越真实了
没有徒步经验的佬友可以体验一下到底有多难
附上我迭代更新了一个月的脚本:不建议用 用了就没意思了
①解锁付费订阅 支持付费下撤路线(你没看错有氪金项目 还有反调试)
②解锁并未开放的卫星电话 可以救驴友远山了
③解锁全成就&称号
④全物品添加&全地点瞬移
⑤修改属性(体温、体力、精神、饱腹、业力、预算、负重、天数、电话电量)
Tips:在死亡界面修改属性可以强行原地复活
// ==UserScript==
// @name 赛博徒步:生死鳌太线 理想值修改器 V7
// @namespace http://tampermonkey.net/
// @version 7.0
// @description 数值修改 + `/~ 显示隐藏 + 面板记忆 + 节点瞬移(中文下拉+自动收集新节点+仅保留“保存当前节点”)
// @author @Wet_Dream_Boy
// @match https://cyberhiking.com/*
// @grant none
// @run-at document-start
// @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// ==/UserScript==
(function () {
'use strict';
const STORAGE_KEY = 'aotai-survival-storage';
const CRYPTO_KEY = 'aotai-survival@2024';
const UI_ID = 'cyber-mod-v6-root';
// 面板输入记忆
const UI_PREF_KEY = 'aotai-ideal-panel-values-v6';
// 节点列表记忆(下拉中文/自动新增也会保存)
const UI_NODE_LIST_KEY = 'aotai-node-list-v6';
let isVisible = true;
// --- 理想默认值配置 ---
const IDEAL_VALUES = {
temp: 36.5,
stamina: 100,
sanity: 100,
hunger: 100,
karma: 1000,
budget: 99999,
weight: 0.1,
day: 1,
battery: 100,
victoryCount: 9,
hasMountainGodPass: false,
subscriptions: '',
lastItemId: 'backpack_expedition',
};
// --- 默认节点(你在脚本里维护;下拉中文显示)---
const DEFAULT_NODES = [
// --- 正常路线 (塘口 -> 南塬) ---
{ id: 'tangkou', name: '塘口' },
{ id: 'longwanghekou', name: '龙王河口' },
{ id: 'xihuagou', name: '西桦沟' }, // ✅ 修正
{ id: 'huoshaopo', name: '火烧坡' },
{ id: 'camp_2900', name: '2900营地' },
{ id: 'penjingyuan', name: '盆景园' },
{ id: 'baiqimiao', name: '白起庙' },
{ id: 'aotou', name: '鳌头' },
{ id: 'aoshanding', name: '鳌山顶' },
{ id: 'west_paoma', name: '西跑马梁' },
{ id: 'yaowangmiao', name: '药王庙' },
{ id: 'maijie_ridge', name: '麦秸岭' },
{ id: 'wenxiong_stone', name: '文胸石' }, // ✅ 修正
{ id: 'shuiwozi', name: '水窝子' },
{ id: 'monument', name: '纪念碑' }, // 纪念碑通常在水窝子到飞机梁之间
{ id: 'feiji_liang', name: '飞机梁' }, // ✅ 按你要求:不动
{ id: 'liang_yi', name: '梁一' },
{ id: 'liang_er', name: '梁二' },
{ id: 'liang_san', name: '梁三' },
{ id: 'camp_2800', name: '2800营地' },
{ id: 'nantianmen_pass', name: '南天门垭口' }, // ✅ 保持你的写法
{ id: 'nantianmen_forest', name: '南天门林区' },
{ id: 'nantianmen_camp', name: '南天门营地' },
{ id: 'pyramid', name: '金字塔' },
{ id: 'ta_yi', name: '塔一' },
{ id: 'ta_er', name: '塔二' },
{ id: 'ta_san', name: '塔三' },
{ id: 'jiuchongtian', name: '九重天' },
{ id: 'xiyuan_camp', name: '西源营地' },
{ id: 'dongyuan_camp', name: '东源营地' },
{ id: 'wanxian_array', name: '万仙阵' },
{ id: 'leigong_temple', name: '雷公庙' },
{ id: 'paoma_liang', name: '跑马梁' },
{ id: 'dayehai', name: '大爷海' },
{ id: 'dawengong_temple', name: '大文公庙' },
{ id: 'fangyang_temple', name: '放羊寺' },
{ id: 'mingxing_temple', name: '明星寺' },
{ id: 'pingan_temple', name: '平安寺' },
{ id: 'nanyuan_village', name: '南塬村' },
// --- 下撤/支线/其他 ---
{ id: 'qiaodiping', name: '桥底坪' },
{ id: 'baiyun_bridge', name: '白云桥' },
{ id: 'baiyun_gorge_new', name: '白云峡谷(新)' },
{ id: 'maershan_village', name: '马耳山村' },
{ id: 'yingge_town', name: '鹦哥镇' }, // 你如果要“鹦鸽镇”就改这里
// --- 北坡下撤路线 ---
{ id: 'northern_slope_bottom', name: '北坡沟底' },
{ id: 'northern_slope_channel', name: '北坡沟道' },
{ id: 'northern_slope_river', name: '北坡河道' },
{ id: 'northern_slope_ridge', name: '北坡山脊' },
{ id: 'northern_slope_cliff_1', name: '北坡悬崖段 1' },
{ id: 'northern_slope_cliff_2', name: '北坡悬崖段 2' },
{ id: 'northern_slope_cliff_3', name: '北坡悬崖段 3' },
{ id: 'northern_slope_valley_1', name: '北坡河谷段 1' },
{ id: 'northern_slope_valley_2', name: '北坡山谷段 2' },
];
// --- 物品列表 (ID -> 中文) ---
const ITEM_MAP = [
{ id: 'backpack_small', name: '45L 轻量背包' },
{ id: 'backpack_medium', name: '65L 进阶背包' },
{ id: 'backpack_large', name: '85L 重装背包' },
{ id: 'backpack_expedition', name: '100L 远征背包' },
{ id: 'poles', name: '碳纤维登山杖' },
{ id: 'knee_pads', name: '专业护膝' },
{ id: 'tent_4season', name: '高山四季帐' },
{ id: 'raincoat', name: '轻量化雨衣' },
{ id: 'wind_goggles', name: '防风护目镜' },
{ id: 'gloves', name: '防风保暖手套' },
{ id: 'mountain_windproof_hat', name: '高山防风保暖帽' },
{ id: 'balaclava', name: '防风面罩' },
{ id: 'sleeping_pad', name: '高R值防潮垫' },
{ id: 'sleeping_bag_0', name: '0°C鹅绒睡袋' },
{ id: 'sleeping_bag_10', name: '-10°C鹅绒睡袋' },
{ id: 'sleeping_bag_20', name: '-20°C鹅绒睡袋' },
{ id: 'sleeping_bag_30', name: '-30°C鹅绒睡袋' },
{ id: 'headlamp', name: '专业头灯' },
{ id: 'snowshoes', name: '简易冰爪' },
{ id: 'snow_gaiters', name: '防雪套' },
{ id: 'food_ration', name: '压缩饼干' },
{ id: 'chocolate', name: '高能黑巧克力' },
{ id: 'energy_gel', name: '能量胶' },
{ id: 'salt_pill', name: '电解质盐丸' },
{ id: 'gas_tank', name: '高山稳压气罐' },
{ id: 'stove', name: '高山稳压炉头' },
{ id: 'med_kit', name: '野外医疗包' },
{ id: 'emergency_blanket', name: '保温毯' },
{ id: 'hand_warmer', name: '暖身贴' },
{ id: 'water_filter', name: '户外净水器' },
{ id: 'rope', name: '登山绳索' },
{ id: 'gps_device', name: '手持GPS导航仪' },
{ id: 'satellite_phone', name: '卫星电话' }
];
const ALL_TITLES = [
'aotai_guardian', 'cyber_living_buddha', 'cyber_philanthropist', 'speedrun_master',
'aotai_photographer', 'aotai_savage', 'hercules', 'qinggong_master', 'biscuit_manufacturer',
'biscuit_wholesaler', 'chocolate_factory', 'wealth_scatterer', 'iron_rooster', 'old_acquaintance',
'freezing_victim', 'freezing_survivor', 'indigenous', 'wicked_master', 'unfulfilled_ambition',
'rookie_driver', 'hunger_king_title', 'aotai_powerful_donkey', 'rational_walker', 'lucky_survivor',
'tangkou_villager', 'tangkou_village_chief', 'victim', 'shennong_descendant', 'bear_grylls_disciple',
'gas_master', 'cure_all'
];
const ALL_ACHIEVEMENTS = [
// --- 58 Achievements from Web (v1.0+) ---
'first_step', 'cloud_wall', 'mountain_master', 'survivor_7d', 'survivor_3d',
'high_altitude', 'nature_lover', 'rich_hiker', 'aotai_photographer', 'kind_heart',
'orographic_slayer', 'destined_meeting', 'golden_sunrise', 'thunder_survivor', 'lnt_guardian',
'star_gazer', 'rare_beast', 'fog_walker', 'night_owl', 'bull_tamer', 'cloud_sea',
'rainbow', 'moon_phantom', 'storm_stoic', 'rainrunner', 'sunset_watcher',
'berry_taster', 'quick_meet', 'memorial_respect', 'together', 'frugal_survivor',
'qinggong_master', 'load_shedder', 'diary_keeper', 'water_connoisseur',
'lost_and_found', 'iron_grip', 'noodle_king', 'free_solo', 'ice_glider',
'generous_soul', 'wild_vet', 'iron_will', 'snow_wise', 'solitude_talk',
'rock_dodger', 'detail_oriented', 'heroic_messenger', 'wind_fighter', 'seven_times_hero',
'mountain_pact', 'spirit_guide', 'accident_survivor', 'lucky_survivor', 'hitchhiker',
'worldly_fireworks', 'equipment_guard', 'wind_repair',
// --- Potential Legacy/Save-only IDs (Keep safe) ---
'light_packer', 'water_filter_master', 'hiker_friend', 'hardship_comrade',
'lucky_panda', 'conqueror', 'photographer', 'gale_walker', 'god_of_aotai',
'solitude_survivor', 'tent_rigger'
];
// ====== 工具函数 ======
function loadPanelPrefs() {
try {
const raw = localStorage.getItem(UI_PREF_KEY);
if (!raw) return { ...IDEAL_VALUES };
const parsed = JSON.parse(raw);
return { ...IDEAL_VALUES, ...parsed };
} catch (e) { return { ...IDEAL_VALUES }; }
}
function savePanelPrefs(prefs) {
try { localStorage.setItem(UI_PREF_KEY, JSON.stringify(prefs)); } catch (e) { }
}
function normalizeNodeList(list) {
const map = new Map();
// 读用户保存的
(Array.isArray(list) ? list : []).forEach(x => {
if (!x || typeof x.id !== 'string') return;
const id = x.id.trim();
if (!id) return;
const name = (x.name || id).toString().trim() || id;
map.set(id, { id, name });
});
// 补齐默认节点(不覆盖用户自定义)
DEFAULT_NODES.forEach(d => {
if (!map.has(d.id)) map.set(d.id, { id: d.id, name: d.name || d.id });
});
return [...map.values()];
}
function loadNodeList() {
try {
const raw = localStorage.getItem(UI_NODE_LIST_KEY);
if (!raw) return normalizeNodeList(DEFAULT_NODES);
return normalizeNodeList(JSON.parse(raw));
} catch (e) { return normalizeNodeList(DEFAULT_NODES); }
}
function saveNodeList(list) {
try { localStorage.setItem(UI_NODE_LIST_KEY, JSON.stringify(normalizeNodeList(list))); } catch (e) { }
}
function upsertNode(list, id, name) {
id = (id || '').trim();
if (!id) return list;
const next = normalizeNodeList(list);
const idx = next.findIndex(x => x.id === id);
const item = { id, name: (name || id).toString().trim() || id };
if (idx >= 0) next[idx] = item;
else next.push(item);
return next;
}
function decryptData(raw) {
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
const bytes = CryptoJS.AES.decrypt(parsed.cipher, CRYPTO_KEY);
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
} catch (e) { return null; }
}
function encryptData(data) {
try {
const cipher = CryptoJS.AES.encrypt(JSON.stringify(data), CRYPTO_KEY).toString();
return JSON.stringify({ "__aotai_enc__": true, "v": 1, "cipher": cipher });
} catch (e) { return null; }
}
function dispatchStorage(key, newValue, oldValue) {
try {
window.dispatchEvent(new StorageEvent('storage', {
key, newValue, oldValue, storageArea: localStorage, url: location.href
}));
} catch (e) { }
}
function isTypingTarget(el) {
if (!el) return false;
const tag = (el.tagName || '').toLowerCase();
return tag === 'input' || tag === 'textarea' || el.isContentEditable;
}
function safeNumber(v, fallback) {
const n = Number(v);
return Number.isFinite(n) ? n : fallback;
}
function zhSort(a, b) {
return (a || '').localeCompare((b || ''), 'zh-Hans-CN');
}
// ====== UI ======
function createUI() {
if (document.getElementById(UI_ID)) return;
const prefs = loadPanelPrefs();
let nodeList = loadNodeList();
const host = document.createElement('div');
host.id = UI_ID;
host.style.cssText =
'position: fixed; top: 10px; right: 10px; z-index: 2147483647; transition: opacity 0.2s;';
document.documentElement.appendChild(host);
const shadow = host.attachShadow({ mode: 'closed' });
const container = document.createElement('div');
container.style.cssText = `
background: rgba(15, 15, 15, 0.98);
color: #00ff00;
padding: 15px;
border: 1px solid #00ff00;
border-radius: 4px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
width: 300px;
box-shadow: 0 0 15px rgba(0, 255, 0, 0.2);
max-height: 85vh;
overflow-y: auto;
`;
container.innerHTML = `
<div style="text-align:center;font-weight:bold;margin-bottom:10px;border-bottom:1px solid #00ff00;padding-bottom:6px;">
CYBER-HIKING IDEAL V7
</div>
<style>
.section-title { color:#888;font-size:10px;margin:10px 0 6px 0;text-transform:uppercase; }
.row { margin-bottom:6px; display:flex; justify-content:space-between; align-items:center; gap:8px; }
input, select {
width: 150px; background:#000; color:#0ff; border:1px solid #333;
padding:2px 4px; font-size:11px; box-sizing:border-box;
}
button {
width:100%; padding:4px; margin-top:8px; cursor:pointer;
border:1px solid #00ff00; background:transparent; color:#00ff00; font-weight:bold;
}
button:hover { background:#00ff00; color:#000; }
.btn2 { display:flex; gap:8px; margin-top:8px; }
.btn2 button { width: 50%; margin-top:0; }
#status { font-size:10px; color:#555; margin-top:10px; text-align:center; }
.small { font-size:10px; color:#777; }
</style>
<div class="section-title">基础生存属性</div>
<div class="row"><span>体温</span><input type="number" id="in-temp" step="0.1" value="${prefs.temp}"></div>
<div class="row"><span>体力</span><input type="number" id="in-stamina" value="${prefs.stamina}"></div>
<div class="row"><span>精神</span><input type="number" id="in-sanity" value="${prefs.sanity}"></div>
<div class="row"><span>饱腹</span><input type="number" id="in-hunger" value="${prefs.hunger}"></div>
<div class="section-title">进阶属性</div>
<div class="row"><span>业力</span><input type="number" id="in-karma" value="${prefs.karma}"></div>
<div class="row"><span>预算</span><input type="number" id="in-budget" value="${prefs.budget}"></div>
<div class="row"><span>负重</span><input type="number" id="in-weight" step="0.1" value="${prefs.weight}"></div>
<div class="section-title">环境与设备</div>
<div class="row"><span>当前天数</span><input type="number" id="in-day" value="${prefs.day}"></div>
<div class="row"><span>卫星电话电量</span><input type="number" id="in-battery" value="${prefs.battery}"></div>
<div class="section-title">特殊权限 & 记录</div>
<div class="row"><span>通关次数</span><input type="number" id="in-victory" value="${prefs.victoryCount}"></div>
<div class="row">
<span>山神通行证</span>
<select id="in-pass">
<option value="true" ${prefs.hasMountainGodPass ? 'selected' : ''}>已拥有 (Yes)</option>
<option value="false" ${!prefs.hasMountainGodPass ? 'selected' : ''}>未拥有 (No)</option>
</select>
</div>
<div class="row"><span>订阅(逗号隔开)</span><input type="text" id="in-subs" value="${prefs.subscriptions}" placeholder="vip, etc"></div>
<button id="apply">应用数值并刷新</button>
<div class="row" style="margin-top: 15px;">
<button id="unlock-all">解锁全成就&称号</button>
</div>
<div class="row" style="margin-top: 15px;">
<span>物品</span>
<select id="in-item" style="width: 110px;"></select>
<input type="number" id="in-item-count" value="1" style="width: 50px;" title="数量">
</div>
<div class="btn2">
<button id="add-item">添加</button>
<button id="add-all-items">全都要(+1)</button>
</div>
<div class="row" style="margin-top: 15px;">
<span>目的地</span>
<select id="in-node"></select>
</div>
<div class="small">当前节点:<span id="cur-node">读取中...</span></div>
<div class="btn2">
<button id="teleport">瞬移并刷新</button>
<button id="save-node">保存当前节点</button>
</div>
<div id="status">\` / ~ 切换显示隐藏;Ctrl+Alt+~ 强制显示</div>
`;
shadow.appendChild(container);
const $ = (id) => shadow.getElementById(id);
function getDecryptedState() {
const raw = localStorage.getItem(STORAGE_KEY);
const obj = decryptData(raw);
return { raw, obj };
}
function writeStateAndReload(newObj, oldRaw) {
const newRaw = encryptData(newObj);
if (!newRaw) return alert('加密失败,无法写入存档。');
// 1. 写入我们的数据
localStorage.setItem(STORAGE_KEY, newRaw);
dispatchStorage(STORAGE_KEY, newRaw, oldRaw);
// 2. 关键:劫持 setItem 防止游戏在 reload 前瞬间覆盖回去 (Game Auto-Save / Unload Save)
// "Cyber-Block": Block the game from overwriting our perfect save.
const originalSetItem = localStorage.setItem;
localStorage.setItem = function (key, value) {
if (key === STORAGE_KEY) {
console.log('[CyberMod] 拦截到游戏尝试覆盖存档 -> 已阻止');
return;
}
originalSetItem.call(localStorage, key, value);
};
// 3. 立即刷新,不再等待
location.reload();
}
// ... (existing helper functions) ...
$('apply').onclick = () => {
// ... (existing apply logic) ...
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
const p = readPrefsFromInputs();
savePanelPrefs(p);
obj.state.stats.temp = p.temp;
obj.state.stats.stamina = p.stamina;
obj.state.stats.sanity = p.sanity;
obj.state.stats.hunger = p.hunger;
obj.state.stats.karma = p.karma;
obj.state.budget = p.budget;
obj.state.weight = p.weight;
obj.state.day = p.day;
obj.state.satellitePhoneBattery = p.battery;
obj.state.victoryCount = p.victoryCount;
obj.state.hasMountainGodPass = p.hasMountainGodPass;
if (!obj.state.user) obj.state.user = {};
const subList = (p.subscriptions || '').split(/[,,]/).map(s => s.trim()).filter(Boolean);
obj.state.user.subscriptions = subList;
writeStateAndReload(obj, oldRaw);
};
function refreshNodeSelect(selectedId) {
const sel = $('in-node');
sel.innerHTML = '';
const sorted = [...nodeList].sort((a, b) => {
const idxA = DEFAULT_NODES.findIndex(x => x.id === a.id);
const idxB = DEFAULT_NODES.findIndex(x => x.id === b.id);
// If both are in default list, sort by index
if (idxA >= 0 && idxB >= 0) return idxA - idxB;
// If one is in default list, it comes first
if (idxA >= 0) return -1;
if (idxB >= 0) return 1;
// Otherwise sort alphabetically
return zhSort(a.name || a.id, b.name || b.id);
});
sorted.forEach(n => {
const opt = document.createElement('option');
opt.value = n.id;
opt.textContent = `${n.name || n.id} (${n.id})`;
sel.appendChild(opt);
});
if (selectedId) sel.value = selectedId;
}
function refreshItemSelect(selectedId) {
const sel = $('in-item');
sel.innerHTML = '';
ITEM_MAP.forEach(item => {
const opt = document.createElement('option');
opt.value = item.id;
opt.textContent = `${item.name} (${item.id})`;
sel.appendChild(opt);
});
if (selectedId) sel.value = selectedId;
}
function readPrefsFromInputs() {
return {
temp: safeNumber($('in-temp').value, IDEAL_VALUES.temp),
stamina: safeNumber($('in-stamina').value, IDEAL_VALUES.stamina),
sanity: safeNumber($('in-sanity').value, IDEAL_VALUES.sanity),
hunger: safeNumber($('in-hunger').value, IDEAL_VALUES.hunger),
karma: safeNumber($('in-karma').value, IDEAL_VALUES.karma),
budget: safeNumber($('in-budget').value, IDEAL_VALUES.budget),
weight: safeNumber($('in-weight').value, IDEAL_VALUES.weight),
day: parseInt($('in-day').value, 10) || IDEAL_VALUES.day,
battery: safeNumber($('in-battery').value, IDEAL_VALUES.battery),
victoryCount: safeNumber($('in-victory').value, IDEAL_VALUES.victoryCount),
hasMountainGodPass: $('in-pass').value === 'true',
subscriptions: $('in-subs').value || '',
lastItemId: $('in-item').value,
};
}
// 数值输入即记忆
['in-temp', 'in-stamina', 'in-sanity', 'in-hunger', 'in-karma', 'in-budget', 'in-weight', 'in-day', 'in-battery',
'in-victory', 'in-pass', 'in-subs', 'in-item']
.forEach(id => {
const el = $(id);
el.addEventListener('input', () => savePanelPrefs(readPrefsFromInputs()));
el.addEventListener('change', () => savePanelPrefs(readPrefsFromInputs()));
});
// init:同步当前节点 + 确保自动收集
(function initNodeUI() {
nodeList = loadNodeList();
const { obj } = getDecryptedState();
const cur = obj?.state?.currentNodeId || '(未知)';
$('cur-node').textContent = cur;
// 自动把当前节点加入列表(如果不在默认里)
if (cur && cur !== '(未知)') {
const found = nodeList.find(x => x.id === cur);
nodeList = upsertNode(nodeList, cur, found?.name || cur);
saveNodeList(nodeList);
}
refreshNodeSelect(cur);
refreshItemSelect(prefs.lastItemId);
})();
$('apply').onclick = () => {
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
const p = readPrefsFromInputs();
savePanelPrefs(p);
obj.state.stats.temp = p.temp;
obj.state.stats.stamina = p.stamina;
obj.state.stats.sanity = p.sanity;
obj.state.stats.hunger = p.hunger;
obj.state.stats.karma = p.karma;
obj.state.budget = p.budget;
obj.state.weight = p.weight;
obj.state.day = p.day;
obj.state.satellitePhoneBattery = p.battery;
// New features
obj.state.victoryCount = p.victoryCount;
obj.state.hasMountainGodPass = p.hasMountainGodPass;
// Subscriptions parsing
if (!obj.state.user) obj.state.user = {};
const subList = (p.subscriptions || '').split(/[,,]/).map(s => s.trim()).filter(Boolean);
obj.state.user.subscriptions = subList;
writeStateAndReload(obj, oldRaw);
};
$('add-item').onclick = () => {
const itemId = $('in-item').value;
const countStr = $('in-item-count').value;
const count = parseInt(countStr, 10) || 1;
if (!itemId) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.inventory) obj.state.inventory = {};
const currentCount = obj.state.inventory[itemId] || 0;
obj.state.inventory[itemId] = currentCount + count;
writeStateAndReload(obj, oldRaw);
};
$('add-all-items').onclick = () => {
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.inventory) obj.state.inventory = {};
ITEM_MAP.forEach(item => {
const cid = item.id;
const currentCount = obj.state.inventory[cid] || 0;
obj.state.inventory[cid] = currentCount + 1;
});
writeStateAndReload(obj, oldRaw);
};
$('teleport').onclick = () => {
const target = $('in-node').value;
if (!target) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
obj.state.currentNodeId = target;
obj.state.pendingTransition = null;
obj.state.currentEvent = null;
obj.state.currentMission = null;
writeStateAndReload(obj, oldRaw);
};
$('save-node').onclick = () => {
const { obj } = getDecryptedState();
const cur = obj?.state?.currentNodeId;
if (!cur) return alert('当前节点未知');
// 若默认表里有中文就用中文;否则用 id 占位
const fromDefault = DEFAULT_NODES.find(x => x.id === cur);
nodeList = upsertNode(nodeList, cur, fromDefault?.name || cur);
saveNodeList(nodeList);
// 立刻刷新下拉(你会马上看到新增)
refreshNodeSelect(cur);
alert(`✅ 已保存当前节点:${fromDefault?.name || cur} (${cur})`);
};
$('unlock-all').onclick = () => {
if (!confirm('确定要解锁所有 31 个称号和 69 个成就吗?\n这将直接修改存档记录。')) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.user) obj.state.user = {};
// Init arrays if missing
obj.state.user.titles = obj.state.user.titles || [];
obj.state.unlockedTitles = obj.state.unlockedTitles || [];
obj.state.user.achievements = obj.state.user.achievements || [];
obj.state.unlockedAchievements = obj.state.unlockedAchievements || [];
let addedT = 0;
let addedA = 0;
// Add Titles
const userTitlesSet = new Set(obj.state.user.titles);
const unlockedTitlesSet = new Set(obj.state.unlockedTitles);
ALL_TITLES.forEach(t => {
if (!userTitlesSet.has(t)) { userTitlesSet.add(t); addedT++; }
if (!unlockedTitlesSet.has(t)) { unlockedTitlesSet.add(t); }
});
obj.state.user.titles = Array.from(userTitlesSet);
obj.state.unlockedTitles = Array.from(unlockedTitlesSet);
// Add Achievements
const userAchSet = new Set(obj.state.user.achievements);
const unlockedAchSet = new Set(obj.state.unlockedAchievements);
ALL_ACHIEVEMENTS.forEach(a => {
if (!userAchSet.has(a)) { userAchSet.add(a); addedA++; }
if (!unlockedAchSet.has(a)) { unlockedAchSet.add(a); }
});
obj.state.user.achievements = Array.from(userAchSet);
obj.state.unlockedAchievements = Array.from(unlockedAchSet);
writeStateAndReload(obj, oldRaw);
};
}
// --- 快捷键 ---
function bindHotkey() {
document.addEventListener('keydown', (e) => {
// 兜底强制显示
if (e.ctrlKey && e.altKey && e.code === 'Backquote') {
const host = document.getElementById(UI_ID);
if (host) {
isVisible = true;
host.style.opacity = '1';
host.style.pointerEvents = 'auto';
} else {
createUI();
}
e.preventDefault();
e.stopPropagation();
return;
}
if (isTypingTarget(e.target)) return;
const isBackquoteKey = (e.code === 'Backquote' && !e.ctrlKey && !e.altKey && !e.metaKey);
if (!isBackquoteKey) return;
e.preventDefault();
e.stopPropagation();
if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
const host = document.getElementById(UI_ID);
if (!host) return;
isVisible = !isVisible;
host.style.opacity = isVisible ? '1' : '0';
host.style.pointerEvents = isVisible ? 'auto' : 'none';
}, true);
}
// --- 注入持久化 ---
const observer = new MutationObserver(() => {
if (!document.getElementById(UI_ID)) createUI();
});
function init() {
createUI();
bindHotkey();
observer.observe(document.documentElement, { childList: true, subtree: true });
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();
image453×879 63.7 KBimage447×875 54.8 KBimage448×879 44.1 KB
image451×878 58.3 KBimage450×879 57.5 KBimage454×882 47.3 KB
--【壹】--:
4块饼干能成功吗 游戏结束可以晒一下称号哈哈
--【贰】--:
有点意思 有空玩玩
--【叁】--:
挺好玩的 建议不用脚本玩一下
--【肆】--:
哈哈哈哈哈哈有意思!
--【伍】--:
游戏做的挺好的 作者一直在更新
--【陆】--:
我真求你了 哈哈哈哈
--【柒】--:
不建议用脚本 原汁原味挺有意思 挺极限
--【捌】--:
hiking变成hacking了
--【玖】--:
好么 紧贴热点
--【拾】--:
牛逼
--【拾壹】--:
哈哈哈 这也能整个脚本
--【拾贰】--:
感谢大佬 。
--【拾叁】--:
你好水王
--【拾肆】--:
好有意思 饿了还会眼花
--【拾伍】--:
哈哈哈 挺好玩的 建议玩一下
--【拾陆】--:
这是一个梗 陈某放
--【拾柒】--:
嗯呐 鳌太线吞噬太多人了
--【拾捌】--:
我就带4块压缩饼干
image2520×252 48.7 KB
--【拾玖】--:
好玩,就是第一次玩就被冻死了
上一个帖子不能编辑了 特开新帖
游戏地址:赛博徒步:生死鳌太线 | 一场关于意志与生存的终极考验
image1552×852 108 KB
image791×592 41.4 KB
很久之前就有佬友推荐过 作者一直在更新 随着细节丰富 越来越真实了
没有徒步经验的佬友可以体验一下到底有多难
附上我迭代更新了一个月的脚本:不建议用 用了就没意思了
①解锁付费订阅 支持付费下撤路线(你没看错有氪金项目 还有反调试)
②解锁并未开放的卫星电话 可以救驴友远山了
③解锁全成就&称号
④全物品添加&全地点瞬移
⑤修改属性(体温、体力、精神、饱腹、业力、预算、负重、天数、电话电量)
Tips:在死亡界面修改属性可以强行原地复活
// ==UserScript==
// @name 赛博徒步:生死鳌太线 理想值修改器 V7
// @namespace http://tampermonkey.net/
// @version 7.0
// @description 数值修改 + `/~ 显示隐藏 + 面板记忆 + 节点瞬移(中文下拉+自动收集新节点+仅保留“保存当前节点”)
// @author @Wet_Dream_Boy
// @match https://cyberhiking.com/*
// @grant none
// @run-at document-start
// @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// ==/UserScript==
(function () {
'use strict';
const STORAGE_KEY = 'aotai-survival-storage';
const CRYPTO_KEY = 'aotai-survival@2024';
const UI_ID = 'cyber-mod-v6-root';
// 面板输入记忆
const UI_PREF_KEY = 'aotai-ideal-panel-values-v6';
// 节点列表记忆(下拉中文/自动新增也会保存)
const UI_NODE_LIST_KEY = 'aotai-node-list-v6';
let isVisible = true;
// --- 理想默认值配置 ---
const IDEAL_VALUES = {
temp: 36.5,
stamina: 100,
sanity: 100,
hunger: 100,
karma: 1000,
budget: 99999,
weight: 0.1,
day: 1,
battery: 100,
victoryCount: 9,
hasMountainGodPass: false,
subscriptions: '',
lastItemId: 'backpack_expedition',
};
// --- 默认节点(你在脚本里维护;下拉中文显示)---
const DEFAULT_NODES = [
// --- 正常路线 (塘口 -> 南塬) ---
{ id: 'tangkou', name: '塘口' },
{ id: 'longwanghekou', name: '龙王河口' },
{ id: 'xihuagou', name: '西桦沟' }, // ✅ 修正
{ id: 'huoshaopo', name: '火烧坡' },
{ id: 'camp_2900', name: '2900营地' },
{ id: 'penjingyuan', name: '盆景园' },
{ id: 'baiqimiao', name: '白起庙' },
{ id: 'aotou', name: '鳌头' },
{ id: 'aoshanding', name: '鳌山顶' },
{ id: 'west_paoma', name: '西跑马梁' },
{ id: 'yaowangmiao', name: '药王庙' },
{ id: 'maijie_ridge', name: '麦秸岭' },
{ id: 'wenxiong_stone', name: '文胸石' }, // ✅ 修正
{ id: 'shuiwozi', name: '水窝子' },
{ id: 'monument', name: '纪念碑' }, // 纪念碑通常在水窝子到飞机梁之间
{ id: 'feiji_liang', name: '飞机梁' }, // ✅ 按你要求:不动
{ id: 'liang_yi', name: '梁一' },
{ id: 'liang_er', name: '梁二' },
{ id: 'liang_san', name: '梁三' },
{ id: 'camp_2800', name: '2800营地' },
{ id: 'nantianmen_pass', name: '南天门垭口' }, // ✅ 保持你的写法
{ id: 'nantianmen_forest', name: '南天门林区' },
{ id: 'nantianmen_camp', name: '南天门营地' },
{ id: 'pyramid', name: '金字塔' },
{ id: 'ta_yi', name: '塔一' },
{ id: 'ta_er', name: '塔二' },
{ id: 'ta_san', name: '塔三' },
{ id: 'jiuchongtian', name: '九重天' },
{ id: 'xiyuan_camp', name: '西源营地' },
{ id: 'dongyuan_camp', name: '东源营地' },
{ id: 'wanxian_array', name: '万仙阵' },
{ id: 'leigong_temple', name: '雷公庙' },
{ id: 'paoma_liang', name: '跑马梁' },
{ id: 'dayehai', name: '大爷海' },
{ id: 'dawengong_temple', name: '大文公庙' },
{ id: 'fangyang_temple', name: '放羊寺' },
{ id: 'mingxing_temple', name: '明星寺' },
{ id: 'pingan_temple', name: '平安寺' },
{ id: 'nanyuan_village', name: '南塬村' },
// --- 下撤/支线/其他 ---
{ id: 'qiaodiping', name: '桥底坪' },
{ id: 'baiyun_bridge', name: '白云桥' },
{ id: 'baiyun_gorge_new', name: '白云峡谷(新)' },
{ id: 'maershan_village', name: '马耳山村' },
{ id: 'yingge_town', name: '鹦哥镇' }, // 你如果要“鹦鸽镇”就改这里
// --- 北坡下撤路线 ---
{ id: 'northern_slope_bottom', name: '北坡沟底' },
{ id: 'northern_slope_channel', name: '北坡沟道' },
{ id: 'northern_slope_river', name: '北坡河道' },
{ id: 'northern_slope_ridge', name: '北坡山脊' },
{ id: 'northern_slope_cliff_1', name: '北坡悬崖段 1' },
{ id: 'northern_slope_cliff_2', name: '北坡悬崖段 2' },
{ id: 'northern_slope_cliff_3', name: '北坡悬崖段 3' },
{ id: 'northern_slope_valley_1', name: '北坡河谷段 1' },
{ id: 'northern_slope_valley_2', name: '北坡山谷段 2' },
];
// --- 物品列表 (ID -> 中文) ---
const ITEM_MAP = [
{ id: 'backpack_small', name: '45L 轻量背包' },
{ id: 'backpack_medium', name: '65L 进阶背包' },
{ id: 'backpack_large', name: '85L 重装背包' },
{ id: 'backpack_expedition', name: '100L 远征背包' },
{ id: 'poles', name: '碳纤维登山杖' },
{ id: 'knee_pads', name: '专业护膝' },
{ id: 'tent_4season', name: '高山四季帐' },
{ id: 'raincoat', name: '轻量化雨衣' },
{ id: 'wind_goggles', name: '防风护目镜' },
{ id: 'gloves', name: '防风保暖手套' },
{ id: 'mountain_windproof_hat', name: '高山防风保暖帽' },
{ id: 'balaclava', name: '防风面罩' },
{ id: 'sleeping_pad', name: '高R值防潮垫' },
{ id: 'sleeping_bag_0', name: '0°C鹅绒睡袋' },
{ id: 'sleeping_bag_10', name: '-10°C鹅绒睡袋' },
{ id: 'sleeping_bag_20', name: '-20°C鹅绒睡袋' },
{ id: 'sleeping_bag_30', name: '-30°C鹅绒睡袋' },
{ id: 'headlamp', name: '专业头灯' },
{ id: 'snowshoes', name: '简易冰爪' },
{ id: 'snow_gaiters', name: '防雪套' },
{ id: 'food_ration', name: '压缩饼干' },
{ id: 'chocolate', name: '高能黑巧克力' },
{ id: 'energy_gel', name: '能量胶' },
{ id: 'salt_pill', name: '电解质盐丸' },
{ id: 'gas_tank', name: '高山稳压气罐' },
{ id: 'stove', name: '高山稳压炉头' },
{ id: 'med_kit', name: '野外医疗包' },
{ id: 'emergency_blanket', name: '保温毯' },
{ id: 'hand_warmer', name: '暖身贴' },
{ id: 'water_filter', name: '户外净水器' },
{ id: 'rope', name: '登山绳索' },
{ id: 'gps_device', name: '手持GPS导航仪' },
{ id: 'satellite_phone', name: '卫星电话' }
];
const ALL_TITLES = [
'aotai_guardian', 'cyber_living_buddha', 'cyber_philanthropist', 'speedrun_master',
'aotai_photographer', 'aotai_savage', 'hercules', 'qinggong_master', 'biscuit_manufacturer',
'biscuit_wholesaler', 'chocolate_factory', 'wealth_scatterer', 'iron_rooster', 'old_acquaintance',
'freezing_victim', 'freezing_survivor', 'indigenous', 'wicked_master', 'unfulfilled_ambition',
'rookie_driver', 'hunger_king_title', 'aotai_powerful_donkey', 'rational_walker', 'lucky_survivor',
'tangkou_villager', 'tangkou_village_chief', 'victim', 'shennong_descendant', 'bear_grylls_disciple',
'gas_master', 'cure_all'
];
const ALL_ACHIEVEMENTS = [
// --- 58 Achievements from Web (v1.0+) ---
'first_step', 'cloud_wall', 'mountain_master', 'survivor_7d', 'survivor_3d',
'high_altitude', 'nature_lover', 'rich_hiker', 'aotai_photographer', 'kind_heart',
'orographic_slayer', 'destined_meeting', 'golden_sunrise', 'thunder_survivor', 'lnt_guardian',
'star_gazer', 'rare_beast', 'fog_walker', 'night_owl', 'bull_tamer', 'cloud_sea',
'rainbow', 'moon_phantom', 'storm_stoic', 'rainrunner', 'sunset_watcher',
'berry_taster', 'quick_meet', 'memorial_respect', 'together', 'frugal_survivor',
'qinggong_master', 'load_shedder', 'diary_keeper', 'water_connoisseur',
'lost_and_found', 'iron_grip', 'noodle_king', 'free_solo', 'ice_glider',
'generous_soul', 'wild_vet', 'iron_will', 'snow_wise', 'solitude_talk',
'rock_dodger', 'detail_oriented', 'heroic_messenger', 'wind_fighter', 'seven_times_hero',
'mountain_pact', 'spirit_guide', 'accident_survivor', 'lucky_survivor', 'hitchhiker',
'worldly_fireworks', 'equipment_guard', 'wind_repair',
// --- Potential Legacy/Save-only IDs (Keep safe) ---
'light_packer', 'water_filter_master', 'hiker_friend', 'hardship_comrade',
'lucky_panda', 'conqueror', 'photographer', 'gale_walker', 'god_of_aotai',
'solitude_survivor', 'tent_rigger'
];
// ====== 工具函数 ======
function loadPanelPrefs() {
try {
const raw = localStorage.getItem(UI_PREF_KEY);
if (!raw) return { ...IDEAL_VALUES };
const parsed = JSON.parse(raw);
return { ...IDEAL_VALUES, ...parsed };
} catch (e) { return { ...IDEAL_VALUES }; }
}
function savePanelPrefs(prefs) {
try { localStorage.setItem(UI_PREF_KEY, JSON.stringify(prefs)); } catch (e) { }
}
function normalizeNodeList(list) {
const map = new Map();
// 读用户保存的
(Array.isArray(list) ? list : []).forEach(x => {
if (!x || typeof x.id !== 'string') return;
const id = x.id.trim();
if (!id) return;
const name = (x.name || id).toString().trim() || id;
map.set(id, { id, name });
});
// 补齐默认节点(不覆盖用户自定义)
DEFAULT_NODES.forEach(d => {
if (!map.has(d.id)) map.set(d.id, { id: d.id, name: d.name || d.id });
});
return [...map.values()];
}
function loadNodeList() {
try {
const raw = localStorage.getItem(UI_NODE_LIST_KEY);
if (!raw) return normalizeNodeList(DEFAULT_NODES);
return normalizeNodeList(JSON.parse(raw));
} catch (e) { return normalizeNodeList(DEFAULT_NODES); }
}
function saveNodeList(list) {
try { localStorage.setItem(UI_NODE_LIST_KEY, JSON.stringify(normalizeNodeList(list))); } catch (e) { }
}
function upsertNode(list, id, name) {
id = (id || '').trim();
if (!id) return list;
const next = normalizeNodeList(list);
const idx = next.findIndex(x => x.id === id);
const item = { id, name: (name || id).toString().trim() || id };
if (idx >= 0) next[idx] = item;
else next.push(item);
return next;
}
function decryptData(raw) {
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
const bytes = CryptoJS.AES.decrypt(parsed.cipher, CRYPTO_KEY);
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
} catch (e) { return null; }
}
function encryptData(data) {
try {
const cipher = CryptoJS.AES.encrypt(JSON.stringify(data), CRYPTO_KEY).toString();
return JSON.stringify({ "__aotai_enc__": true, "v": 1, "cipher": cipher });
} catch (e) { return null; }
}
function dispatchStorage(key, newValue, oldValue) {
try {
window.dispatchEvent(new StorageEvent('storage', {
key, newValue, oldValue, storageArea: localStorage, url: location.href
}));
} catch (e) { }
}
function isTypingTarget(el) {
if (!el) return false;
const tag = (el.tagName || '').toLowerCase();
return tag === 'input' || tag === 'textarea' || el.isContentEditable;
}
function safeNumber(v, fallback) {
const n = Number(v);
return Number.isFinite(n) ? n : fallback;
}
function zhSort(a, b) {
return (a || '').localeCompare((b || ''), 'zh-Hans-CN');
}
// ====== UI ======
function createUI() {
if (document.getElementById(UI_ID)) return;
const prefs = loadPanelPrefs();
let nodeList = loadNodeList();
const host = document.createElement('div');
host.id = UI_ID;
host.style.cssText =
'position: fixed; top: 10px; right: 10px; z-index: 2147483647; transition: opacity 0.2s;';
document.documentElement.appendChild(host);
const shadow = host.attachShadow({ mode: 'closed' });
const container = document.createElement('div');
container.style.cssText = `
background: rgba(15, 15, 15, 0.98);
color: #00ff00;
padding: 15px;
border: 1px solid #00ff00;
border-radius: 4px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 12px;
width: 300px;
box-shadow: 0 0 15px rgba(0, 255, 0, 0.2);
max-height: 85vh;
overflow-y: auto;
`;
container.innerHTML = `
<div style="text-align:center;font-weight:bold;margin-bottom:10px;border-bottom:1px solid #00ff00;padding-bottom:6px;">
CYBER-HIKING IDEAL V7
</div>
<style>
.section-title { color:#888;font-size:10px;margin:10px 0 6px 0;text-transform:uppercase; }
.row { margin-bottom:6px; display:flex; justify-content:space-between; align-items:center; gap:8px; }
input, select {
width: 150px; background:#000; color:#0ff; border:1px solid #333;
padding:2px 4px; font-size:11px; box-sizing:border-box;
}
button {
width:100%; padding:4px; margin-top:8px; cursor:pointer;
border:1px solid #00ff00; background:transparent; color:#00ff00; font-weight:bold;
}
button:hover { background:#00ff00; color:#000; }
.btn2 { display:flex; gap:8px; margin-top:8px; }
.btn2 button { width: 50%; margin-top:0; }
#status { font-size:10px; color:#555; margin-top:10px; text-align:center; }
.small { font-size:10px; color:#777; }
</style>
<div class="section-title">基础生存属性</div>
<div class="row"><span>体温</span><input type="number" id="in-temp" step="0.1" value="${prefs.temp}"></div>
<div class="row"><span>体力</span><input type="number" id="in-stamina" value="${prefs.stamina}"></div>
<div class="row"><span>精神</span><input type="number" id="in-sanity" value="${prefs.sanity}"></div>
<div class="row"><span>饱腹</span><input type="number" id="in-hunger" value="${prefs.hunger}"></div>
<div class="section-title">进阶属性</div>
<div class="row"><span>业力</span><input type="number" id="in-karma" value="${prefs.karma}"></div>
<div class="row"><span>预算</span><input type="number" id="in-budget" value="${prefs.budget}"></div>
<div class="row"><span>负重</span><input type="number" id="in-weight" step="0.1" value="${prefs.weight}"></div>
<div class="section-title">环境与设备</div>
<div class="row"><span>当前天数</span><input type="number" id="in-day" value="${prefs.day}"></div>
<div class="row"><span>卫星电话电量</span><input type="number" id="in-battery" value="${prefs.battery}"></div>
<div class="section-title">特殊权限 & 记录</div>
<div class="row"><span>通关次数</span><input type="number" id="in-victory" value="${prefs.victoryCount}"></div>
<div class="row">
<span>山神通行证</span>
<select id="in-pass">
<option value="true" ${prefs.hasMountainGodPass ? 'selected' : ''}>已拥有 (Yes)</option>
<option value="false" ${!prefs.hasMountainGodPass ? 'selected' : ''}>未拥有 (No)</option>
</select>
</div>
<div class="row"><span>订阅(逗号隔开)</span><input type="text" id="in-subs" value="${prefs.subscriptions}" placeholder="vip, etc"></div>
<button id="apply">应用数值并刷新</button>
<div class="row" style="margin-top: 15px;">
<button id="unlock-all">解锁全成就&称号</button>
</div>
<div class="row" style="margin-top: 15px;">
<span>物品</span>
<select id="in-item" style="width: 110px;"></select>
<input type="number" id="in-item-count" value="1" style="width: 50px;" title="数量">
</div>
<div class="btn2">
<button id="add-item">添加</button>
<button id="add-all-items">全都要(+1)</button>
</div>
<div class="row" style="margin-top: 15px;">
<span>目的地</span>
<select id="in-node"></select>
</div>
<div class="small">当前节点:<span id="cur-node">读取中...</span></div>
<div class="btn2">
<button id="teleport">瞬移并刷新</button>
<button id="save-node">保存当前节点</button>
</div>
<div id="status">\` / ~ 切换显示隐藏;Ctrl+Alt+~ 强制显示</div>
`;
shadow.appendChild(container);
const $ = (id) => shadow.getElementById(id);
function getDecryptedState() {
const raw = localStorage.getItem(STORAGE_KEY);
const obj = decryptData(raw);
return { raw, obj };
}
function writeStateAndReload(newObj, oldRaw) {
const newRaw = encryptData(newObj);
if (!newRaw) return alert('加密失败,无法写入存档。');
// 1. 写入我们的数据
localStorage.setItem(STORAGE_KEY, newRaw);
dispatchStorage(STORAGE_KEY, newRaw, oldRaw);
// 2. 关键:劫持 setItem 防止游戏在 reload 前瞬间覆盖回去 (Game Auto-Save / Unload Save)
// "Cyber-Block": Block the game from overwriting our perfect save.
const originalSetItem = localStorage.setItem;
localStorage.setItem = function (key, value) {
if (key === STORAGE_KEY) {
console.log('[CyberMod] 拦截到游戏尝试覆盖存档 -> 已阻止');
return;
}
originalSetItem.call(localStorage, key, value);
};
// 3. 立即刷新,不再等待
location.reload();
}
// ... (existing helper functions) ...
$('apply').onclick = () => {
// ... (existing apply logic) ...
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
const p = readPrefsFromInputs();
savePanelPrefs(p);
obj.state.stats.temp = p.temp;
obj.state.stats.stamina = p.stamina;
obj.state.stats.sanity = p.sanity;
obj.state.stats.hunger = p.hunger;
obj.state.stats.karma = p.karma;
obj.state.budget = p.budget;
obj.state.weight = p.weight;
obj.state.day = p.day;
obj.state.satellitePhoneBattery = p.battery;
obj.state.victoryCount = p.victoryCount;
obj.state.hasMountainGodPass = p.hasMountainGodPass;
if (!obj.state.user) obj.state.user = {};
const subList = (p.subscriptions || '').split(/[,,]/).map(s => s.trim()).filter(Boolean);
obj.state.user.subscriptions = subList;
writeStateAndReload(obj, oldRaw);
};
function refreshNodeSelect(selectedId) {
const sel = $('in-node');
sel.innerHTML = '';
const sorted = [...nodeList].sort((a, b) => {
const idxA = DEFAULT_NODES.findIndex(x => x.id === a.id);
const idxB = DEFAULT_NODES.findIndex(x => x.id === b.id);
// If both are in default list, sort by index
if (idxA >= 0 && idxB >= 0) return idxA - idxB;
// If one is in default list, it comes first
if (idxA >= 0) return -1;
if (idxB >= 0) return 1;
// Otherwise sort alphabetically
return zhSort(a.name || a.id, b.name || b.id);
});
sorted.forEach(n => {
const opt = document.createElement('option');
opt.value = n.id;
opt.textContent = `${n.name || n.id} (${n.id})`;
sel.appendChild(opt);
});
if (selectedId) sel.value = selectedId;
}
function refreshItemSelect(selectedId) {
const sel = $('in-item');
sel.innerHTML = '';
ITEM_MAP.forEach(item => {
const opt = document.createElement('option');
opt.value = item.id;
opt.textContent = `${item.name} (${item.id})`;
sel.appendChild(opt);
});
if (selectedId) sel.value = selectedId;
}
function readPrefsFromInputs() {
return {
temp: safeNumber($('in-temp').value, IDEAL_VALUES.temp),
stamina: safeNumber($('in-stamina').value, IDEAL_VALUES.stamina),
sanity: safeNumber($('in-sanity').value, IDEAL_VALUES.sanity),
hunger: safeNumber($('in-hunger').value, IDEAL_VALUES.hunger),
karma: safeNumber($('in-karma').value, IDEAL_VALUES.karma),
budget: safeNumber($('in-budget').value, IDEAL_VALUES.budget),
weight: safeNumber($('in-weight').value, IDEAL_VALUES.weight),
day: parseInt($('in-day').value, 10) || IDEAL_VALUES.day,
battery: safeNumber($('in-battery').value, IDEAL_VALUES.battery),
victoryCount: safeNumber($('in-victory').value, IDEAL_VALUES.victoryCount),
hasMountainGodPass: $('in-pass').value === 'true',
subscriptions: $('in-subs').value || '',
lastItemId: $('in-item').value,
};
}
// 数值输入即记忆
['in-temp', 'in-stamina', 'in-sanity', 'in-hunger', 'in-karma', 'in-budget', 'in-weight', 'in-day', 'in-battery',
'in-victory', 'in-pass', 'in-subs', 'in-item']
.forEach(id => {
const el = $(id);
el.addEventListener('input', () => savePanelPrefs(readPrefsFromInputs()));
el.addEventListener('change', () => savePanelPrefs(readPrefsFromInputs()));
});
// init:同步当前节点 + 确保自动收集
(function initNodeUI() {
nodeList = loadNodeList();
const { obj } = getDecryptedState();
const cur = obj?.state?.currentNodeId || '(未知)';
$('cur-node').textContent = cur;
// 自动把当前节点加入列表(如果不在默认里)
if (cur && cur !== '(未知)') {
const found = nodeList.find(x => x.id === cur);
nodeList = upsertNode(nodeList, cur, found?.name || cur);
saveNodeList(nodeList);
}
refreshNodeSelect(cur);
refreshItemSelect(prefs.lastItemId);
})();
$('apply').onclick = () => {
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
const p = readPrefsFromInputs();
savePanelPrefs(p);
obj.state.stats.temp = p.temp;
obj.state.stats.stamina = p.stamina;
obj.state.stats.sanity = p.sanity;
obj.state.stats.hunger = p.hunger;
obj.state.stats.karma = p.karma;
obj.state.budget = p.budget;
obj.state.weight = p.weight;
obj.state.day = p.day;
obj.state.satellitePhoneBattery = p.battery;
// New features
obj.state.victoryCount = p.victoryCount;
obj.state.hasMountainGodPass = p.hasMountainGodPass;
// Subscriptions parsing
if (!obj.state.user) obj.state.user = {};
const subList = (p.subscriptions || '').split(/[,,]/).map(s => s.trim()).filter(Boolean);
obj.state.user.subscriptions = subList;
writeStateAndReload(obj, oldRaw);
};
$('add-item').onclick = () => {
const itemId = $('in-item').value;
const countStr = $('in-item-count').value;
const count = parseInt(countStr, 10) || 1;
if (!itemId) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.inventory) obj.state.inventory = {};
const currentCount = obj.state.inventory[itemId] || 0;
obj.state.inventory[itemId] = currentCount + count;
writeStateAndReload(obj, oldRaw);
};
$('add-all-items').onclick = () => {
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.inventory) obj.state.inventory = {};
ITEM_MAP.forEach(item => {
const cid = item.id;
const currentCount = obj.state.inventory[cid] || 0;
obj.state.inventory[cid] = currentCount + 1;
});
writeStateAndReload(obj, oldRaw);
};
$('teleport').onclick = () => {
const target = $('in-node').value;
if (!target) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
obj.state.currentNodeId = target;
obj.state.pendingTransition = null;
obj.state.currentEvent = null;
obj.state.currentMission = null;
writeStateAndReload(obj, oldRaw);
};
$('save-node').onclick = () => {
const { obj } = getDecryptedState();
const cur = obj?.state?.currentNodeId;
if (!cur) return alert('当前节点未知');
// 若默认表里有中文就用中文;否则用 id 占位
const fromDefault = DEFAULT_NODES.find(x => x.id === cur);
nodeList = upsertNode(nodeList, cur, fromDefault?.name || cur);
saveNodeList(nodeList);
// 立刻刷新下拉(你会马上看到新增)
refreshNodeSelect(cur);
alert(`✅ 已保存当前节点:${fromDefault?.name || cur} (${cur})`);
};
$('unlock-all').onclick = () => {
if (!confirm('确定要解锁所有 31 个称号和 69 个成就吗?\n这将直接修改存档记录。')) return;
const { raw: oldRaw, obj } = getDecryptedState();
if (!obj?.state) return alert('未找到存档数据,请先开始游戏!');
if (!obj.state.user) obj.state.user = {};
// Init arrays if missing
obj.state.user.titles = obj.state.user.titles || [];
obj.state.unlockedTitles = obj.state.unlockedTitles || [];
obj.state.user.achievements = obj.state.user.achievements || [];
obj.state.unlockedAchievements = obj.state.unlockedAchievements || [];
let addedT = 0;
let addedA = 0;
// Add Titles
const userTitlesSet = new Set(obj.state.user.titles);
const unlockedTitlesSet = new Set(obj.state.unlockedTitles);
ALL_TITLES.forEach(t => {
if (!userTitlesSet.has(t)) { userTitlesSet.add(t); addedT++; }
if (!unlockedTitlesSet.has(t)) { unlockedTitlesSet.add(t); }
});
obj.state.user.titles = Array.from(userTitlesSet);
obj.state.unlockedTitles = Array.from(unlockedTitlesSet);
// Add Achievements
const userAchSet = new Set(obj.state.user.achievements);
const unlockedAchSet = new Set(obj.state.unlockedAchievements);
ALL_ACHIEVEMENTS.forEach(a => {
if (!userAchSet.has(a)) { userAchSet.add(a); addedA++; }
if (!unlockedAchSet.has(a)) { unlockedAchSet.add(a); }
});
obj.state.user.achievements = Array.from(userAchSet);
obj.state.unlockedAchievements = Array.from(unlockedAchSet);
writeStateAndReload(obj, oldRaw);
};
}
// --- 快捷键 ---
function bindHotkey() {
document.addEventListener('keydown', (e) => {
// 兜底强制显示
if (e.ctrlKey && e.altKey && e.code === 'Backquote') {
const host = document.getElementById(UI_ID);
if (host) {
isVisible = true;
host.style.opacity = '1';
host.style.pointerEvents = 'auto';
} else {
createUI();
}
e.preventDefault();
e.stopPropagation();
return;
}
if (isTypingTarget(e.target)) return;
const isBackquoteKey = (e.code === 'Backquote' && !e.ctrlKey && !e.altKey && !e.metaKey);
if (!isBackquoteKey) return;
e.preventDefault();
e.stopPropagation();
if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
const host = document.getElementById(UI_ID);
if (!host) return;
isVisible = !isVisible;
host.style.opacity = isVisible ? '1' : '0';
host.style.pointerEvents = isVisible ? 'auto' : 'none';
}, true);
}
// --- 注入持久化 ---
const observer = new MutationObserver(() => {
if (!document.getElementById(UI_ID)) createUI();
});
function init() {
createUI();
bindHotkey();
observer.observe(document.documentElement, { childList: true, subtree: true });
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();
image453×879 63.7 KBimage447×875 54.8 KBimage448×879 44.1 KB
image451×878 58.3 KBimage450×879 57.5 KBimage454×882 47.3 KB
--【壹】--:
4块饼干能成功吗 游戏结束可以晒一下称号哈哈
--【贰】--:
有点意思 有空玩玩
--【叁】--:
挺好玩的 建议不用脚本玩一下
--【肆】--:
哈哈哈哈哈哈有意思!
--【伍】--:
游戏做的挺好的 作者一直在更新
--【陆】--:
我真求你了 哈哈哈哈
--【柒】--:
不建议用脚本 原汁原味挺有意思 挺极限
--【捌】--:
hiking变成hacking了
--【玖】--:
好么 紧贴热点
--【拾】--:
牛逼
--【拾壹】--:
哈哈哈 这也能整个脚本
--【拾贰】--:
感谢大佬 。
--【拾叁】--:
你好水王
--【拾肆】--:
好有意思 饿了还会眼花
--【拾伍】--:
哈哈哈 挺好玩的 建议玩一下
--【拾陆】--:
这是一个梗 陈某放
--【拾柒】--:
嗯呐 鳌太线吞噬太多人了
--【拾捌】--:
我就带4块压缩饼干
image2520×252 48.7 KB
--【拾玖】--:
好玩,就是第一次玩就被冻死了

