feat: initial commit for TheFarmer project
This commit is contained in:
474
server/tools/calc-exp-yield.js
Normal file
474
server/tools/calc-exp-yield.js
Normal file
@@ -0,0 +1,474 @@
|
||||
/**
|
||||
* 基于 tools/seed-shop-merged-export.json 计算经验收益率
|
||||
*
|
||||
* 规则:
|
||||
* 1) 每次收获经验 = exp(新版已去除铲地+1经验)
|
||||
* 2) 种植速度:
|
||||
* - 不施肥:2 秒种 18 块地 => 9 块/秒
|
||||
* - 普通肥:2 秒种 12 块地 => 6 块/秒
|
||||
* 3) 普通肥:直接减少一个生长阶段(按 Plant.json 的 grow_phases 取首个非0阶段时长)
|
||||
*
|
||||
* 用法:
|
||||
* node tools/calc-exp-yield.js
|
||||
* node tools/calc-exp-yield.js --lands 18 --level 27
|
||||
* node tools/calc-exp-yield.js --input tools/seed-shop-merged-export.json
|
||||
*
|
||||
* 运行时调用:
|
||||
* const { getPlantingRecommendation } = require('../tools/calc-exp-yield');
|
||||
* const rec = getPlantingRecommendation(27, 18);
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DEFAULT_INPUT = path.join(__dirname, 'seed-shop-merged-export.json');
|
||||
const PLANT_CONFIG_PATH = path.join(__dirname, '..', 'gameConfig', 'Plant.json');
|
||||
const DEFAULT_OUT_JSON = path.join(__dirname, 'exp-yield-result.json');
|
||||
const DEFAULT_OUT_CSV = path.join(__dirname, 'exp-yield-result.csv');
|
||||
const DEFAULT_OUT_TXT = path.join(__dirname, 'exp-yield-summary.txt');
|
||||
|
||||
const NO_FERT_PLANTS_PER_2_SEC = 18;
|
||||
const NORMAL_FERT_PLANTS_PER_2_SEC = 12;
|
||||
const NO_FERT_PLANT_SPEED_PER_SEC = NO_FERT_PLANTS_PER_2_SEC / 2; // 9 块/秒
|
||||
const NORMAL_FERT_PLANT_SPEED_PER_SEC = NORMAL_FERT_PLANTS_PER_2_SEC / 2; // 6 块/秒
|
||||
|
||||
function toNum(v, fallback = 0) {
|
||||
const n = Number(v);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const opts = {
|
||||
input: DEFAULT_INPUT,
|
||||
outJson: DEFAULT_OUT_JSON,
|
||||
outCsv: DEFAULT_OUT_CSV,
|
||||
outTxt: DEFAULT_OUT_TXT,
|
||||
lands: 18,
|
||||
level: null,
|
||||
top: 20,
|
||||
};
|
||||
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const a = argv[i];
|
||||
if (a === '--input' && argv[i + 1]) opts.input = argv[++i];
|
||||
else if (a === '--out-json' && argv[i + 1]) opts.outJson = argv[++i];
|
||||
else if (a === '--out-csv' && argv[i + 1]) opts.outCsv = argv[++i];
|
||||
else if (a === '--out-txt' && argv[i + 1]) opts.outTxt = argv[++i];
|
||||
else if (a === '--lands' && argv[i + 1]) opts.lands = Math.max(1, Math.floor(toNum(argv[++i], 18)));
|
||||
else if (a === '--level' && argv[i + 1]) opts.level = Math.max(1, Math.floor(toNum(argv[++i], 1)));
|
||||
else if (a === '--top' && argv[i + 1]) opts.top = Math.max(1, Math.floor(toNum(argv[++i], 20)));
|
||||
else if (a === '--help' || a === '-h') {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
console.log('Usage: node tools/calc-exp-yield.js [options]');
|
||||
console.log('');
|
||||
console.log('Options:');
|
||||
console.log(' --input <path> 输入 JSON 文件路径');
|
||||
console.log(' --lands <n> 地块数(默认 18)');
|
||||
console.log(' --level <n> 指定账号等级,输出该等级可用最优作物');
|
||||
console.log(' --top <n> 摘要 Top 数量(默认 20)');
|
||||
console.log(' --out-json <path> 输出 JSON 路径');
|
||||
console.log(' --out-csv <path> 输出 CSV 路径');
|
||||
console.log(' --out-txt <path> 输出 TXT 路径');
|
||||
}
|
||||
|
||||
function readSeeds(inputPath) {
|
||||
const text = fs.readFileSync(inputPath, 'utf8');
|
||||
const data = JSON.parse(text);
|
||||
if (Array.isArray(data)) return data;
|
||||
if (data && Array.isArray(data.rows)) return data.rows;
|
||||
if (data && Array.isArray(data.seeds)) return data.seeds;
|
||||
throw new Error('无法识别输入数据格式,需要数组或 rows/seeds 字段');
|
||||
}
|
||||
|
||||
function parseGrowPhases(growPhases) {
|
||||
if (!growPhases || typeof growPhases !== 'string') return [];
|
||||
return growPhases
|
||||
.split(';')
|
||||
.map(x => x.trim())
|
||||
.filter(Boolean)
|
||||
.map(seg => {
|
||||
const parts = seg.split(':');
|
||||
return parts.length >= 2 ? toNum(parts[1], 0) : 0;
|
||||
})
|
||||
.filter(sec => sec > 0);
|
||||
}
|
||||
|
||||
function loadSeedPhaseReduceMap() {
|
||||
const text = fs.readFileSync(PLANT_CONFIG_PATH, 'utf8');
|
||||
const rows = JSON.parse(text);
|
||||
if (!Array.isArray(rows)) {
|
||||
throw new Error(`Plant 配置格式异常: ${PLANT_CONFIG_PATH}`);
|
||||
}
|
||||
|
||||
const map = new Map();
|
||||
for (const p of rows) {
|
||||
const seedId = toNum(p.seed_id, 0);
|
||||
if (seedId <= 0 || map.has(seedId)) continue;
|
||||
const phases = parseGrowPhases(p.grow_phases);
|
||||
if (phases.length === 0) continue;
|
||||
map.set(seedId, phases[0]); // 普通肥减少一个阶段:以首个阶段时长为准
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
function calcEffectiveGrowTime(growSec, seedId, seedPhaseReduceMap) {
|
||||
const reduce = toNum(seedPhaseReduceMap.get(seedId), 0);
|
||||
if (reduce <= 0) return growSec;
|
||||
return Math.max(1, growSec - reduce);
|
||||
}
|
||||
|
||||
function formatSec(sec) {
|
||||
const s = Math.max(0, Math.round(sec));
|
||||
if (s < 60) return `${s}s`;
|
||||
const m = Math.floor(s / 60);
|
||||
const r = s % 60;
|
||||
if (m < 60) return r > 0 ? `${m}m${r}s` : `${m}m`;
|
||||
const h = Math.floor(m / 60);
|
||||
const mm = m % 60;
|
||||
return r > 0 ? `${h}h${mm}m${r}s` : `${h}h${mm}m`;
|
||||
}
|
||||
|
||||
function csvCell(v) {
|
||||
const s = v == null ? '' : String(v);
|
||||
if (s.includes(',') || s.includes('"') || s.includes('\n')) {
|
||||
return `"${s.replace(/"/g, '""')}"`;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function buildRows(rawSeeds, lands, seedPhaseReduceMap) {
|
||||
const plantSecondsNoFert = lands / NO_FERT_PLANT_SPEED_PER_SEC;
|
||||
const plantSecondsNormalFert = lands / NORMAL_FERT_PLANT_SPEED_PER_SEC;
|
||||
const rows = [];
|
||||
let skipped = 0;
|
||||
let missingPhaseReduceCount = 0;
|
||||
|
||||
for (const s of rawSeeds) {
|
||||
const seedId = toNum(s.seedId || s.seed_id);
|
||||
const name = s.name || `seed_${seedId}`;
|
||||
const requiredLevel = toNum(s.requiredLevel || s.required_level || 1, 1);
|
||||
const price = toNum(s.price, 0);
|
||||
const expHarvest = toNum(s.exp, 0);
|
||||
const growTimeSec = toNum(s.growTimeSec || s.growTime || s.grow_time || 0, 0);
|
||||
|
||||
if (seedId <= 0 || growTimeSec <= 0) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const expPerCycle = expHarvest;
|
||||
const reduceSec = toNum(seedPhaseReduceMap.get(seedId), 0);
|
||||
if (reduceSec <= 0) missingPhaseReduceCount++;
|
||||
const growTimeNormalFert = calcEffectiveGrowTime(growTimeSec, seedId, seedPhaseReduceMap);
|
||||
|
||||
// 整个农场一轮 = 生长时间 + 本轮全部地块种植耗时
|
||||
const cycleSecNoFert = growTimeSec + plantSecondsNoFert;
|
||||
const cycleSecNormalFert = growTimeNormalFert + plantSecondsNormalFert;
|
||||
|
||||
const farmExpPerHourNoFert = (lands * expPerCycle / cycleSecNoFert) * 3600;
|
||||
const farmExpPerHourNormalFert = (lands * expPerCycle / cycleSecNormalFert) * 3600;
|
||||
const gainPercent = farmExpPerHourNoFert > 0
|
||||
? ((farmExpPerHourNormalFert - farmExpPerHourNoFert) / farmExpPerHourNoFert) * 100
|
||||
: 0;
|
||||
const expPerGoldSeed = price > 0 ? expPerCycle / price : 0;
|
||||
|
||||
rows.push({
|
||||
seedId,
|
||||
goodsId: toNum(s.goodsId || s.goods_id),
|
||||
plantId: toNum(s.plantId || s.plant_id),
|
||||
name,
|
||||
requiredLevel,
|
||||
unlocked: !!s.unlocked,
|
||||
price,
|
||||
expHarvest,
|
||||
expPerCycle,
|
||||
growTimeSec,
|
||||
growTimeStr: s.growTimeStr || formatSec(growTimeSec),
|
||||
normalFertReduceSec: reduceSec,
|
||||
growTimeNormalFert,
|
||||
growTimeNormalFertStr: formatSec(growTimeNormalFert),
|
||||
cycleSecNoFert,
|
||||
cycleSecNormalFert,
|
||||
farmExpPerHourNoFert,
|
||||
farmExpPerHourNormalFert,
|
||||
farmExpPerDayNoFert: farmExpPerHourNoFert * 24,
|
||||
farmExpPerDayNormalFert: farmExpPerHourNormalFert * 24,
|
||||
gainPercent,
|
||||
expPerGoldSeed,
|
||||
fruitId: toNum(s?.fruit?.id || s.fruitId),
|
||||
fruitCount: toNum(s?.fruit?.count || s.fruitCount),
|
||||
});
|
||||
}
|
||||
|
||||
return { rows, skipped, plantSecondsNoFert, plantSecondsNormalFert, missingPhaseReduceCount };
|
||||
}
|
||||
|
||||
function pickTop(rows, key, topN) {
|
||||
return [...rows]
|
||||
.sort((a, b) => b[key] - a[key])
|
||||
.slice(0, topN);
|
||||
}
|
||||
|
||||
function buildBestByLevel(rows) {
|
||||
const maxLevel = rows.reduce((m, r) => Math.max(m, r.requiredLevel), 1);
|
||||
const result = [];
|
||||
for (let lv = 1; lv <= maxLevel; lv++) {
|
||||
// 按用户指定等级做理论可种分析,不受商店 unlocked 状态影响
|
||||
const available = rows.filter(r => r.requiredLevel <= lv);
|
||||
if (available.length === 0) continue;
|
||||
const bestNo = pickTop(available, 'farmExpPerHourNoFert', 1)[0];
|
||||
const bestFert = pickTop(available, 'farmExpPerHourNormalFert', 1)[0];
|
||||
result.push({
|
||||
level: lv,
|
||||
bestNoFert: {
|
||||
seedId: bestNo.seedId,
|
||||
name: bestNo.name,
|
||||
expPerHour: Number(bestNo.farmExpPerHourNoFert.toFixed(2)),
|
||||
},
|
||||
bestNormalFert: {
|
||||
seedId: bestFert.seedId,
|
||||
name: bestFert.name,
|
||||
expPerHour: Number(bestFert.farmExpPerHourNormalFert.toFixed(2)),
|
||||
},
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function writeJson(outPath, payload) {
|
||||
fs.writeFileSync(outPath, JSON.stringify(payload, null, 2), 'utf8');
|
||||
}
|
||||
|
||||
function writeCsv(outPath, rows) {
|
||||
const headers = [
|
||||
'seedId',
|
||||
'name',
|
||||
'requiredLevel',
|
||||
'price',
|
||||
'expHarvest',
|
||||
'expPerCycle',
|
||||
'growTimeSec',
|
||||
'growTimeNormalFert',
|
||||
'cycleSecNoFert',
|
||||
'cycleSecNormalFert',
|
||||
'farmExpPerHourNoFert',
|
||||
'farmExpPerHourNormalFert',
|
||||
'farmExpPerDayNoFert',
|
||||
'farmExpPerDayNormalFert',
|
||||
'gainPercent',
|
||||
'expPerGoldSeed',
|
||||
];
|
||||
const lines = [headers.join(',')];
|
||||
for (const r of rows) {
|
||||
lines.push(headers.map(h => csvCell(r[h])).join(','));
|
||||
}
|
||||
fs.writeFileSync(outPath, `${lines.join('\n')}\n`, 'utf8');
|
||||
}
|
||||
|
||||
function writeSummaryTxt(outPath, opts, meta, topNo, topFert, levelInfo) {
|
||||
const lines = [];
|
||||
lines.push('经验收益率分析结果');
|
||||
lines.push('');
|
||||
lines.push(`数据源: ${meta.input}`);
|
||||
lines.push(`导出时间: ${new Date().toISOString()}`);
|
||||
lines.push(`地块数: ${opts.lands}`);
|
||||
lines.push(`种植速度(不施肥): ${NO_FERT_PLANTS_PER_2_SEC}块/${2}s (${NO_FERT_PLANT_SPEED_PER_SEC}块/s)`);
|
||||
lines.push(`种植速度(普通肥): ${NORMAL_FERT_PLANTS_PER_2_SEC}块/${2}s (${NORMAL_FERT_PLANT_SPEED_PER_SEC}块/s)`);
|
||||
lines.push(`整场种植耗时(不施肥): ${formatSec(meta.plantSecondsNoFert)}`);
|
||||
lines.push(`整场种植耗时(普通肥): ${formatSec(meta.plantSecondsNormalFert)}`);
|
||||
lines.push(`普通肥规则: 直接减少一个生长阶段(按 Plant.json 的首个阶段时长)`);
|
||||
lines.push(`缺少阶段配置的种子数: ${meta.missingPhaseReduceCount}`);
|
||||
lines.push('');
|
||||
|
||||
lines.push(`Top ${topNo.length}(不施肥,按每小时经验)`);
|
||||
lines.push('排名 | 名称 | Lv需 | 生长 | 单轮经验 | 每小时经验');
|
||||
topNo.forEach((r, i) => {
|
||||
lines.push(
|
||||
`${String(i + 1).padStart(2)} | ${r.name} | ${r.requiredLevel} | ${r.growTimeStr} | ${r.expPerCycle} | ${r.farmExpPerHourNoFert.toFixed(2)}`
|
||||
);
|
||||
});
|
||||
lines.push('');
|
||||
|
||||
lines.push(`Top ${topFert.length}(普通肥,按每小时经验)`);
|
||||
lines.push('排名 | 名称 | Lv需 | 肥后生长 | 单轮经验 | 每小时经验 | 提升');
|
||||
topFert.forEach((r, i) => {
|
||||
lines.push(
|
||||
`${String(i + 1).padStart(2)} | ${r.name} | ${r.requiredLevel} | ${r.growTimeNormalFertStr} | ${r.expPerCycle} | ${r.farmExpPerHourNormalFert.toFixed(2)} | ${r.gainPercent.toFixed(2)}%`
|
||||
);
|
||||
});
|
||||
lines.push('');
|
||||
|
||||
if (levelInfo) {
|
||||
lines.push(`当前等级 Lv${levelInfo.level} 推荐`);
|
||||
lines.push(`不施肥: ${levelInfo.bestNoFert.name}(seed=${levelInfo.bestNoFert.seedId}) -> ${levelInfo.bestNoFert.expPerHour.toFixed(2)} exp/h`);
|
||||
lines.push(`普通肥: ${levelInfo.bestNormalFert.name}(seed=${levelInfo.bestNormalFert.seedId}) -> ${levelInfo.bestNormalFert.expPerHour.toFixed(2)} exp/h`);
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
fs.writeFileSync(outPath, `${lines.join('\n')}\n`, 'utf8');
|
||||
}
|
||||
|
||||
function analyzeExpYield(opts = {}) {
|
||||
const lands = Math.max(1, Math.floor(toNum(opts.lands, 18)));
|
||||
const level = opts.level == null ? null : Math.max(1, Math.floor(toNum(opts.level, 1)));
|
||||
const top = Math.max(1, Math.floor(toNum(opts.top, 20)));
|
||||
const input = opts.input || DEFAULT_INPUT;
|
||||
const inputAbs = path.resolve(input);
|
||||
const rawSeeds = readSeeds(inputAbs);
|
||||
const seedPhaseReduceMap = loadSeedPhaseReduceMap();
|
||||
const { rows, skipped, plantSecondsNoFert, plantSecondsNormalFert, missingPhaseReduceCount } = buildRows(rawSeeds, lands, seedPhaseReduceMap);
|
||||
|
||||
if (rows.length === 0) {
|
||||
throw new Error('没有可计算的种子数据(请检查输入文件)');
|
||||
}
|
||||
|
||||
const topNo = pickTop(rows, 'farmExpPerHourNoFert', top);
|
||||
const topFert = pickTop(rows, 'farmExpPerHourNormalFert', top);
|
||||
const bestByLevel = buildBestByLevel(rows);
|
||||
|
||||
let currentLevel = null;
|
||||
if (level != null) {
|
||||
currentLevel = bestByLevel.find(x => x.level === level) || null;
|
||||
}
|
||||
|
||||
return {
|
||||
generatedAt: new Date().toISOString(),
|
||||
input: inputAbs,
|
||||
config: {
|
||||
lands,
|
||||
plantSpeedPerSecNoFert: NO_FERT_PLANT_SPEED_PER_SEC,
|
||||
plantSpeedPerSecNormalFert: NORMAL_FERT_PLANT_SPEED_PER_SEC,
|
||||
plantSecondsNoFert,
|
||||
plantSecondsNormalFert,
|
||||
fertilizer: {
|
||||
mode: 'minus_one_phase',
|
||||
},
|
||||
rule: {
|
||||
expPerCycle: 'expHarvest',
|
||||
},
|
||||
},
|
||||
stats: {
|
||||
rawCount: rawSeeds.length,
|
||||
calculatedCount: rows.length,
|
||||
skippedCount: skipped,
|
||||
missingPhaseReduceCount,
|
||||
},
|
||||
topNoFert: topNo.map(r => ({
|
||||
seedId: r.seedId,
|
||||
name: r.name,
|
||||
requiredLevel: r.requiredLevel,
|
||||
expPerHour: Number(r.farmExpPerHourNoFert.toFixed(4)),
|
||||
})),
|
||||
topNormalFert: topFert.map(r => ({
|
||||
seedId: r.seedId,
|
||||
name: r.name,
|
||||
requiredLevel: r.requiredLevel,
|
||||
expPerHour: Number(r.farmExpPerHourNormalFert.toFixed(4)),
|
||||
gainPercent: Number(r.gainPercent.toFixed(4)),
|
||||
})),
|
||||
bestByLevel,
|
||||
currentLevel,
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
function getPlantingRecommendation(level, lands, opts = {}) {
|
||||
const safeLevel = Math.max(1, Math.floor(toNum(level, 1)));
|
||||
const payload = analyzeExpYield({
|
||||
input: opts.input || DEFAULT_INPUT,
|
||||
lands: lands == null ? 18 : lands,
|
||||
top: opts.top || 20,
|
||||
level: safeLevel,
|
||||
});
|
||||
|
||||
const availableRows = payload.rows.filter(r => r.requiredLevel <= safeLevel);
|
||||
const bestNoFertRow = pickTop(availableRows, 'farmExpPerHourNoFert', 1)[0] || null;
|
||||
const bestNormalFertRow = pickTop(availableRows, 'farmExpPerHourNormalFert', 1)[0] || null;
|
||||
|
||||
return {
|
||||
level: safeLevel,
|
||||
lands: payload.config.lands,
|
||||
input: payload.input,
|
||||
bestNoFert: bestNoFertRow ? {
|
||||
seedId: bestNoFertRow.seedId,
|
||||
name: bestNoFertRow.name,
|
||||
requiredLevel: bestNoFertRow.requiredLevel,
|
||||
expPerHour: Number(bestNoFertRow.farmExpPerHourNoFert.toFixed(4)),
|
||||
} : null,
|
||||
bestNormalFert: bestNormalFertRow ? {
|
||||
seedId: bestNormalFertRow.seedId,
|
||||
name: bestNormalFertRow.name,
|
||||
requiredLevel: bestNormalFertRow.requiredLevel,
|
||||
expPerHour: Number(bestNormalFertRow.farmExpPerHourNormalFert.toFixed(4)),
|
||||
} : null,
|
||||
candidatesNoFert: pickTop(availableRows, 'farmExpPerHourNoFert', opts.top || 20).map(r => ({
|
||||
seedId: r.seedId,
|
||||
name: r.name,
|
||||
requiredLevel: r.requiredLevel,
|
||||
expPerHour: Number(r.farmExpPerHourNoFert.toFixed(4)),
|
||||
})),
|
||||
candidatesNormalFert: pickTop(availableRows, 'farmExpPerHourNormalFert', opts.top || 20).map(r => ({
|
||||
seedId: r.seedId,
|
||||
name: r.name,
|
||||
requiredLevel: r.requiredLevel,
|
||||
expPerHour: Number(r.farmExpPerHourNormalFert.toFixed(4)),
|
||||
gainPercent: Number(r.gainPercent.toFixed(4)),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function main() {
|
||||
const opts = parseArgs(process.argv.slice(2));
|
||||
const payload = analyzeExpYield(opts);
|
||||
const rows = payload.rows;
|
||||
const topNo = pickTop(rows, 'farmExpPerHourNoFert', opts.top);
|
||||
const topFert = pickTop(rows, 'farmExpPerHourNormalFert', opts.top);
|
||||
const currentLevel = payload.currentLevel;
|
||||
|
||||
writeJson(path.resolve(opts.outJson), payload);
|
||||
writeCsv(path.resolve(opts.outCsv), rows);
|
||||
writeSummaryTxt(
|
||||
path.resolve(opts.outTxt),
|
||||
opts,
|
||||
{
|
||||
input: payload.input,
|
||||
plantSecondsNoFert: payload.config.plantSecondsNoFert,
|
||||
plantSecondsNormalFert: payload.config.plantSecondsNormalFert,
|
||||
missingPhaseReduceCount: payload.stats.missingPhaseReduceCount,
|
||||
},
|
||||
topNo,
|
||||
topFert,
|
||||
currentLevel
|
||||
);
|
||||
|
||||
console.log(`[收益率] 计算完成,共 ${rows.length} 条(跳过 ${payload.stats.skippedCount} 条)`);
|
||||
console.log(`[收益率] JSON: ${path.resolve(opts.outJson)}`);
|
||||
console.log(`[收益率] CSV : ${path.resolve(opts.outCsv)}`);
|
||||
console.log(`[收益率] TXT : ${path.resolve(opts.outTxt)}`);
|
||||
if (currentLevel) {
|
||||
console.log(`[收益率] Lv${opts.level} 最优(不施肥): ${currentLevel.bestNoFert.name} ${currentLevel.bestNoFert.expPerHour} exp/h`);
|
||||
console.log(`[收益率] Lv${opts.level} 最优(普通肥): ${currentLevel.bestNormalFert.name} ${currentLevel.bestNormalFert.expPerHour} exp/h`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
analyzeExpYield,
|
||||
getPlantingRecommendation,
|
||||
DEFAULT_INPUT,
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
try {
|
||||
main();
|
||||
} catch (e) {
|
||||
console.error(`[收益率] 失败: ${e.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
127
server/tools/crop_list.md
Normal file
127
server/tools/crop_list.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# 农作物列表 (共 123 种)
|
||||
|
||||
| ID | 名称 | 等级 | 季数 | 产量 | 生长(小时) | 阶段详情 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1020001 | 草莓 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020002 | 白萝卜 | 1 | 1 | 5 | 0.0h | 种子:30;发芽:30;成熟:0; |
|
||||
| 1020003 | 胡萝卜 | 1 | 1 | 10 | 0.0h | 种子:30;发芽:30;小叶子:30;大叶子:30;成熟:0; |
|
||||
| 1020004 | 玉米 | 1 | 1 | 40 | 1.3h | 种子:960;发芽:960;小叶子:960;大叶子:960;开花:960;成熟:0; |
|
||||
| 1020005 | 土豆 | 1 | 1 | 60 | 2.0h | 种子:1440;发芽:1440;小叶子:1440;大叶子:1440;初熟:1440;成熟:0; |
|
||||
| 1020006 | 茄子 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020007 | 番茄 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020008 | 豌豆 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;初熟:5760;成熟:0; |
|
||||
| 1020009 | 辣椒 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;初熟:5760;成熟:0; |
|
||||
| 1020010 | 南瓜 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;初熟:5760;成熟:0; |
|
||||
| 1020011 | 苹果 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;开花:8640;成熟:0; |
|
||||
| 1020013 | 葡萄 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020014 | 西瓜 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020015 | 香蕉 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;开花:17280;成熟:0; |
|
||||
| 1020016 | 菠萝蜜 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020018 | 桃子 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;开花:5760;小叶子:5760;大叶子:5760;成熟:0; |
|
||||
| 1020019 | 橙子 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;开花:17280;成熟:0; |
|
||||
| 1020022 | 鳄梨 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020023 | 石榴 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;开花:5760;成熟:0; |
|
||||
| 1020026 | 柚子 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;开花:17280;成熟:0; |
|
||||
| 1020027 | 菠萝 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;开花:7200;成熟:0; |
|
||||
| 1020029 | 椰子 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020031 | 葫芦 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
| 1020033 | 火龙果 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
| 1020034 | 樱桃 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;开花:7200;成熟:0; |
|
||||
| 1020035 | 荔枝 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020036 | 箬竹 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;初熟:10800;成熟:0; |
|
||||
| 1020037 | 莲藕 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;开花:8640;成熟:0; |
|
||||
| 1020038 | 木瓜 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;开花:7200;成熟:0; |
|
||||
| 1020039 | 杨桃 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;成熟:0; |
|
||||
| 1020041 | 红玫瑰 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;初熟:17280;成熟:0; |
|
||||
| 1020042 | 柠檬 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
| 1020043 | 无花果 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020044 | 丝瓜 | 1 | 1 | 200 | 12.0h | 种子:8640;长枝:8640;开花:8640;小叶子:8640;大叶子:8640;结果:0; |
|
||||
| 1020045 | 猕猴桃 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;成熟:0; |
|
||||
| 1020047 | 甘蔗 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;幼苗:8640;分叶:8640;伸长:8640;成熟:0; |
|
||||
| 1020048 | 杨梅 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;开花:7200;成熟:0; |
|
||||
| 1020049 | 花生 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;初熟:7200;成熟:0; |
|
||||
| 1020050 | 蘑菇 | 1 | 2 | 200 | 4.0h | 种子:3600;发芽:3600;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020051 | 红枣 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;开花:8640;成熟:0; |
|
||||
| 1020052 | 金针菇 | 1 | 2 | 200 | 12.0h | 种子:7200;发菌:7200;出菇:7200;幼菇:10800;初熟:10800;成熟:0; |
|
||||
| 1020053 | 桂圆 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020054 | 梨 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;初熟:7200;成熟:0; |
|
||||
| 1020055 | 枇杷 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020056 | 哈密瓜 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;开花:7200;成熟:0; |
|
||||
| 1020057 | 芒果 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020058 | 榴莲 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020059 | 大白菜 | 1 | 1 | 20 | 0.1h | 种子:60;发芽:60;幼苗:60;成株:60;卷心:60;成熟:0; |
|
||||
| 1020060 | 水稻 | 1 | 1 | 30 | 0.7h | 种子:480;幼苗:480;秧苗:480;幼穗:480;开花:480;成熟:0; |
|
||||
| 1020061 | 小麦 | 1 | 1 | 40 | 1.0h | 种子:720;发芽:720;小叶子:720;大叶子:720;幼穗:720;成熟:0; |
|
||||
| 1020062 | 四叶草 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;初熟:17280;成熟:0; |
|
||||
| 1020063 | 苦瓜 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020064 | 大葱 | 1 | 1 | 30 | 0.3h | 种子:300;发芽:300;小叶子:300;大叶子:300;成熟:0; |
|
||||
| 1020065 | 大蒜 | 1 | 1 | 20 | 0.2h | 种子:120;发芽:120;幼苗:120;伸长:120;初熟:120;成熟:0; |
|
||||
| 1020066 | 鲜姜 | 1 | 1 | 60 | 1.7h | 种子:1500;发芽:1500;小叶子:1500;大叶子:1500;成熟:0; |
|
||||
| 1020067 | 香瓜 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;成熟:0; |
|
||||
| 1020068 | 冬瓜 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;成熟:0; |
|
||||
| 1020070 | 黄豆 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;初熟:8640;成熟:0; |
|
||||
| 1020071 | 小白菜 | 1 | 1 | 80 | 2.5h | 种子:2250;发芽:2250;小叶子:2250;大叶子:2250;成熟:0; |
|
||||
| 1020072 | 榛子 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;开花:17280;小叶子:17280;大叶子:17280;成熟:0; |
|
||||
| 1020073 | 菠菜 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;初熟:2880;成熟:0; |
|
||||
| 1020074 | 金桔 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
| 1020075 | 桑葚 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020076 | 山竹 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020077 | 蓝莓 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;初熟:7200;成熟:0; |
|
||||
| 1020078 | 杏子 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;初熟:10800;成熟:0; |
|
||||
| 1020079 | 番石榴 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020080 | 月柿 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020083 | 红毛丹 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;初熟:3600;成熟:0; |
|
||||
| 1020084 | 芭蕉 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;结果:0; |
|
||||
| 1020085 | 番荔枝 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;结果:0; |
|
||||
| 1020086 | 橄榄 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020087 | 百香果 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;结果:0; |
|
||||
| 1020088 | 灯笼果 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;结果:0; |
|
||||
| 1020089 | 芦荟 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;开花:3600;成熟:0; |
|
||||
| 1020090 | 薄荷 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020091 | 山楂 | 1 | 1 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:14400;开花:14400;初熟:14400;成熟:0; |
|
||||
| 1020095 | 栗子 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;开花:8640;成熟:0; |
|
||||
| 1020096 | 生菜 | 1 | 1 | 80 | 3.0h | 种子:2160;发芽:2160;小叶子:2160;大叶子:2160;初熟:2160;成熟:0; |
|
||||
| 1020097 | 黄瓜 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;开花:8640;成熟:0; |
|
||||
| 1020098 | 花菜 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;幼苗:8640;卷心:8640;初熟:8640;成熟:0; |
|
||||
| 1020099 | 油菜 | 1 | 1 | 200 | 4.0h | 种子:3600;发芽:3600;小叶子:3600;大叶子:3600;成熟:0; |
|
||||
| 1020100 | 竹笋 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;幼苗:2880;伸长:2880;初熟:2880;成熟:0; |
|
||||
| 1020103 | 天香百合 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;初熟:2880;成熟:0; |
|
||||
| 1020104 | 非洲菊 | 1 | 1 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:2400;花蕾:2400;盛开:2400;成熟:0; |
|
||||
| 1020105 | 小雏菊 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;初熟:2880;成熟:0; |
|
||||
| 1020110 | 满天星 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;花蕾:5760;盛开:0; |
|
||||
| 1020116 | 曼陀罗华 | 1 | 2 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:3600;花蕾:3600;盛开:0; |
|
||||
| 1020120 | 蒲公英 | 1 | 1 | 200 | 24.0h | 种子:17280;小叶子:17280;大叶子:17280;花蕾:17280;盛开:17280;成熟:0; |
|
||||
| 1020126 | 曼珠沙华 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;初熟:7200;成熟:0; |
|
||||
| 1020128 | 茉莉花 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;花蕾:2880;盛开:0; |
|
||||
| 1020135 | 火绒草 | 1 | 1 | 200 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;花蕾:5760;盛开:0; |
|
||||
| 1020141 | 花香根鸢尾 | 1 | 1 | 200 | 12.0h | 种子:8640;发芽:8640;小叶子:8640;大叶子:8640;花蕾:8640;盛开:0; |
|
||||
| 1020142 | 虞美人 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;花蕾:17280;盛开:0; |
|
||||
| 1020143 | 含羞草 | 1 | 1 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:7200;花蕾:7200;盛开:7200;成熟:0; |
|
||||
| 1020145 | 向日葵 | 1 | 1 | 200 | 4.0h | 种子:2400;发芽:2400;小叶子:2400;大叶子:2400;开花:2400;初熟:2400;成熟:0; |
|
||||
| 1020147 | 牵牛花 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;花蕾:17280;盛开:0; |
|
||||
| 1020161 | 秋菊(黄色) | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;花蕾:2880;盛开:0; |
|
||||
| 1020162 | 秋菊(红色) | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶子:2880;大叶子:2880;花蕾:2880;盛开:0; |
|
||||
| 1020201 | 天山雪莲 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;幼株:21600;成熟:0; |
|
||||
| 1020202 | 金边灵芝 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;芝蕾:4800;幼芝:7200;初熟:7200;成熟:0; |
|
||||
| 1020204 | 人参 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;初熟:7200;成熟:0; |
|
||||
| 1020218 | 瓶子树 | 1 | 2 | 200 | 4.0h | 种子:2400;长枝:2400;小叶子:2400;大叶子:3600;初熟:3600;成树:0; |
|
||||
| 1020220 | 猪笼草 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;初熟:10800;成熟:0; |
|
||||
| 1020221 | 天堂鸟 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;花蕾:21600;盛开:0; |
|
||||
| 1020222 | 豹皮花 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;花蕾:7200;盛开:0; |
|
||||
| 1020225 | 宝华玉兰 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;花蕾:7200;盛开:0; |
|
||||
| 1020226 | 依米花 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;花蕾:21600;盛开:0; |
|
||||
| 1020227 | 大王花 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;幼蕾:4800;含苞:7200;初放:7200;盛开:0; |
|
||||
| 1020228 | 人参果 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;开花:21600;成熟:0; |
|
||||
| 1020229 | 何首乌 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
| 1020235 | 金花茶 | 1 | 2 | 200 | 8.0h | 种子:4800;发芽:4800;小叶子:4800;大叶子:7200;花蕾:7200;盛开:0; |
|
||||
| 1020242 | 似血杜鹃 | 1 | 2 | 200 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;花蕾:21600;盛开:0; |
|
||||
| 1020259 | 银莲花 | 1 | 1 | 200 | 4.0h | 种子:2880;发芽:2880;小叶:2880;大叶:2880;花蕾:2880;开花:0; |
|
||||
| 1020305 | 韭菜 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;初熟:17280;成熟:0; |
|
||||
| 1020306 | 芹菜 | 1 | 1 | 200 | 24.0h | 种子:17280;发芽:17280;小叶子:17280;大叶子:17280;初熟:17280;成熟:0; |
|
||||
| 1020308 | 核桃 | 1 | 1 | 200 | 12.0h | 种子:10800;发芽:10800;小叶子:10800;大叶子:10800;成熟:0; |
|
||||
| 1020396 | 迎春花 | 1 | 1 | 200 | 4.0h | 种子:2880;幼芽:2880;小叶:2880;大叶:2880;花蕾:2880;开花:0; |
|
||||
| 1020413 | 李子 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;开花:10800;成熟:0; |
|
||||
| 1020442 | 睡莲 | 1 | 2 | 200 | 12.0h | 种子:7200;发芽:7200;小叶子:7200;大叶子:10800;幼株:10800;成熟:0; |
|
||||
| 1021542 | 新春红包 | 1 | 1 | 20 | 8.0h | 种子:5760;发芽:5760;小叶子:5760;大叶子:5760;初熟:5760;成熟:0; |
|
||||
| 2020002 | 白萝卜 | 1 | 1 | 5 | 0.0h | 种子:1;发芽:1;成熟:0; |
|
||||
| 2029998 | 哈哈南瓜 | 1 | 1 | 50 | 24.0h | 种子:14400;发芽:14400;小叶子:14400;大叶子:21600;初熟:21600;成熟:0; |
|
||||
37
server/tools/list_crops.js
Normal file
37
server/tools/list_crops.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const plantPath = path.join(__dirname, '../gameConfig/Plant.json');
|
||||
|
||||
try {
|
||||
const data = fs.readFileSync(plantPath, 'utf8');
|
||||
const plants = JSON.parse(data);
|
||||
|
||||
let content = `# 农作物列表 (共 ${plants.length} 种)\n\n`;
|
||||
content += `| ID | 名称 | 等级 | 季数 | 产量 | 生长(小时) | 阶段详情 |\n`;
|
||||
content += `|---|---|---|---|---|---|---|\n`;
|
||||
|
||||
plants.sort((a, b) => a.land_level_need - b.land_level_need || a.id - b.id);
|
||||
|
||||
plants.forEach(p => {
|
||||
let totalTime = 0;
|
||||
if (p.grow_phases) {
|
||||
const parts = p.grow_phases.split(';');
|
||||
parts.forEach(part => {
|
||||
if (part) {
|
||||
const [stage, time] = part.split(':');
|
||||
if (time) totalTime += parseInt(time);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const hours = (totalTime / 3600).toFixed(1);
|
||||
content += `| ${p.id} | ${p.name} | ${p.land_level_need} | ${p.seasons} | ${p.fruit ? p.fruit.count : '?'} | ${hours}h | ${p.grow_phases} |\n`;
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, 'crop_list.md'), content);
|
||||
console.log('列表已生成: server/tools/crop_list.md');
|
||||
|
||||
} catch (err) {
|
||||
console.error('读取失败:', err);
|
||||
}
|
||||
2007
server/tools/seed-shop-merged-export.json
Normal file
2007
server/tools/seed-shop-merged-export.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user