我正在为 Ren'Py 游戏编写一个 mod,其中包含编辑游戏变量值的可能性(“作弊”)。游戏中的变量包括从简单布尔值到相当复杂的变量(例如 simple_variable、obj.attr、obj.attr_a("some_id").attr_b)。这是我用来为变量/属性设置新值的函数(var_name 是变量的字符串名称,new_val 是我尝试设置的值):
def icmod_set_var_val(var_name, new_val): # e.g var_name is avatar.skills["combat"].level
_list = var_name.split('.')
o = globals()[_list[0]] # e.g <store.Avatar object at 0x0000000029388880>
if len(_list) == 1:
o = new_val
elif len(_list) == 2:
setattr(o, _list[1], new_val)
elif len(_list) == 3:
between_quotes = _list[1].split('"')[1::2][0] # e.g combat
first_attr = _list[1].split('[')[0] # e.g skills
_x = getattr(o, first_attr)[between_quotes] # e.g <store.Skill object at 0x00000000293883a0>
setattr(_x, _list[2], new_val) # e.g _list[2] is level
else:
msgs.show('Something went wrong')
它不起作用。当我使用类似的函数来显示修改的值(使用 getattr)时,它们显示正确。但是当我使用控制台或保存游戏并再次打开它时,我可以看到这些值实际上没有改变。我什至尝试使用 exec 来更改值,但这似乎也没有永久效果。那么我在这里做错或遗漏了什么?
e:这似乎是一个 Ren'Py 问题,脚本本身按预期工作(除了
len(_list) == 1
c 部分)。当我打开控制台而不退出 mod 屏幕时,值会发生更改。当我退出模组时,屏幕变化就消失了。
问题出在 Ren'Py 如何处理游戏变量及其与 Python 作用域的交互。
当你修改
store
对象上的属性时,实际上是在修改一个代理对象,而不是实际的游戏变量。这些代理对象在 Ren'Py 引擎更新游戏状态时会被同步。因此,当你退出 mod 屏幕时,Ren'Py 引擎会用之前保存的游戏状态覆盖你的更改。
要解决此问题,你需要使用 Ren'Py 提供的 API 来修改游戏变量。
renpy.store
模块提供了访问和修改游戏变量的功能。
以下是如何使用
renpy.store
模块修改游戏变量的修改后的代码:
import renpy
def icmod_set_var_val(var_name, new_val):
try:
# 获取变量名对应的 Python 对象路径
parts = var_name.split('.')
obj = renpy.store
for part in parts[:-1]:
if '[' in part:
# 处理字典或列表索引
key = part.split('[')[0]
index = int(part.split('[')[1][:-1]) # 提取索引
obj = getattr(obj, key)[index]
else:
obj = getattr(obj, part)
# 设置变量值
setattr(obj, parts[-1], new_val)
except Exception as e:
msgs.show(f'Error setting variable: {e}')
代码解释:
-
导入
renpy
模块。 -
使用
renpy.store
访问游戏变量的根对象。 -
逐级解析变量名,并使用
getattr
获取对应的属性。 -
如果遇到
[]
,则表示访问字典或列表元素,使用相应的索引进行访问。 -
最后,使用
setattr
设置最终属性的值。
通过使用
renpy.store
模块,你的更改将直接应用于游戏变量,并将在游戏保存和加载时持久化。
注意:
- 确保你的 mod 在 Ren'Py 游戏启动后加载。
- 某些游戏变量可能受到游戏逻辑的保护,无法直接修改。