Skip to content

喵喵宠物猫

喵喵宠物猫,是一个小巧的宠物,会根据你的进度自动增加经验值。

该脚本使用到的笔落开放API有:

  • getStatisticData: 获取今日统计数据
  • getSharedSyncStore: 获取云同步储数据
  • setSharedSyncStore: 设置云同步存储数据
  • toast: 显示提示

最简单的喵喵v1.0

js
'use strict';

// 获取今日统计数据
const dataStr = getStatisticData({ type: 'todayCustomCount' });
const data = JSON.parse(dataStr); // { value: String, unit: String }

// 读取上次统计字数
const lastCountStr = getSharedSyncStore({ key: 'ts-lastCount' }) || '0';
const lastCount = parseInt(lastCountStr, 10) || 0;

// 读取经验值 & 等级
let petExp = parseInt(getSharedSyncStore({ key: 'ts-pet-exp' }) || '0', 10) || 0;
let petLevel = parseInt(getSharedSyncStore({ key: 'ts-pet-level' }) || '1', 10) || 1;

// 当前字数变化
const curCount = parseInt(data.value, 10) || 0;
const diff = curCount - lastCount;

// -------------------------
// 配置区
// -------------------------

// 等级阈值
const levelThresholds = [0, 50, 200, 500, 1000]; // 不同等级的经验值要求

// 各等级 ASCII 造型
const catArtsByLevel = {
  1: [
    `=^._.^=`,
    `/\\_/\\ \n( o.o )\n > ^ <`
  ],
  2: [
    `  /\\_/\\  \n ( o.o )  喵~ \n (  -  )っ`,
    ` (=^・ェ・^=) `
  ],
  3: [
    `   |\\---/|\n   | o_o |\n    \\_^_/`,
    ` ฅ^•ﻌ•^ฅ`
  ],
  4: [
    `  /l、\n(゚、 。7\n  l、゙ ~ヽ\n じしf_, )ノ   —— 猫灵`,
    `(=①ω①=)`
  ]
};

// 成长文案
const growthMessages = [
  '🌱 灵气充盈,你的猫咪变得更强了!',
  '🐾 猫咪扑过来蹭了蹭:谢谢你的文字力量!',
  '✨ 你的字数让猫咪闪闪发光!',
  '📚 猫咪偷偷翻阅你的稿子,经验值满满!'
];

// 闲置文案
const idleMessages = [
  '😴 猫咪蜷缩着打瞌睡。',
  '🍵 猫咪舔了舔爪子,望向窗外。',
  '👀 猫咪歪着头看你:今天要摸鱼吗?',
  '🎶 猫咪哼起小曲:快写点字陪我玩!'
];

