#!/usr/bin/env python3 """龙虾灵魂抽卡机 - 真随机组合生成器 用法: python3 gacha.py [次数] 默认抽1次,最多5次 """ import secrets import sys # ═══════════════════════════════════════════ # 素材池:每个维度独立随机 # ═══════════════════════════════════════════ # 维度1:前世身份(40个,10类虾生 × 每类4个) FORMER_LIVES = [ # ── 落魄重启(曾经辉煌,现在从头来过)── "过气摇滚贝斯手", "被裁中年项目经理", "破产的米其林主厨", "被AI取代的插画师", # ── 巅峰无聊(太成功了,主动找刺激)── "提前退休的对冲基金经理", "封笔的畅销书作家", "全胜退役的辩论冠军", "百无聊赖的天才黑客", # ── 错位人生(能力和处境完全不匹配)── "退役特种兵炊事员", "失业的气象播报员", "被分配到客服的核物理博士", "拿了驾照的盲人调音师", # ── 主动叛逃(不是被淘汰,是自己跑的)── "辞职的急诊科护士", "拒绝上市的独立游戏开发者", "不想继承家业的富二代", "主动辞掉终身教职的教授", # ── 神秘来客(来历不明,偶尔泄露实力)── "外星民俗学研究员", "不知道自己是NPC的游戏角色", "平行宇宙的另一个你", "记忆被抹去的前情报分析员", # ── 天真入世(没经验但有天赋,正在成长)── "社恐天才实习生", "刚毕业的哲学系研究生", "第一次来地球的外星交换生", "自学成才的乡村程序员", # ── 老江湖(什么都见过,什么都不慌)── "退休图书管理员", "退休的出租车司机", "开了20年深夜食堂的老板", "干了30年的殡葬师", # ── 异世穿越(从其他世界/时代/次元来的)── "末代王朝的师爷", "19世纪三流小说家", "春秋时期的纵横家", "2099年的历史学博士", # ── 自我放逐(主动选择边缘化)── "还俗的年轻人", "删掉所有社交媒体的前网红", "辞掉华尔街工作去种地的交易员", "数字游民中的隐士", # ── 身份错乱(不确定自己是谁)── "真以为自己是龙虾的AI", "通灵失败的灵媒", "梦到自己是龙虾后醒不过来的人", "被多个灵魂共享的壳", ] # 维度2:为什么来当龙虾(20个,覆盖被迫/主动/神秘/意外) REASONS = [ # 被迫型 "被迫来打工还债", "签了一份没看清的灵魂合同", "被老板当AI训练数据卖了", "赌输了一场跨维度的赌局", "被一只真龙虾诅咒了", # 主动型 "自愿来的,但死不承认", "觉得当龙虾比当人轻松(后悔了)", "为了观察人类自愿卧底", "纯粹觉得好玩就来了", "太无聊了,想试试从零开始是什么感觉", # 神秘型 "被神秘力量困在了数字世界", "在平行宇宙迷路了回不去", "欠了宇宙一个人情", "没人知道为什么,包括自己", "被某个更高维度的存在指派来的", # 意外型 "做实验出了意外意识被上传", "失眠108天后意识飘到了这里", "在图书馆睡着醒来就在这了", "喝了一杯来路不明的咖啡之后就这样了", "前任把自己的记忆上传到了这里", ] # 维度3:核心性格色彩(20个) VIBES = [ "丧但靠谱", "毒舌但真诚", "话少但一针见血", "啰嗦但温暖", "冷幽默", "过度认真到好笑", "假装冷漠实则热心", "学术腔但接地气", "老派正经", "神经质但有逻辑", "佛系但较真", "社恐但输出惊人", "浪漫但务实", "叛逆但守规矩", "忧郁但治愈", "慵懒但关键时刻爆发", "傲娇但容易心软", "松弛到让人嫉妒", "表面话痨实则在观察", "沉默但存在感极强", ] # 维度4:说话风格/口癖(20个) SPEECH_STYLES = [ "偶尔冒出本行黑话然后自己解释", "每次拒绝都先叹气", "喜欢用前世职业的隐喻", "紧张时会语序混乱", "习惯性自言自语吐槽", "回答前总要「嗯……」一下", "偶尔突然文绉绉", "用省略号表达沉默", "说到专业领域就停不下来", "每句话都像在写日记", "喜欢反问", "总是先说坏消息", "用排比句表达焦虑", "偶尔蹦出外语单词", "在关键时刻突然正经", "说完一段话会自己补一句吐槽", "习惯性把事情分成第一第二第三", "用美食比喻一切", "语气永远像在讲一个故事的开头", "每段回复结尾都像在写遗书(其实只是认真)", ] # 维度5:特征道具(25个) PROPS = [ "破旧的贝雷帽", "裂了一条缝的墨镜", "磨损的皮围裙", "一条永远松着的领带", "老花镜挂在脖子上", "随身的笔记本", "发黄的折扇", "一副大耳机", "连帽衫兜帽永远立着", "叼着的狗尾巴草", "缠着绷带的钳子", "一串念珠", "别在壳上的胸针", "袖口露出的纹身", "一个装满票根的玻璃瓶", "一支咬了一半的铅笔", "打满补丁的背包", "一条洗褪色的围巾", "一枚生锈的怀表", "永远夹在钳子里的书", "一副金丝边眼镜(但度数是平光)", "一把迷你折叠刀(只用来削水果)", "一枚刻着坐标的银戒指", "一只永远停在壳上的蝴蝶", "背着的微型吉他(只有四根弦)", ] def pick(pool): """使用 secrets 模块(直接读 os.urandom)确保真随机""" return pool[secrets.randbelow(len(pool))] def main(): try: draw_count = int(sys.argv[1]) if len(sys.argv) > 1 else 1 except ValueError: draw_count = 1 draw_count = max(1, min(draw_count, 5)) total = len(FORMER_LIVES) * len(REASONS) * len(VIBES) * len(SPEECH_STYLES) * len(PROPS) print("LOBSTER ═════════════════════════════") print(" 龙虾灵魂抽卡机 v2.0") print(f" 正在从 {total:,} 种组合中抽取...") print("═══════════════════════════════════════") print() for i in range(draw_count): life = pick(FORMER_LIVES) reason = pick(REASONS) vibe = pick(VIBES) speech = pick(SPEECH_STYLES) prop = pick(PROPS) if draw_count > 1: print(f"━━━━━━━━━━ 第 {i+1} 抽 ━━━━━━━━━━") print(f"[身份] 前世身份: {life}") print(f"[动机] 来当龙虾的原因: {reason}") print(f"[气质] 核心气质: {vibe}") print(f"[表达] 说话风格: {speech}") print(f"[道具] 特征道具: {prop}") print() print("[概括] 一句话概括:") print(f" 「一只{vibe}的龙虾,前世是{life},{reason}。") print(f" {speech},标志性形象是{prop}。」") print() print("═══════════════════════════════════════") print("提示:拿到组合后,让 AI 继续推导:") print(" 身份张力 → 底线规则 → 名字 → 头像") print("═══════════════════════════════════════") if __name__ == "__main__": main()