|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 Maz马 于 2026-8-17 11:20 编辑
全随机游戏就是肉鸽Rogue了...
26/8/17 重构了类和变量的命名风格,配置方式,使用方式。
让内部黑箱工厂化,不再用调用式配置。
支持节点、单元检索生成。
组件可以对接的功能
1随机取名,随机属性的角色
2随机取名,随机属性的道具
3随机地点,发生随机事件
4随机房间,放置随机家具
...
组件本身是定义了随机组装的规则而不是生产具体的对象
所以这是一个核心
在使用上需要自行设计接收者,可以是类,也可以是函数
这里主要还是提供一个“心脏”提供一个思路
如果只想使用,完全不关心内部
你只要知道,在配置好树图后,系统提交给你的是
一枚 随机种子
种子是一个RL_Seed对象,内部属性是:
units 单元列表
nodes 节点列表
votes 投票字典
以及name,rare等对以上三个属性封装翻译处理后转发的getattr方法
系统不知道你的节点内容,单元内容,给哪个tag投票
只根据你设计的路径图进行收集组装。
过去的思路是写表,在结构简单时还行
随机创建角色
但一旦可能性变多,分支复用,写表穷举就会十分臃肿
然后就演变成以下
第一部分:RL系统(直接复制为一个文件)
[RenPy] 纯文本查看 复制代码 # ---------- 节点随机核心 ----------
init python:
"""
Roguelike Core(Ren'py 8.3.6)
Ver 1.0
Author: Maz
核心设计
有向无环图、双树嵌套、投票字典
RL_Node ➡ RL_Node RL_Node ➡ RL_Unit
| |
➡ RL_Node ➡ RL_Unit
| |
➡ RL_Node ➡ RL_Unit
从节点树随机选择路径到达叶子节点结束 ,从每个节点的局部单元树随机获取数据,用词条投票的模式整合成 随机种子字典
"""
# 随机种子注册表单
default _RL_SYS = {}
init python:
import random
class RL_Unit:
def __init__(self,name,roll=None,node=None,vote=None):
self.name = name # 文本
self.roll = roll # 权重 数值越大概率越大,正数非0
self.node = node # 所属节点(NODE对象)
self.vote = vote # 投票字典/词缀系统 {tags:value}
class RL_Node:
def __init__(self,name,roll=None,units=None,parents=None,childs=None):
self.name = name # 文本
self.roll = roll # 权重 数值越大概率越大,正数非0
self.units = units or [] # 关联单元(UNIT对象池)
self.parents = parents or [] # 父级节点(NODE对象池)
self.childs = childs or [] # 子级节点(NODE对象池)
class RL_Seed:
def __init__(self,units,nodes,votes):
self.units = units # 单元列表
self.nodes = nodes # 节点列表
self.votes = votes # 投票字典
# 转发给外部的方法,可在这一层同一封装特殊处理,比如先翻译再组合字段
def __getattr__(self, attr):
if attr == "name":
return "".join(renpy.translate_string(u) for u in self.units)
if attr == "type":
return renpy.translate_string(self.nodes[0])
if attr == "race":
return renpy.translate_string(self.nodes[1])
if attr == "rare":
return "".join(renpy.translate_string(u) for u in self.nodes[2:])
raise AttributeError(attr)
class RL_Tree:
def __init__(self,tree,registry):
self.tree = tree # 树图名称
self.registry = registry # 注册表单 {树名:{名称:种子字典}}
self.nodepool = {} # 节点表单 {node_name:node obj}
self.unitpool = {} # 单元表单 {node_name:unit obj}
self.cache_roots = [] # 所有根 [n,n...]
self.cache_paths = [] # 所有路径 [(n,n),(n,n)...]
self.cache_units = {} # 单元索引 {u:[n...]}
self.cache_nodes = {} # 节点索引 {n:[[n...],[n...]...]}
# 节点 创建/关联(_roll 必填,配置表已保证合法)
def _set_node(self,node_name,roll):
if node_name not in self.nodepool:
self.nodepool[node_name] = RL_Node(node_name,roll=roll)
def _link_node(self,node_name,node_names):
for k in node_names:
if k not in self.nodepool:
continue
if self.nodepool[node_name] not in self.nodepool[k].parents:
self.nodepool[k].parents.append(self.nodepool[node_name])
if self.nodepool[k] not in self.nodepool[node_name].childs:
self.nodepool[node_name].childs.append(self.nodepool[k])
# 单元 创建/关联(_unit_names 标准化:[名字,权重,投票] 三元素,不允许多种格式)
def _set_unit(self,node_name,unit_names):
if node_name not in self.nodepool:
print(f"!!!节点'{node_name}'不存在,请先创建节点")
return
if node_name not in self.unitpool:
self.unitpool[node_name] = []
exist = {unit.name for unit in self.unitpool[node_name]}
for i in unit_names:
_name = i[0]
_roll = i[1]
_vote = i[2]
if _name not in exist:
self.unitpool[node_name].append(RL_Unit(_name,roll=_roll,vote=_vote))
def _link_unit(self):
# 关联所有节点和节点下所有单元
for k in self.nodepool:
if k not in self.unitpool:
print(f"??? 节点'{k}'下没有任何关联单元")
for k in self.unitpool:
self.nodepool[k].units = self.unitpool[k]
for unit in self.unitpool[k]:
unit.node = self.nodepool[k]
# 遍历树图 深度优先搜索
def _path_update(self):
# 清空缓存
self.cache_roots = []
self.cache_paths = []
self.cache_units = {}
self.cache_nodes = {}
# 锁定根,缓存根,DFS
for node in self.nodepool.values():
if not node.parents:
self.cache_roots.append(node.name)
self._path_dfs(node,[],self.cache_paths,{})
# 缓存索引
for path in self.cache_paths:
for k in path:
if k not in self.cache_nodes:
self.cache_nodes[k] = []
self.cache_nodes[k].append(path)
# 单元索引:单元名 → 含它的节点列表(跨节点重名累积)
for node,units in self.unitpool.items():
for unit in units:
if unit.name not in self.cache_units:
self.cache_units[unit.name] = []
self.cache_units[unit.name].append(node)
# DFS 从指定节点出发 检测环 并 收集路径
def _path_dfs(self,node,path,paths,visit):
if node.name in visit:
loop = path[visit[node.name]:] + [node.name]
print(f"!!!检测到环: {' → '.join(loop)}")
return
visit[node.name] = len(path)
# 每次加入节点
path.append(node.name)
# 开始递归
# path [1]➡[1,2]➡[1,2,3]
# paths []
if node.childs:
for child in node.childs:
self._path_dfs(child,path,paths,visit.copy())
# 递归到最深处后把路径加入路径列表
# path [1,2,3]
# paths [(1,2,3)]
else:
paths.append(tuple(path))
# 弹出最后一个节点,检查2除了3能不能继续,逐级回退检查
# paths [(1,2,3)]
path.pop()
# 打印缓存
def _path_check(self):
print(f"@ {self.tree}")
print("-" * 60)
if not self.cache_roots:
print("!!! 未找到根节点 !!!")
else:
for i in self.cache_roots:
print(f"根节点: {i}")
print(f"共 {len(self.nodepool)} 个节点,{len(self.cache_roots)} 个根节点")
if not self.cache_paths:
print("!!! 未找到路径 !!!")
print("请先刷新树图缓存")
print("如果已经缓存,则节点未进行连接")
else:
print(f"共 {len(self.cache_paths)} 条路径")
print("")
for i,p in enumerate(self.cache_paths,1):
print(f"{i:3}. {' → '.join(p)}")
# 节点筛选路径
def _random_paths(self,must_nodes,skip_nodes):
paths = set(self.cache_paths)
# 候选 路径交集
if must_nodes:
path_sets = [set(self.cache_nodes.get(node, [])) for node in must_nodes]
paths = set.intersection(*path_sets)
# 排除 路径并集
if skip_nodes:
skip_sets = [set(self.cache_nodes.get(node, [])) for node in skip_nodes]
paths = paths - set.union(*skip_sets)
return paths
# 单元筛选路径 返回可用路径
def _random_units(self,must_units,skip_units):
paths = set(self.cache_paths)
musts = {} # 必须单元节点表 {单元:[落点...]}
skips = {} # 回避单元节点表 {节点:{单元...}}
# 必须单元
if must_units:
# 读取预存的单元索引,单元名映射节点,映射表的设计是同一单元名:[节点名,节点名...]
# 因为在设计上是字段检索,因此单元唯一,但不同节点下的不同单元的单元名的映射并不唯一
for _u in must_units:
musts[_u] = self.cache_units.get(_u, [])
# 节点可能持有同一单元名,把所有节点组合穷举,找出能同时锁定单元的路径
unit_paths = set()
must_units = {u:set() for u in musts}
# 穷举节点组合
combos = [[]]
for unit in musts:
new_combos = []
for combo in combos:
for node in musts[unit]:
new_combos.append(combo + [node])
combos = new_combos
# 筛选可用组合
for combo in combos:
# 同一个节点被两个单元锁定,抛弃
if len(set(combo)) != len(combo):
continue
# 无路径同时锁定全部的单元,抛弃
combo_paths = set(self.cache_nodes.get(combo[0], []))
for node in combo[1:]:
combo_paths &= set(self.cache_nodes.get(node, []))
if not combo_paths:
continue
# 累加组装 paths,musts
unit_paths |= combo_paths
for unit,node in zip(musts,combo):
must_units[unit].add(node)
# 整理最终计算值
paths = unit_paths
musts = {u:sorted(nodes) for u,nodes in must_units.items() if nodes}
# 回避单元
if skip_units:
# 因为逻辑上需要节点反查单元,所以直接反向建表
for _u in skip_units:
for node in self.cache_units.get(_u, []):
skips.setdefault(node,set()).add(_u)
# 筛选可用组合
for node,names in list(skips.items()):
# 路径存在全为回避单元的节点,抛弃
if all(k.name in names for k in self.nodepool[node].units):
paths -= set(self.cache_nodes.get(node,[]))
# 无需整理skips,因为是查找制,避免多余遍历
return paths,musts,skips
# 加权游走:先按节点权重随机选路径,再为必须单元分配落点,最后按绑定回填单元
def _random_walk(self,paths,must_units,skip_units):
if not paths:
return [],[]
# 按节点权重筛选路径
idx = 0
select_nodes = []
while paths:
# 获取当前索引节点
current_names = list(set([path[idx] for path in paths]))
weight = [self.nodepool[name].roll for name in current_names]
select = random.choices(current_names,weights=weight,k=1)[0]
# 从节点池放进结果集
select_nodes.append(self.nodepool[select])
# 排除不匹配的路径,并前进一步
paths = [path for path in paths if path[idx] == select]
idx += 1
# 如果只剩一条路径,直接走完剩余部分,如果路径恰好结束,那么直接结束
# 不存在索引越位,因为节点不可能既为路径,又为末端
if len(paths) == 1:
path = paths[0]
for i in range(idx,len(path)):
select_nodes.append(self.nodepool[path[i]])
break
# 为必须单元分配落点
path_names = [n.name for n in select_nodes]
assign = {}
if must_units:
occupied = set()
# 可用落点少的先分(唯一落点优先,防止同节点挤占)
order = []
for unit in must_units:
count = 0
for n in must_units[unit]:
if n in path_names:
count += 1
order.append((count, unit))
order.sort()
for _, unit in order:
avail = [n for n in must_units[unit] if n in path_names and n not in occupied]
if not avail:
continue
pick = random.choice(avail)
assign[pick] = unit
occupied.add(pick)
# 去除回避单元,按分配回填单元,其余按权重随机
select_units = []
for node_obj in select_nodes:
if not node_obj.units:
continue
cand = [u for u in node_obj.units if u.name not in skip_units.get(node_obj.name,())]
if node_obj.name in assign:
unit = [u for u in cand if u.name == assign[node_obj.name]]
if unit:
select_units.append(unit[0])
continue
weight_units = [u.roll for u in cand]
select_units.append(random.choices(cand,weights=weight_units,k=1)[0])
return select_units,select_nodes
# 由路径集生成种子
def _random_seed(self,paths,must_units,skip_units):
_units,_nodes = self._random_walk(paths,must_units,skip_units)
votes = {}
for unit in _units:
if not unit.vote:
continue
for k,v in unit.vote.items():
votes[k] = votes.get(k,0) + v
# 组装种子实例
return RL_Seed([unit.name for unit in _units],[node.name for node in _nodes],votes)
# 对外接口
def obj_random(self,id,must_nodes=None,skip_nodes=None,must_units=None,skip_units=None):
if must_nodes and not all(node_name in self.nodepool for node_name in must_nodes):
print(f"???存在未注册节点,随机游走返回空种子")
if must_units and not all(u in self.cache_units for u in must_units):
print(f"???存在未注册单元,随机游走返回空种子")
# 无约束随机根节点生成
if not must_nodes and not must_units:
must_nodes = [random.choice(self.cache_roots)]
# 单元域:可用路径 + 强选单元 + 回避单元(收在 _random_units 内)
paths, musts, skips = self._random_units(must_units, skip_units)
# 节点域与单元域路径取交集
final_paths = self._random_paths(must_nodes, skip_nodes) & paths
if not final_paths:
print("!!!约束无法满足,无可用路径")
return
# 存储 随机种子 到 随机种子注册表单
self.registry[self.tree][id] = self._random_seed(final_paths,musts,skips)
return self.registry[self.tree].get(id)
def obj_get(self,id):
# 已存在直接返回,未创建则随机生成一个
if id not in self.registry[self.tree]:
return self.obj_random(id)
return self.registry[self.tree].get(id)
def obj_del(self,id):
if id not in self.registry[self.tree]:
print("!!!未记录的id,删除无效")
return
return self.registry[self.tree].pop(id)
def obj_list(self):
seeds = list(self.registry[self.tree].keys())
print(f"树图 '{self.tree}' 中共有 {len(seeds)} 个随机种子: {seeds}")
return seeds
# 树图管理器
class RL_Manager:
def __init__(self):
self.registry = store._RL_SYS.setdefault("_registry_",{}) # 注册表单 {tree_name:{_id:_seed}}(硬绑定全局注册表)
self.treeform = store._RL_SYS.setdefault("_treepool_",{}) # 树图表单 {tree_name:tree obj} (硬绑定全局注册表)
self.tree_name_cache = None # 树图名缓存
# 接入树图 间接操作注册表单
def api_tree(self,tree):
if tree not in self.registry:
self.registry[tree] = {}
self.treeform[tree] = RL_Tree(tree,self.registry)
self.tree_name_cache = tree
if tree != self.tree_name_cache:
print(f"\n※ 已接入随机树: {tree}")
self.tree_name_cache = tree
return self.treeform[tree]
# 校验刷新
def api_update(self,tree=None,check=False):
if tree:
self.api_tree(tree)._path_update()
else:
for name in self.treeform:
self.api_tree(name)._path_update()
if check:
self.api_check(tree)
# 打印报告
def api_check(self,tree=None):
# 打印标题
print("\n\n\n")
print("RL SYS")
print("=" * 60)
print("!!! 注意核对根节点 !!!")
print("!!!根节点不正常则环位于根 !!!")
print("")
print("!!! 注意核对路径 !!!")
print("!!!不检测*跳过节点*的逆向环!!!")
print("")
if tree:
self.api_tree(tree)._path_check()
else:
for name in self.treeform:
self.api_tree(name)._path_check()
print("=" * 60)
print("\n\n\n")
# 对外接口
def obj_random(self,tree,id,must_nodes=None,skip_nodes=None,must_units=None,skip_units=None):
return self.api_tree(tree).obj_random(id,must_nodes,skip_nodes,must_units,skip_units)
def obj_get(self,tree,id):
return self.api_tree(tree).obj_get(id)
def obj_del(self,tree,id):
return self.api_tree(tree).obj_del(id)
def obj_list(self,tree=None):
if tree:
self.api_tree(tree).obj_list()
else:
for name in self.registry:
self.api_tree(name).obj_list()
return
# 遍历配置表建树工厂
def init_RLSYS():
store.RL = RL_Manager()
for cfg in RL_TREES:
t = store.RL.api_tree(cfg["tree"])
for name,roll in cfg["node"].items():
t._set_node(name,roll=roll)
for parent,childs in cfg["link"].items():
t._link_node(parent,node_names=childs)
for node,units in cfg["unit"].items():
t._set_unit(node,units)
t._link_unit()
# 完成树图注册,检测结构健康,顺遍在控制台输出
store.RL.api_update(check=True)
# 在renpy完全启动后再初始化树图
config.start_callbacks += [init_RLSYS]
第二部分 配置树图:
[RenPy] 纯文本查看 复制代码 # 树图配置表
# tree 树名 内部标识
# link 字典 {父节点:[子节点...]}
# node 字典 {节点名:权重},权重数值越大概率越大,默认1(均等)
# unit 字典 {节点:[[名字,权重,投票],...]},每个单元固定三元素
define RL_TREE_1 = {
"tree": "中文姓名",
"link":{
_("角色"):[_("男"),_("女")],
_("男"):[_("男前名")],_("男前名"):[_("男中名")],_("男中名"):[_("男后名")],
_("女"):[_("女前名")],_("女前名"):[_("女中名")],_("女中名"):[_("女后名")],
},
"node":{
_("角色"):1,_("男"):4,_("女"):7,
_("男前名"):1,_("男中名"):1,_("男后名"):1,
_("女前名"):1,_("女中名"):1,_("女后名"):1,
},
"unit":{
_("男前名"):[
[_("赵"),1,{}],[_("钱"),1,{}],[_("孙"),1,{}],[_("李"),1,{}],[_("周"),1,{}],[_("吴"),1,{}],[_("郑"),1,{}],[_("王"),1,{}],
[_("冯"),1,{}],[_("陈"),1,{}],[_("蒋"),1,{}],[_("沈"),1,{}],[_("韩"),1,{}],[_("杨"),1,{}],[_("朱"),1,{}],[_("秦"),1,{}],
[_("许"),1,{}],[_("何"),1,{}],[_("吕"),1,{}],[_("张"),1,{}],[_("孔"),1,{}],[_("曹"),1,{}],[_("魏"),1,{}],[_("陶"),1,{}],
[_("姜"),1,{}],[_("韦"),1,{}],[_("马"),1,{}],[_("袁"),1,{}],[_("柳"),1,{}],[_("史"),1,{}],[_("姚"),1,{}],[_("汪"),1,{}],
[_("朱"),1,{}],[_("董"),1,{}],[_("梁"),1,{}],[_("杜"),1,{}],[_("阮"),1,{}],[_("蓝"),1,{}],[_("贾"),1,{}],[_("童"),1,{}],
[_("武"),1,{}],[_("司马"),1,{}],[_("上官"),1,{}],[_("欧阳"),1,{}],[_("夏侯"),1,{}],[_("诸葛"),1,{}],[_("东方"),1,{}],
[_("公孙"),1,{}],[_("宇文"),1,{}],[_("长孙"),1,{}],[_("慕容"),1,{}],
],
_("女前名"):[
[_("赵"),1,{}],[_("钱"),1,{}],[_("孙"),1,{}],[_("李"),1,{}],[_("周"),1,{}],[_("吴"),1,{}],[_("郑"),1,{}],[_("王"),1,{}],
[_("冯"),1,{}],[_("陈"),1,{}],[_("蒋"),1,{}],[_("沈"),1,{}],[_("韩"),1,{}],[_("杨"),1,{}],[_("朱"),1,{}],[_("秦"),1,{}],
[_("许"),1,{}],[_("何"),1,{}],[_("吕"),1,{}],[_("张"),1,{}],[_("孔"),1,{}],[_("曹"),1,{}],[_("魏"),1,{}],[_("陶"),1,{}],
[_("姜"),1,{}],[_("韦"),1,{}],[_("马"),1,{}],[_("袁"),1,{}],[_("柳"),1,{}],[_("史"),1,{}],[_("姚"),1,{}],[_("汪"),1,{}],
[_("朱"),1,{}],[_("董"),1,{}],[_("梁"),1,{}],[_("杜"),1,{}],[_("阮"),1,{}],[_("蓝"),1,{}],[_("贾"),1,{}],[_("童"),1,{}],
[_("武"),1,{}],[_("司马"),1,{}],[_("上官"),1,{}],[_("欧阳"),1,{}],[_("夏侯"),1,{}],[_("诸葛"),1,{}],[_("东方"),1,{}],
[_("公孙"),1,{}],[_("宇文"),1,{}],[_("长孙"),1,{}],[_("慕容"),1,{}],
],
_("男中名"):[
[_("伯"),1,{}],[_("仲"),1,{}],[_("叔"),1,{}],[_("季"),1,{}],[_("子"),1,{}],[_("作"),1,{}],[_("文"),1,{}],[_("武"),1,{}],
[_("元"),1,{}],[_("宇"),1,{}],[_("冠"),1,{}],[_("世"),1,{}],[_("震"),1,{}],[_("晓"),1,{}],[_("克"),1,{}],[_("轩"),1,{}],
[_("昂"),1,{}],[_("光"),1,{}],[_("修"),1,{}],[_("柯"),1,{}],[_("云"),1,{}],[_(""),15,{}],
],
_("女中名"):[
[_("温"),1,{}],[_("婉"),1,{}],[_("绮"),1,{}],[_("诗"),1,{}],[_("润"),1,{}],[_("涵"),1,{}],[_("曼"),1,{}],[_("玉"),1,{}],
[_("元"),1,{}],[_("语"),1,{}],[_("言"),1,{}],[_("怜"),1,{}],[_("惜"),1,{}],[_("清"),1,{}],[_("雨"),1,{}],[_("文"),1,{}],
[_("汶"),1,{}],[_("嫣"),1,{}],[_("芷"),1,{}],[_("初"),1,{}],[_("乐"),1,{}],[_(""),15,{}],
],
_("男后名"):[
[_("杰"),1,{}],[_("和"),1,{}],[_("祖"),1,{}],[_("雄"),1,{}],[_("长"),1,{}],[_("德"),1,{}],[_("儒"),1,{}],
[_("冲"),1,{}],[_("高"),1,{}],[_("龙"),1,{}],[_("炎"),1,{}],[_("霖"),1,{}],[_("彻"),1,{}],[_("南"),1,{}],
[_("爽"),1,{}],[_("过"),1,{}],[_("谋"),1,{}],[_("晏"),1,{}],[_("天"),1,{}],[_("农"),1,{}],[_("坤"),1,{}],
],
_("女后名"):[
[_("柔"),1,{}],[_("珊"),1,{}],[_("怡"),1,{}],[_("容"),1,{}],[_("婷"),1,{}],[_("梦"),1,{}],[_("卿"),1,{}],[_("岚"),1,{}],
[_("清"),1,{}],[_("琴"),1,{}],[_("瑶"),1,{}],[_("璇"),1,{}],[_("萱"),1,{}],[_("琪"),1,{}],[_("晴"),1,{}],[_("彤"),1,{}],
[_("若"),1,{}],[_("凤"),1,{}],[_("稚"),1,{}],[_("乐"),1,{}],[_("然"),1,{}],
],
},}
define RL_TREE_2 = {
"tree": "修仙道具",
"link":{
_("道具"):[_("秘籍"),_("药品")],
_("秘籍"):[_("天阶"),_("地阶"),_("玄阶"),_("黄阶")],
_("天阶"):[_("极品"),_("上品"),_("中品"),_("下品")],_("地阶"):[_("极品"),_("上品"),_("中品"),_("下品")],
_("玄阶"):[_("极品"),_("上品"),_("中品"),_("下品")],_("黄阶"):[_("极品"),_("上品"),_("中品"),_("下品")],
_("极品"):[_("功法"),_("身法"),_("武技"),_("战技")],_("上品"):[_("功法"),_("身法"),_("武技"),_("战技")],
_("中品"):[_("功法"),_("身法"),_("武技"),_("战技")],_("下品"):[_("功法"),_("身法"),_("武技"),_("战技")],
_("药品"):[_("九品"),_("六品"),_("三品"),_("一品")],
_("九品"):[_("丹药"),_("灵植")],_("六品"):[_("丹药"),_("灵植")],
_("三品"):[_("丹药"),_("灵植")],_("一品"):[_("丹药"),_("灵植")],
},
"node":{
_("道具"):1,
_("秘籍"):1,
_("天阶"):0.05,_("地阶"):0.15,_("玄阶"):0.30,_("黄阶"):0.50,
_("极品"):0.10,_("上品"):0.20,_("中品"):0.30,_("下品"):0.40,
_("功法"):1.0,_("身法"):1.0,_("武技"):1.0,_("战技"):1.0,
_("药品"):1,
_("九品"):0.35,_("六品"):0.30,_("三品"):0.20,_("一品"):0.15,
_("丹药"):0.50,_("灵植"):0.50,
},
"unit":{
_("天阶"):[[_("大天衍"),1,{}],[_("无极"),1,{}],[_("万象"),1,{}],[_("九转"),1,{}],[_("四象"),1,{}]],
_("地阶"):[[_("阴阳"),1,{}],[_("梵天"),1,{}],[_("破军"),1,{}],[_("八荒"),1,{}],[_("天罡"),1,{}]],
_("玄阶"):[[_("两仪"),1,{}],[_("星月"),1,{}],[_("七杀"),1,{}],[_("镇狱"),1,{}],[_("地煞"),1,{}]],
_("黄阶"):[[_("孤峰"),1,{}],[_("崩山"),1,{}],[_("沧澜"),1,{}],[_("断水"),1,{}],[_("叠浪"),1,{}]],
_("极品"):[[_("真龙"),1,{}],[_("白虎"),1,{}],[_("朱雀"),1,{}],[_("真武"),1,{}],[_("鲲鹏"),1,{}]],
_("上品"):[[_("赤炎"),1,{}],[_("寒霜"),1,{}],[_("风雷"),1,{}],[_("穿云"),1,{}],[_("金刚"),1,{}]],
_("中品"):[[_("游龙"),1,{}],[_("伏虎"),1,{}],[_("贪狼"),1,{}],[_("长春"),1,{}],[_("灵蛇"),1,{}]],
_("下品"):[[_("一"),1,{}],[_("九"),1,{}],[_("十三"),1,{}],[_("二十四"),1,{}],[_("三十六"),1,{}],[_(""),1,{}]],
_("功法"):[[_("法"),1,{}],[_("经"),1,{}],[_("诀"),1,{}],[_("功"),1,{}],[_("残篇"),1,{}]],
_("身法"):[[_("变"),1,{}],[_("纵"),1,{}],[_("步"),1,{}],[_("遁"),1,{}],[_("闪"),1,{}]],
_("武技"):[[_("破"),1,{}],[_("斩"),1,{}],[_("掌"),1,{}],[_("拳"),1,{}],[_("指"),1,{}]],
_("战技"):[[_("术"),1,{}],[_("击"),1,{}],[_("剑"),1,{}],[_("刀"),1,{}],[_("枪"),1,{}]],
_("九品"):[[_("还魂"),1,{}],[_("断肠"),1,{}],[_("妖"),1,{}],[_("仙"),1,{}],[_("异域"),1,{}]],
_("六品"):[[_("金"),1,{}],[_("银"),1,{}],[_("暴血"),1,{}],[_("聚灵"),1,{}],[_("破境"),1,{}]],
_("三品"):[[_("固本"),1,{}],[_("培元"),1,{}],[_("金创"),1,{}],[_("提气"),1,{}],[_("补神"),1,{}]],
_("一品"):[[_("练气"),1,{}],[_("筑基"),1,{}],[_("回气"),1,{}],[_("益血"),1,{}],[_("治愈"),1,{}]],
_("丹药"):[[_("丹"),1,{}],[_("散"),1,{}],[_("汤"),1,{}],[_("液"),1,{}],[_("药"),1,{}]],
_("灵植"):[[_("叶"),1,{}],[_("花"),1,{}],[_("草"),1,{}],[_("果"),1,{}],[_("根"),1,{}]],
},}
define RL_TREE_3 = {
"tree": "西幻姓名",
"link":{
_("角色"):[_("男"),_("女")],
_("男"):[_("男前名")],_("女"):[_("女前名")],
_("男前名"):[_("男中名")],_("女前名"):[_("女中名")],
_("男中名"):[_("男后名")],_("女中名"):[_("女后名")],
},
"node":{
_("角色"):1,
_("男"):4,_("女"):7,
_("男前名"):1,_("女前名"):1,
_("男中名"):1,_("女中名"):1,
_("男后名"):1,_("女后名"):1,
},
"unit":{
_("男前名"):[
[_("诺亚"),1,{}],[_("利亚姆"),1,{}],[_("奥利弗"),1,{}],[_("以利亚"),1,{}],[_("卢卡斯"),1,{}],
[_("马特奥"),1,{}],[_("利维"),1,{}],[_("阿瑟"),1,{}],[_("西奥多"),1,{}],[_("亨利"),1,{}],
[_("亚历山大"),1,{}],[_("塞巴斯蒂安"),1,{}],[_("本杰明"),1,{}],[_("伊桑"),1,{}],[_("丹尼尔"),1,{}],
],
_("女前名"):[
[_("艾玛"),1,{}],[_("奥利维亚"),1,{}],[_("夏洛特"),1,{}],[_("索菲亚"),1,{}],[_("阿米莉亚"),1,{}],
[_("伊莎贝拉"),1,{}],[_("米娅"),1,{}],[_("埃维莉娜"),1,{}],[_("卢娜"),1,{}],[_("艾娃"),1,{}],
[_("哈珀"),1,{}],[_("吉安娜"),1,{}],[_("伊丽莎白"),1,{}],[_("埃莉诺"),1,{}],[_("斯卡利特"),1,{}],
],
_("男中名"):[[_("."),1,{}]],
_("女中名"):[[_("."),1,{}]],
_("男后名"):[
[_("史密斯"),1,{}],[_("约翰逊"),1,{}],[_("威廉姆斯"),1,{}],[_("布朗"),1,{}],[_("琼斯"),1,{}],
[_("米勒"),1,{}],[_("戴维斯"),1,{}],[_("加西亚"),1,{}],[_("罗德里格斯"),1,{}],[_("威尔逊"),1,{}],
[_("马丁内斯"),1,{}],[_("安德森"),1,{}],[_("泰勒"),1,{}],[_("托马斯"),1,{}],[_("杰克逊"),1,{}],
],
_("女后名"):[
[_("史密斯"),1,{}],[_("约翰逊"),1,{}],[_("威廉姆斯"),1,{}],[_("布朗"),1,{}],[_("琼斯"),1,{}],
[_("米勒"),1,{}],[_("戴维斯"),1,{}],[_("加西亚"),1,{}],[_("罗德里格斯"),1,{}],[_("威尔逊"),1,{}],
[_("马丁内斯"),1,{}],[_("安德森"),1,{}],[_("泰勒"),1,{}],[_("托马斯"),1,{}],[_("杰克逊"),1,{}],
],
},}
# 树图放进工厂列表中
define RL_TREES = [RL_TREE_1, RL_TREE_2, RL_TREE_3]
第三部分 使用方式:
[RenPy] 纯文本查看 复制代码 # ---------- 最小使用流程示例 ----------
init python:
# 自定义复杂类
class Char:
def __init__(self,seed=None,name=None,rare=None,type=None,race=None):
self.seed = seed # 存储种子实例
# 显式给的名字 会 覆盖种子兜底属性
if name is not None:
self.name = name
if type is not None:
self.type = type
if race is not None:
self.race = race
if rare is not None:
self.rare = rare
# 用getattr方法,让种子数据只作为兜底,实例上不存在属性时,使用种子的属性
def __getattr__(self,attr):
if attr in ("name","type","race","rare") and self.seed is not None:
seed = self.__dict__.get("seed") # 直接查实例字典,防递归
if seed is not None:
return getattr(seed,attr)
raise AttributeError(attr)
# 原生角色类 用 猴子补丁 注入种子兜底方法
def adv_getattr(self,attr):
if attr in ("type","race","rare"):
seed = self.__dict__.get("seed") # 直接查实例字典,防递归
if seed is not None:
return getattr(seed,attr)
raise AttributeError(attr)
# 注入
ADVCharacter.seed = None # 类属性兜底,未注入时不炸
ADVCharacter.__getattr__ = adv_getattr
# 原生角色的使用方法 动态转发name实际数据
default testchar = Character("testchar.seed.name",dynamic=True)
label RLSYS_test:
"随机种子为实例,系统只负责生成和存储,不负责你如何使用"
"种子本身带了封装好的返回属性函数"
"用 RL.obj_random('树图名称','任意字符ID') 取得随机种子"
$ RL.obj_random('中文姓名','随机1')
# 用 RL.obj_random('树图名称','任意字符ID',[必须节点名],[回避节点名],[必须单元名],[回避单元名]) 取得定向随机种子
$ RL.obj_random('中文姓名','随机1',['男'],[],['龙'],[])
"使用不同树图,可用同样的字符ID"
$ RL.obj_random('修仙道具','随机1')
"使用相同树图,同字符ID会覆盖原来的种子"
$ RL.obj_random('修仙道具','随机1')
"用 RL.obj_get(树图名称,字符ID) 获取已创建的种子"
$ RL.obj_get('修仙道具','随机1')
"用 RL.obj_del(树图名称,字符ID) 删除已创建的种子"
$ RL.obj_del('修仙道具','随机1')
"用 RL.obj_list() 查看所有已创建的随机种子ID"
$ RL.obj_list()
$ testchar.seed = RL.obj_get('中文姓名','随机2')
testchar "这个原生角色的name使用了动态延迟求值的方法,因此可以直接接入种子的name的getattr方法"
"同时,别的数据也可以调用到种子方法或数据,[testchar.race]"
# 可以重复覆盖,但注意用字符串引号多包裹一层,因为dynamic=True外层会从字面量转为表达式
$ testchar.name = "'我改名了'"
testchar "种子在使用上只是兜底"
""
return
注意,此处只是数据实现,假设要批量的,自动管理多角色、多道具
请查阅 多数据管理技巧
#点击头像 查看我写的更多屎
粉身碎骨浑不怕,要留答辩在人间
|
|