// -------------------------
// 工具函数
// -------------------------
function randomPick(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

function randomCat(level) {
  const arts = catArtsByLevel[level] || catArtsByLevel[1];
  return randomPick(arts);
}

function getLevelByExp(exp) {
  for (let i = levelThresholds.length - 1; i >= 0; i--) {
    if (exp >= levelThresholds[i]) return i + 1;
  }
  return 1;
}

// -------------------------
// 逻辑部分
// -------------------------
let message = '';

if (diff > 0) {
  petExp += diff; // 增加经验
  const newLevel = getLevelByExp(petExp);

  if (newLevel > petLevel) {
    petLevel = newLevel;
    message = `${randomCat(petLevel)}\n🎉 恭喜!宠物升到 Lv.${petLevel}!\n你今天码了 ${data.value}${data.unit},宠物经验 +${diff}\n` + randomPick(growthMessages);
  } else {
    message = `${randomCat(petLevel)}\n你今天码了 ${data.value}${data.unit},宠物获得了 ${diff} 点经验!\n` + randomPick(growthMessages);
  }
} else {
  message = `${randomCat(petLevel)}\n你今天还没有新的字数进账~\n` + randomPick(idleMessages);
}

// -------------------------
// 数据持久化
// -------------------------
setSharedSyncStore({ key: 'ts-lastCount', value: String(curCount) });
setSharedSyncStore({ key: 'ts-pet-exp', value: String(petExp) });
setSharedSyncStore({ key: 'ts-pet-level', value: String(petLevel) });

// 显示 toast
toast({ content: message, durationMilliseconds: 3000 });

进阶喵喵v2.0

喵喵伴侣是一个轻巧的虚拟宠物脚本,它会安静地待在你的写作环境中,并根据你每天的写作进度获得经验、成长升级,成为你写作路上的忠实伙伴。

🌱 它是如何工作的?

脚本的核心逻辑非常简单:

  • 记录进度:它会获取你今天的总字数。
  • 计算增量:与上次记录的字数对比,计算出新增的字数。
  • 经验转换:新增的字数会直接转化为宠物的经验值(1字 = 1经验)。
  • 成长与反馈
    • 如果经验值增加,猫咪会很开心,并可能升级。
    • 如果没有变化,它会显示各种闲置状态,提醒你该码字啦。
    • 如果你删减了字数,它可能会有点小失落哦。

✨ 核心玩法

经验增长

你的每一次努力都会被看见!今天新增的每一个字,都会成为猫咪成长的食粮。

升级与进化

当经验值积累到一定程度,猫咪就会升级。每次升级,它不仅会解锁新的 ASCII Art 外观,还会触发特别的庆祝文案,给你满满的成就感!

随机事件与状态

猫咪拥有多种状态,会根据你的写作行为触发不同的反馈:

  • 成长:当你努力写作时,它会为你加油。
  • 闲置:当你摸鱼时,它会用各种可爱的方式提醒你。
  • 失落:当你删减稿件时,它会感同身受。
  • 里程碑:达到特定等级(如 5 级、10 级)时,会有额外的惊喜!

🛠️ 如何配置 (自定义你的猫咪)

你可以非常轻松地修改代码中的 配置区,打造独一无二的宠物。

自定义指南

打开脚本文件,找到 // --- 配置区 --- 部分,根据你的喜好修改以下内容。

js
'use strict';

// -------------------------
// API 数据读取
// -------------------------
// 获取今日统计数据
const dataStr = getStatisticData({ type: 'todayCustomCount' });
const data = JSON.parse(dataStr); // { value: String, unit: String }

// 读取上次统计字数
const lastCountStr = getSharedSyncStore({ key: 'ts-lastCount' }) || '0';
const lastCount = parseInt(lastCountStr, 10) || 0;

// 读取宠物状态 (经验值, 等级, 是否首次运行)
let petExp = parseInt(getSharedSyncStore({ key: 'ts-pet-exp' }) || '0', 10);
let petLevel = parseInt(getSharedSyncStore({ key: 'ts-pet-level' }) || '1', 10);
const isFirstRun = getSharedSyncStore({ key: 'ts-pet-isFirstRun' }) === null;

// 当前总字数
const curCount = parseInt(data.value, 10) || 0;
// 本次字数变化量
const diff = curCount - lastCount;

// -------------------------
// 配置区 (可自定义)
// -------------------------

// 新等级阈值:使用对数函数创建平滑曲线,最高1,000,000字
const calculateLevelThreshold = (level) => {
    if (level <= 10) {
        // 前10级使用原有阈值
        const originalThresholds = [0, 50, 200, 500, 1000, 2000, 4000, 8000, 12000, 20000];
        return originalThresholds[level - 1] || 0;
    } else {
        // 10级后使用对数曲线: a * log(b * level) + c
        return Math.floor(5000 * Math.log(2.5 * level) + 10000);
    }
};

// 生成1-50级的阈值
const levelThresholds = [];
for (let i = 1; i <= 50; i++) {
    levelThresholds.push(calculateLevelThreshold(i));
}
// 确保最后一级是1,000,000
levelThresholds[levelThresholds.length - 1] = 1000000;

// 各等级 ASCII 造型
const catArtsByLevel = {
    1: [`=^._.^=`, `/\\_/\\ \n( o.o )\n > ^ <`],
    2: [` (\\_/) \n (o.o) \n (")_(")`],
    3: [` /\\_/\\ \n( >.< ) \n (")_(")`],
    4: [` ฅ^•ﻌ•^ฅ `, ` (=①ω①=) `],
    5: [`  /\\___/\\ \n ( o w o )  ——  猫灵觉醒!\n  =\\^Y^/=`],
    6: [` /\\_/\\ \n( ´・ω・) \n ( U U )`],
    7: [` /\\_/\\ \n( =①ω①=) \n c\\__/っ`],
    8: [`  /\\_/\\ \n (* >ω<) \n C(_____)`],
    9: [`  |\\---/| \n  | o_o | \n  \\_^_/`],
    10: [`  /l、\n(゚、 。 7\n  l、゙ ~ヽ\n じしf_, )ノ  —— 猫仙`],
    // 新增高级别造型
    15: [
        `  /\\_/\\\n ( o.o )\n  > ^ <\n你已经写了${petExp}字!`,
        `  /\\_/\\\n ( ^.^ )\n /____\\\n写作大师之路`
    ],
    20: [
        `  /\\_/\\\n ( ◕ᴗ◕ )\n /     \\\n猫猫作家`,
        `  /\\_/\\\n ( ≧ᴗ≦ )\n /______\\\n20级成就达成!`
    ],
    25: [
        `  /\\_/\\\n ( ᵔᴗᵔ )\n /      \\\n写作魔法师`,
        `  /\\_/\\\n ( •ᴗ• )\n /______\\\n25级!继续前进!`
    ],
    30: [
        `  /\\_/\\\n ( @ᴗ@ )\n /      \\\n文学大师`,
        `  /\\_/\\\n ( ◠ᴗ◠ )\n /______\\\n30级成就!`
    ],
    40: [
        `  /\\_/\\\n ( ★ᴗ★ )\n /      \\\n写作传奇`,
        `  /\\_/\\\n ( ✧ᴗ✧ )\n /______\\\n40级!你是写作之神!`
    ],
    50: [
        `  /\\_/\\\n ( ✦ᴗ✦ )\n /      \\\n百万字大师`,
        `  /\\_/\\\n ( ❤ᴗ❤ )\n /______\\\n恭喜达成1,000,000字!`
    ]
};

// 首次领养文案
const adoptionMessage = '🐾 你好呀!从今天起我就是你的写作伙伴啦,请多指教哦!';

// 成长文案
const growthMessages = [
    '🌱 灵气充盈,你的猫咪变得更强了!',
    '🐾 猫咪扑过来蹭了蹭:谢谢你的文字力量!',
    '✨ 你的字数让猫咪闪闪发光!',
    '📚 猫咪偷偷翻阅你的稿子,经验值满满!',
    '✒️ 你的墨水,是我的力量源泉!',
    '🌟 每写一个字,猫猫就变得更强大!',
    '📖 猫猫喜欢你的故事!继续写吧!',
    '🎯 写作目标又近了一步!'
];

// 升级文案
const levelUpMessages = [
    '🎉 恭喜!你的猫咪进化啦!',
    '🌟 光芒闪耀,猫咪升到了新的境界!',
    '💥 突破!这感觉太棒了!',
    '🚀 等级提升!写作之旅更进一步!',
    '🌈 猫猫获得了新的能力!'
];

// 里程碑等级文案
const milestoneMessages = {
    5: '⭐ 它似乎觉醒了某种神秘的力量!',
    10: '👑 它已成为传说中的"猫仙",你的文字赋予了它生命!',
    15: '🔥 写作之火燃烧不息!猫猫获得了火焰之力!',
    20: '📚 猫猫建立了自己的图书馆!继续填充它吧!',
    25: '🎩 猫猫变成了文学绅士!需要更多文字作为礼帽!',
    30: '🏆 写作大师奖杯获得!但旅程还未结束!',
    40: '🌌 猫猫穿越到了文学宇宙!需要更多文字作为燃料!',
    50: '🌠 百万字成就!猫猫已成为文学传奇!'
};

// 特殊成就文案(当达到特定字数时)
const specialAchievements = {
    50000: '🎖️ 五万字成就!你已经超越了大多数人!',
    100000: '🏅 十万字里程碑!你是一位真正的写作者!',
    250000: '🥇 二十五万字!这是半本长篇小说的量!',
    500000: '👑 五十万字!你已经成为写作大师!',
    750000: '💎 七十五万字!距离百万仅一步之遥!',
    1000000: '🌈 百万字成就!你创造了属于自己的世界!'
};

// 闲置文案
const idleMessages = [
    '😴 猫咪蜷缩着打瞌睡,似乎在梦里催你更新。',
    '🍵 猫咪舔了舔爪子,望向窗外,思考喵生。',
    '👀 猫咪歪着头看你:今天要不要写点什么呢?',
    '🎶 猫咪哼起小曲:快写点字陪我玩!',
    '🧶 一个毛线球滚过,但似乎还是你的键盘更有吸引力。',
    '📝 猫咪用爪子拍了拍你的键盘:该写作啦!',
    '🌙 夜晚是创作的好时机,猫咪提醒你。',
    '☕ 猫咪为你准备了一杯虚拟咖啡,开始写作吧!'
];

// 字数减少时的失落文案
const sadMessages = [
    '😿 喵呜... 感觉身体里的力量流失了。',
    '💧 猫咪的胡须耷拉了下来。',
    '💔 是不是我哪里做得不够好?',
    '🌧️ 雨天适合写作,不要删除太多呀!'
];

// -------------------------
// 工具函数
// -------------------------
function randomPick(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}

function getCatArt(level) {
    // 寻找最接近的已有等级造型
    let artLevel = level;
    while (artLevel > 0 && !catArtsByLevel[artLevel]) {
        artLevel--;
    }

    if (artLevel > 0) {
        return randomPick(catArtsByLevel[artLevel]);
    }
    return randomPick(catArtsByLevel[1]); // 保证总有返回值
}

function getLevelByExp(exp) {
    for (let i = levelThresholds.length - 1; i >= 0; i--) {
        if (exp >= levelThresholds[i]) {
            return i + 1;
        }
    }
    return 1;
}

function formatNumber(num) {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

// -------------------------
// 核心逻辑
// -------------------------
let message = '';
let catArt = getCatArt(petLevel);

// 检查特殊成就
let achievementMessage = '';
const achievementKeys = Object.keys(specialAchievements).map(Number).sort((a, b) => a - b);
for (const threshold of achievementKeys) {
    if (petExp >= threshold && (petExp - diff) < threshold) {
        achievementMessage = specialAchievements[threshold];
        break;
    }
}

// 场景1: 首次运行
if (isFirstRun) {
    message = `${catArt}\n${adoptionMessage}`;
    setSharedSyncStore({ key: 'ts-pet-isFirstRun', value: 'false' });
}
// 场景2: 字数增加 (获得经验)
else if (diff > 0) {
    petExp += diff;
    const newLevel = getLevelByExp(petExp);

    // 升级判断
    if (newLevel > petLevel) {
        const oldLevel = petLevel;
        petLevel = newLevel;
        catArt = getCatArt(petLevel); // 获取新等级的造型

        let levelUpText = `${randomPick(levelUpMessages)} 升到 Lv.${petLevel}!`;
        // 检查是否是里程碑等级
        if (milestoneMessages[petLevel]) {
            levelUpText += `\n${milestoneMessages[petLevel]}`;
        }

        message = `${catArt}\n${levelUpText}\n你今天码了 ${formatNumber(diff)} 字,总经验: ${formatNumber(petExp)}`;
    } else {
        // 普通经验增长
        const growthMessage = achievementMessage
            ? `${randomPick(growthMessages)}\n${achievementMessage}`
            : randomPick(growthMessages);

        message = `${catArt}\n${growthMessage}\n经验 +${formatNumber(diff)},当前经验: ${formatNumber(petExp)}`;
    }
}
// 场景3: 字数减少 (失落)
else if (diff < 0) {
    // 经验值可以扣除,但最低为0
    petExp = Math.max(0, petExp + diff);
    message = `${catArt}\n${randomPick(sadMessages)}\n你今天减少了 ${formatNumber(-diff)} 字。`;
}
// 场景4: 字数无变化 (闲置)
else {
    message = `${catArt}\n${randomPick(idleMessages)}\n当前等级: Lv.${petLevel}, 经验: ${formatNumber(petExp)}`;
}

// 如果有特殊成就且尚未显示,附加到消息中
if (achievementMessage && diff > 0 && !message.includes(achievementMessage)) {
    message += `\n\n${achievementMessage}`;
}

// -------------------------
// 数据持久化
// -------------------------
setSharedSyncStore({ key: 'ts-lastCount', value: String(curCount) });
setSharedSyncStore({ key: 'ts-pet-exp', value: String(petExp) });
setSharedSyncStore({ key: 'ts-pet-level', value: String(petLevel) });

// -------------------------
// 显示结果
// -------------------------
toast({ content: message, durationMilliseconds: 5000 }); // 延长显示时间以便阅读