全站通知:

模块:GiftTastesNPC/data/doc

来自星露谷物语维基
跳到导航 跳到搜索
[ 刷新 ]
当前页面是文档页面,会被模块:GiftTastesNPC/data引入。查看模板:Documentation获取更多信息。

当前页面的数据通过以下 Python 代码生成,后续如果游戏版本更新,可重新执行脚本,导出最新的数据。

本 Python 脚本部分内容与 MediaWiki 解析发生冲突,原脚本:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
星露谷物语 NPCGiftTastes.zh-CN.json 转 Lua 数据转换器

此脚本将 NPCGiftTastes.zh-CN.json 文件转换为 Lua 数据格式。

NPCGiftTastes数据格式说明:
1. Universal_* 键: 通用喜好,对所有村民有效
   - 值为用空格分隔的ID数组
   - 正数表示物品ID,负数表示类别ID

2. NPC名称键: 个人喜好,格式为用"/"分隔的字符串
   结构: 最爱对话/最爱物品ID/喜欢对话/喜欢物品ID/不喜欢对话/不喜欢物品ID/讨厌对话/讨厌物品ID/一般对话/一般物品ID
"""

import json
import os
import re
from typing import Dict, List, Any, Union


class NPCGiftTastesConverter:
    def __init__(self, input_file: str, output_file: str = None):
        """
        初始化转换器
        
        Args:
            input_file (str): 输入的JSON文件路径
            output_file (str): 输出的Lua文件路径,如果为None则自动生成
        """
        self.input_file = input_file
        self.output_file = output_file or self._generate_output_filename()
        
        # 通用喜好级别映射
        self.universal_levels = [
            'Universal_Love',
            'Universal_Like', 
            'Universal_Neutral',
            'Universal_Dislike',
            'Universal_Hate'
        ]
        
        # 个人喜好级别映射(索引对应NPC数据中的位置)
        self.personal_levels = [
            'love',      # 0,1 最爱
            'like',      # 2,3 喜欢  
            'dislike',   # 4,5 不喜欢
            'hate',      # 6,7 讨厌
            'neutral'    # 8,9 一般
        ]

    def _generate_output_filename(self) -> str:
        """生成输出文件名"""
        base_name = os.path.splitext(self.input_file)[0]
        return f"{base_name}.lua"

    def _escape_lua_string(self, text: str) -> str:
        """转义Lua字符串中的特殊字符"""
        if not text:
            return '""'
        
        # 转义特殊字符
        text = text.replace('\\', '\\\\')
        text = text.replace('"', '\\"')
        text = text.replace('\n', '\\n')
        text = text.replace('\r', '\\r')
        text = text.replace('\t', '\\t')
        
        return f'"{text}"'

    def _parse_id_list(self, id_string: str) -> List[Union[int, str]]:
        """解析空格分隔的ID列表,可以是数字或字符串"""
        if not id_string or id_string.strip() == '':
            return []
        
        ids = []
        for id_str in id_string.strip().split():
            try:
                # 尝试将ID转换为整数
                ids.append(int(id_str))
            except ValueError:
                # 如果不是数字,可能是特殊标识符 (例如物品的英文名),作为字符串保留
                ids.append(id_str)
        return ids

    def _parse_npc_data(self, npc_data: str) -> Dict[str, Any]:
        """
        解析NPC个人喜好数据
        
        格式: 最爱对话/最爱物品/喜欢对话/喜欢物品/不喜欢对话/不喜欢物品/讨厌对话/讨厌物品/一般对话/一般物品
        """
        parts = npc_data.split('/')
        
        # 确保有足够的部分(至少10个部分)
        while len(parts) < 10:
            parts.append('')
        
        result = {}
        
        for i, level in enumerate(self.personal_levels):
            dialogue_index = i * 2
            items_index = i * 2 + 1
            
            dialogue = parts[dialogue_index] if dialogue_index < len(parts) else ''
            items_str = parts[items_index] if items_index < len(parts) else ''
            
            result[level] = {
                'dialogue': dialogue.strip(),
                'items': self._parse_id_list(items_str)
            }
        
        return result

    def _convert_to_lua_table(self, data: Any, indent: int = 0) -> str:
        """将数据转换为Lua表格式"""
        indent_str = '    ' * indent
        
        if isinstance(data, dict):
            if not data:
                return '{}'
            
            lines = ['{']
            for key, value in data.items():
                # 确保键名是有效的Lua标识符或使用方括号语法
                if isinstance(key, str) and re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', key):
                    key_str = key
                else:
                    key_str = f'[{self._escape_lua_string(str(key))}]'
                
                value_str = self._convert_to_lua_table(value, indent + 1)
                lines.append(f'{indent_str}    {key_str} = {value_str},')
            lines.append(f'{indent_str}}}')
            return '\n'.join(lines)
        
        elif isinstance(data, list):
            if not data:
                return '{}'
            
            # 如果是纯数字数组,使用紧凑格式
            if all(isinstance(x, (int, float)) for x in data):
                return '{' + ', '.join(str(x) for x in data) + '}'
            # 否则,使用多行格式以提高可读性
            else:
                lines = ['{']
                for item in data:
                    item_str = self._convert_to_lua_table(item, indent + 1)
                    lines.append(f'{indent_str}    {item_str},')
                lines.append(f'{indent_str}}}')
                return '\n'.join(lines)
        
        elif isinstance(data, str):
            return self._escape_lua_string(data)
        
        elif isinstance(data, (int, float)):
            return str(data)
        
        elif isinstance(data, bool):
            return 'true' if data else 'false'
        
        elif data is None:
            return 'nil'
        
        else:
            return self._escape_lua_string(str(data))

    def convert(self) -> None:
        """执行转换"""
        print(f"开始转换: {self.input_file}")
        
        # 读取JSON文件
        try:
            with open(self.input_file, 'r', encoding='utf-8') as f:
                json_data = json.load(f)
        except FileNotFoundError:
            print(f"错误: 找不到文件 {self.input_file}")
            return
        except json.JSONDecodeError as e:
            print(f"错误: JSON解析失败 - {e}")
            return
        except Exception as e:
            print(f"错误: 读取文件失败 - {e}")
            return
        
        # 准备Lua数据结构
        lua_data = {
            'universal': {},
            'npcs': {}
        }
        
        # 处理通用喜好
        for level in self.universal_levels:
            if level in json_data:
                level_name = level.replace('Universal_', '').lower()
                lua_data['universal'][level_name] = self._parse_id_list(json_data[level])
        
        # 处理NPC个人喜好
        for key, value in json_data.items():
            if not key.startswith('Universal_'):
                lua_data['npcs'][key] = self._parse_npc_data(value)
        
        # 生成Lua文件内容
        lua_content = self._generate_lua_file(lua_data)
        
        # 写入Lua文件
        try:
            with open(self.output_file, 'w', encoding='utf-8') as f:
                f.write(lua_content)
            print(f"转换完成: {self.output_file}")
            print(f"- 通用喜好级别: {len(lua_data['universal'])}")
            print(f"- NPC数量: {len(lua_data['npcs'])}")
        except Exception as e:
            print(f"错误: 写入文件失败 - {e}")

    def _generate_lua_file(self, data: Dict[str, Any]) -> str:
        """生成完整的Lua文件内容"""
        header = '''--[[
星露谷物语 NPC礼物喜好数据 (中文版)
由脚本自动生成

数据结构说明:
- universal: 通用喜好,对所有NPC有效
  - love/like/neutral/dislike/hate: 各级别喜好的物品/类别ID数组
- npcs: 各NPC的个人喜好
  - [NPC名称]: NPC的个人喜好数据
    - love/like/neutral/dislike/hate: 各级别的对话和物品数据
      - dialogue: 对应级别的对话文本
      - items: 对应级别的物品/类别ID数组

注意: 
- 正数ID表示物品ID,负数ID表示类别ID
- 物品ID也可能是字符串形式(例如英文原名)
- 个人喜好会覆盖通用喜好
--]]

'''
        
        lua_table = self._convert_to_lua_table(data)
        
        return f'{header}local NPCGiftTastes = {lua_table}\n\nreturn NPCGiftTastes\n'


def main():
    """主函数"""
    # 请确保此路径是您系统中正确的路径
    input_file = r"C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley\Content (unpacked)\Data\NPCGiftTastes.zh-CN.json"
    
    # 检查输入文件是否存在
    if not os.path.exists(input_file):
        print(f"错误: 输入文件不存在: {input_file}")
        print("请检查 main() 函数中的 input_file 路径是否正确。")
        return
    
    # 创建转换器并执行转换
    converter = NPCGiftTastesConverter(input_file)
    converter.convert()
    
    print("\n脚本执行完毕!")


if __name__ == '__main__':
    main()