pymud 0.21.1__py3-none-any.whl → 0.21.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pymud/__init__.py +16 -16
- pymud/__main__.py +3 -3
- pymud/decorators.py +234 -234
- pymud/dialogs.py +166 -166
- pymud/extras.py +974 -918
- pymud/i18n.py +62 -62
- pymud/lang/i18n_chs.py +226 -226
- pymud/lang/i18n_eng.py +850 -850
- pymud/logger.py +167 -167
- pymud/main.py +220 -220
- pymud/modules.py +285 -285
- pymud/objects.py +1032 -1032
- pymud/pkuxkx.py +280 -280
- pymud/protocol.py +1010 -1010
- pymud/pymud.py +1295 -1286
- pymud/session.py +3584 -3578
- pymud/settings.py +196 -196
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/METADATA +478 -476
- pymud-0.21.2.dist-info/RECORD +23 -0
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/WHEEL +1 -1
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/licenses/LICENSE.txt +674 -674
- pymud-0.21.1.dist-info/RECORD +0 -23
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/entry_points.txt +0 -0
- {pymud-0.21.1.dist-info → pymud-0.21.2.dist-info}/top_level.txt +0 -0
pymud/pkuxkx.py
CHANGED
@@ -1,281 +1,281 @@
|
|
1
|
-
# 示例脚本:如何在PyMud中玩PKUXKX
|
2
|
-
|
3
|
-
import webbrowser
|
4
|
-
from pymud import Session, IConfig, alias, trigger, timer, gmcp, Alias, Trigger, Timer, SimpleTrigger, SimpleAlias
|
5
|
-
|
6
|
-
# 在PyMud中,使用#load {filename}可以加载对应的配置作为脚本文件以提供支撑。支持多脚本加载
|
7
|
-
# 本示例脚本对PyMud支持的变量(Variable)、触发器(Trigger,包含单行与多行触发)、别名(Alias)、定时器(Timer)进行了代码示例
|
8
|
-
# 使用#load {filename}加载的配置文件中,若有一个类型继承自IConfig,则在#load操作时,会自动创建此类型;若没有继承自IConfig的类,则仅将文件引入
|
9
|
-
# 例如,加载本文件指定的配置,则使用 #load pymud.pkuxkx即可
|
10
|
-
|
11
|
-
# 定义一个自定义配置类,并继承自IConfig。
|
12
|
-
# 目前不在推荐使用Configuration类,而是使用IConfig接口。因为只有使用IConfig接口,才能在类型函数中自动管理由装饰器创建的对象
|
13
|
-
class MyConfig(IConfig):
|
14
|
-
# 类的构造函数,传递参数session,是会话本身。另外请保留*args和**kwargs,以便后续扩展
|
15
|
-
def __init__(self, session: Session, *args, **kwargs) -> None:
|
16
|
-
# 建议将 super().__init__()放在类型init的首句代码,该代码用于对装饰器@alias等函数所装饰的对象进行管理
|
17
|
-
# 调用super().__init__()时,会自动将session传递给父类,以便后续使用。
|
18
|
-
# 因此此处无需再使用self.session = session来保存传递的会话类型
|
19
|
-
#
|
20
|
-
super().__init__(session, *args, **kwargs)
|
21
|
-
|
22
|
-
# 所有自行构建的对象, 建议统一放到self._objs中,方便管理和卸载。
|
23
|
-
# 目前加载卸载可以支持字典、列表、单个对象均可。此处使用字典,是为了方便后续处理其中某个单个对象。
|
24
|
-
# 对象创建时将自动增加到会话中,不需要手动调用session.addObject操作了
|
25
|
-
self._objs = {
|
26
|
-
# 别名,触发器可以通过创建一个对应类型的实例来生成
|
27
|
-
"tri_gem" : SimpleTrigger(self.session ,r'^[> ]*从.+身上.+[◎☆★].+', "pack gem", group = "sys"),
|
28
|
-
"ali_yz_xm" : SimpleAlias(self.session ,'^yz_xm$', "w;#wa 100;w;#wa 100;w;#wa 100;w", group = "sys")
|
29
|
-
}
|
30
|
-
|
31
|
-
# 将自定义的状态窗口函数赋值给会话的status_maker属性,这样会话就会使用该函数来显示状态信息。
|
32
|
-
self.session.status_maker = self.status_window
|
33
|
-
|
34
|
-
|
35
|
-
# 如果仅使用了装饰器定义的PyMUD对象(Alias,Trigger等),则无需实现__unload__方法。
|
36
|
-
# 但如果自定义了PyMUD对象,那么必须实现__unload__方法,否则会导致加载的对象无法被正常卸载。
|
37
|
-
# 如果实现了__unload__方法,那么在该方法中必须调用super().__unload__(),否则会导致@alias等函数装饰器生成的对象不能被正常卸载
|
38
|
-
def __unload__(self):
|
39
|
-
# 在__unload__方法中定义卸载时需要从会话中清除的对象。
|
40
|
-
# 目前加载卸载可以支持字典、列表、单个对象均可。
|
41
|
-
self.session.delObjects(self._objs)
|
42
|
-
|
43
|
-
# 不要遗漏 super().__unload__(),否则会导致@alias等函数装饰器生成的对象不能被正常卸载
|
44
|
-
super().__unload__()
|
45
|
-
|
46
|
-
# 别名, gp gold = get gold from corpse
|
47
|
-
@alias(r"^gp\s(.+)$", id = "ali_get", group = "sys")
|
48
|
-
def getfromcorpse(self, id, line, wildcards):
|
49
|
-
cmd = f"get {wildcards[0]} from corpse"
|
50
|
-
self.session.writeline(cmd)
|
51
|
-
|
52
|
-
# 定时器,每5秒打印一次信息
|
53
|
-
@timer(5)
|
54
|
-
def onTimer(self, id, *args, **kwargs):
|
55
|
-
self.session.info("每5秒都会打印本信息", "定时器测试")
|
56
|
-
|
57
|
-
# 导航触发器示例
|
58
|
-
@trigger('^http://fullme.pkuxkx.net/robot.php.+$', group = "sys")
|
59
|
-
def ontri_webpage(self, id, line, wildcards):
|
60
|
-
webbrowser.open(line)
|
61
|
-
|
62
|
-
# 若多个对象共用同一个处理函数,也可以同时使用多个装饰器实现
|
63
|
-
@trigger(r"^\s+你可以获取(.+)")
|
64
|
-
@trigger(r"^\s+这里位于(.+)和(.+)的.+")
|
65
|
-
def ontri_multideco(self, id, line, wildcards):
|
66
|
-
self.session.info("触发器触发,ID: {0}, 内容: {1}, 匹配项: {2}".format(id, line, wildcards), "测试")
|
67
|
-
|
68
|
-
# 多行触发器示例
|
69
|
-
@trigger([r'^[> ]*#(\d+.?\d*[KM]?),(\d+),(\d+),(\d+),(\d+),(\d+)$', r'^[> ]*#(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)$', r'^[> ]*#(\d+),(\d+),(-?\d+),(-?\d+),(\d+),(\d+)$'], group = "sys")
|
70
|
-
def ontri_hpbrief_3lines(self, id, line, wildcards):
|
71
|
-
# 注意注意,此处捕获的额内容在wildcards里都是str类型,直接用下面这种方式赋值的时候,保存的变量也是str类型,因此这种在status_window直接调用并用于计算时,需要另行处理
|
72
|
-
self.session.setVariables([
|
73
|
-
"combat_exp", "potential", "max_neili", "neili", "max_jingli", "jingli",
|
74
|
-
"max_qi", "eff_qi", "qi", "max_jing", "eff_jing", "jing",
|
75
|
-
"vigour/qi", "vigour/yuan", "food", "water", "fighting", "busy"
|
76
|
-
]
|
77
|
-
, wildcards)
|
78
|
-
# 因为GMCP.Status传递来的是busy和fighting,与hpbrief逻辑相反,因此重新处理下,保证hpbrief和GMCP.Status一致
|
79
|
-
is_busy = not wildcards[-1]
|
80
|
-
is_fighting = not wildcards[-2]
|
81
|
-
self.session.setVariables(['is_busy', 'is_fighting'], [is_busy, is_fighting])
|
82
|
-
|
83
|
-
# gmcp定义式,name的大小写必须与GMCP的大小写一致,否则无法触发
|
84
|
-
@gmcp("GMCP.Status")
|
85
|
-
def ongmcp_status(self, id, line, wildcards):
|
86
|
-
# GMCP.Status in pkuxkx
|
87
|
-
# 自己的Status和敌人的Status均会使用GMCP.Status发送
|
88
|
-
# 区别在于,敌人的Status会带有id属性。但登录首次自己也会发送id属性,但同时有很多属性,因此增加一个实战经验属性判定
|
89
|
-
if isinstance(wildcards, dict): # 正常情况下,GMCP.Status应该是一个dict
|
90
|
-
if ("id" in wildcards.keys()) and (not "combat_exp" in wildcards.keys()):
|
91
|
-
# 说明是敌人的,暂时忽略
|
92
|
-
#self.session.info(f"GMCP.Status 收到非自己信息: {wildcards}")
|
93
|
-
pass
|
94
|
-
|
95
|
-
else:
|
96
|
-
# GMCP.status收到的wildcards是一个json格式转换过来的字典信息,可以直接用于变量赋值
|
97
|
-
# 但json过来的true/false时全小写字符串,此处转换为bool类型使用
|
98
|
-
#self.session.info(f"GMCP.Status 收到个人信息: {wildcards}")
|
99
|
-
for key, value in wildcards.items():
|
100
|
-
if value == "false": value = False
|
101
|
-
elif value == "true": value = True
|
102
|
-
self.session.setVariable(key, value)
|
103
|
-
|
104
|
-
# 如果这些变量显示在状态窗口中,可以调用下面代码强制刷新状态窗口
|
105
|
-
self.session.application.invalidate()
|
106
|
-
|
107
|
-
# 创建自定义的健康条用作分隔符
|
108
|
-
def create_status_bar(self, current, effective, maximum, barlength = 20, barstyle = "—"):
|
109
|
-
from wcwidth import wcswidth
|
110
|
-
barline = list()
|
111
|
-
stylewidth = wcswidth(barstyle)
|
112
|
-
filled_length = int(round(barlength * current / maximum / stylewidth))
|
113
|
-
# 计算有效健康值部分的长度
|
114
|
-
effective_length = int(round(barlength * effective / maximum / stylewidth))
|
115
|
-
|
116
|
-
# 计算剩余部分长度
|
117
|
-
remaining_length = barlength - effective_length
|
118
|
-
|
119
|
-
# 构造健康条
|
120
|
-
barline.append(("fg:lightcyan", barstyle * filled_length))
|
121
|
-
barline.append(("fg:yellow", barstyle * (effective_length - filled_length)))
|
122
|
-
barline.append(("fg:red", barstyle * remaining_length))
|
123
|
-
|
124
|
-
return barline
|
125
|
-
|
126
|
-
# 自定义状态栏窗口
|
127
|
-
def status_window(self):
|
128
|
-
from pymud.settings import Settings
|
129
|
-
try:
|
130
|
-
formatted_list = list()
|
131
|
-
|
132
|
-
# line 0. hp bar
|
133
|
-
jing = self.session.getVariable("jing", 0)
|
134
|
-
effjing = self.session.getVariable("eff_jing", 0)
|
135
|
-
maxjing = self.session.getVariable("max_jing", 0)
|
136
|
-
jingli = self.session.getVariable("jingli", 0)
|
137
|
-
maxjingli = self.session.getVariable("max_jingli", 0)
|
138
|
-
qi = self.session.getVariable("qi", 0)
|
139
|
-
effqi = self.session.getVariable("eff_qi", 0)
|
140
|
-
maxqi = self.session.getVariable("max_qi", 0)
|
141
|
-
neili = self.session.getVariable("neili", 0)
|
142
|
-
maxneili = self.session.getVariable("max_neili", 0)
|
143
|
-
|
144
|
-
barstyle = "━"
|
145
|
-
screenwidth = self.session.application.get_width()
|
146
|
-
barlength = screenwidth // 2 - 1
|
147
|
-
span = screenwidth - 2 * barlength
|
148
|
-
qi_bar = self.create_status_bar(qi, effqi, maxqi, barlength, barstyle)
|
149
|
-
jing_bar = self.create_status_bar(jing, effjing, maxjing, barlength, barstyle)
|
150
|
-
|
151
|
-
formatted_list.extend(qi_bar)
|
152
|
-
formatted_list.append(("", " " * span))
|
153
|
-
formatted_list.extend(jing_bar)
|
154
|
-
formatted_list.append(("", "\n"))
|
155
|
-
|
156
|
-
# line 1. char, menpai, deposit, food, water, exp, pot
|
157
|
-
formatted_list.append((Settings.styles["title"], "【角色】"))
|
158
|
-
formatted_list.append((Settings.styles["value"], "{0}({1})".format(self.session.getVariable('name'), self.session.getVariable('id'))))
|
159
|
-
formatted_list.append(("", " "))
|
160
|
-
|
161
|
-
formatted_list.append((Settings.styles["title"], "【食物】"))
|
162
|
-
|
163
|
-
food = int(self.session.getVariable('food', '0'))
|
164
|
-
max_food = self.session.getVariable('max_food', 350)
|
165
|
-
if food < 100:
|
166
|
-
style = Settings.styles["value.worst"]
|
167
|
-
elif food < 200:
|
168
|
-
style = Settings.styles["value.worse"]
|
169
|
-
elif food < max_food:
|
170
|
-
style = Settings.styles["value"]
|
171
|
-
else:
|
172
|
-
style = Settings.styles["value.better"]
|
173
|
-
|
174
|
-
formatted_list.append((style, "{}".format(food)))
|
175
|
-
formatted_list.append(("", " "))
|
176
|
-
|
177
|
-
formatted_list.append((Settings.styles["title"], "【饮水】"))
|
178
|
-
water = int(self.session.getVariable('water', '0'))
|
179
|
-
max_water = self.session.getVariable('max_water', 350)
|
180
|
-
if water < 100:
|
181
|
-
style = Settings.styles["value.worst"]
|
182
|
-
elif water < 200:
|
183
|
-
style = Settings.styles["value.worse"]
|
184
|
-
elif water < max_water:
|
185
|
-
style = Settings.styles["value"]
|
186
|
-
else:
|
187
|
-
style = Settings.styles["value.better"]
|
188
|
-
formatted_list.append((style, "{}".format(water)))
|
189
|
-
formatted_list.append(("", " "))
|
190
|
-
formatted_list.append((Settings.styles["title"], "【经验】"))
|
191
|
-
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('combat_exp'))))
|
192
|
-
formatted_list.append(("", " "))
|
193
|
-
formatted_list.append((Settings.styles["title"], "【潜能】"))
|
194
|
-
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('potential'))))
|
195
|
-
formatted_list.append(("", " "))
|
196
|
-
|
197
|
-
formatted_list.append((Settings.styles["title"], "【门派】"))
|
198
|
-
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('family/family_name'))))
|
199
|
-
formatted_list.append(("", " "))
|
200
|
-
formatted_list.append((Settings.styles["title"], "【存款】"))
|
201
|
-
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('deposit'))))
|
202
|
-
formatted_list.append(("", " "))
|
203
|
-
|
204
|
-
# line 2. hp
|
205
|
-
# a new-line
|
206
|
-
formatted_list.append(("", "\n"))
|
207
|
-
|
208
|
-
formatted_list.append((Settings.styles["title"], "【精神】"))
|
209
|
-
if int(effjing) < int(maxjing):
|
210
|
-
style = Settings.styles["value.worst"]
|
211
|
-
elif int(jing) < 0.8 * int(effjing):
|
212
|
-
style = Settings.styles["value.worse"]
|
213
|
-
else:
|
214
|
-
style = Settings.styles["value"]
|
215
|
-
|
216
|
-
if maxjing == 0:
|
217
|
-
pct1 = pct2 = 0
|
218
|
-
else:
|
219
|
-
pct1 = 100.0*float(jing)/float(maxjing)
|
220
|
-
pct2 = 100.0*float(effjing)/float(maxjing)
|
221
|
-
formatted_list.append((style, "{0}[{1:3.0f}%] / {2}[{3:3.0f}%]".format(jing, pct1, effjing, pct2)))
|
222
|
-
|
223
|
-
formatted_list.append(("", " "))
|
224
|
-
|
225
|
-
formatted_list.append((Settings.styles["title"], "【气血】"))
|
226
|
-
if int(effqi) < int(maxqi):
|
227
|
-
style = Settings.styles["value.worst"]
|
228
|
-
elif int(qi) < 0.8 * int(effqi):
|
229
|
-
style = Settings.styles["value.worse"]
|
230
|
-
else:
|
231
|
-
style = Settings.styles["value"]
|
232
|
-
|
233
|
-
if maxqi == 0:
|
234
|
-
pct1 = pct2 = 0
|
235
|
-
else:
|
236
|
-
pct1 = 100.0*float(qi)/float(maxqi)
|
237
|
-
pct2 = 100.0*float(effqi)/float(maxqi)
|
238
|
-
formatted_list.append((style, "{0}[{1:3.0f}%] / {2}[{3:3.0f}%]".format(qi, pct1, effqi, pct2)))
|
239
|
-
formatted_list.append(("", " "))
|
240
|
-
|
241
|
-
# 内力
|
242
|
-
formatted_list.append((Settings.styles["title"], "【内力】"))
|
243
|
-
if int(neili) < 0.6 * int(maxneili):
|
244
|
-
style = Settings.styles["value.worst"]
|
245
|
-
elif int(neili) < 0.8 * int(maxneili):
|
246
|
-
style = Settings.styles["value.worse"]
|
247
|
-
elif int(neili) < 1.2 * int(maxneili):
|
248
|
-
style = Settings.styles["value"]
|
249
|
-
else:
|
250
|
-
style = Settings.styles["value.better"]
|
251
|
-
|
252
|
-
if maxneili == 0:
|
253
|
-
pct = 0
|
254
|
-
else:
|
255
|
-
pct = 100.0*float(neili)/float(maxneili)
|
256
|
-
formatted_list.append((style, "{0} / {1}[{2:3.0f}%]".format(neili, maxneili, pct)))
|
257
|
-
formatted_list.append(("", " "))
|
258
|
-
|
259
|
-
# 精力
|
260
|
-
formatted_list.append((Settings.styles["title"], "【精力】"))
|
261
|
-
if int(jingli) < 0.6 * int(maxjingli):
|
262
|
-
style = Settings.styles["value.worst"]
|
263
|
-
elif int(jingli) < 0.8 * int(maxjingli):
|
264
|
-
style = Settings.styles["value.worse"]
|
265
|
-
elif int(jingli) < 1.2 * int(maxjingli):
|
266
|
-
style = Settings.styles["value"]
|
267
|
-
else:
|
268
|
-
style = Settings.styles["value.better"]
|
269
|
-
|
270
|
-
if maxjingli == 0:
|
271
|
-
pct = 0
|
272
|
-
else:
|
273
|
-
pct = 100.0*float(jingli)/float(maxjingli)
|
274
|
-
|
275
|
-
formatted_list.append((style, "{0} / {1}[{2:3.0f}%]".format(jingli, maxjingli, pct)))
|
276
|
-
formatted_list.append(("", " "))
|
277
|
-
|
278
|
-
return formatted_list
|
279
|
-
|
280
|
-
except Exception as e:
|
1
|
+
# 示例脚本:如何在PyMud中玩PKUXKX
|
2
|
+
|
3
|
+
import webbrowser
|
4
|
+
from pymud import Session, IConfig, alias, trigger, timer, gmcp, Alias, Trigger, Timer, SimpleTrigger, SimpleAlias
|
5
|
+
|
6
|
+
# 在PyMud中,使用#load {filename}可以加载对应的配置作为脚本文件以提供支撑。支持多脚本加载
|
7
|
+
# 本示例脚本对PyMud支持的变量(Variable)、触发器(Trigger,包含单行与多行触发)、别名(Alias)、定时器(Timer)进行了代码示例
|
8
|
+
# 使用#load {filename}加载的配置文件中,若有一个类型继承自IConfig,则在#load操作时,会自动创建此类型;若没有继承自IConfig的类,则仅将文件引入
|
9
|
+
# 例如,加载本文件指定的配置,则使用 #load pymud.pkuxkx即可
|
10
|
+
|
11
|
+
# 定义一个自定义配置类,并继承自IConfig。
|
12
|
+
# 目前不在推荐使用Configuration类,而是使用IConfig接口。因为只有使用IConfig接口,才能在类型函数中自动管理由装饰器创建的对象
|
13
|
+
class MyConfig(IConfig):
|
14
|
+
# 类的构造函数,传递参数session,是会话本身。另外请保留*args和**kwargs,以便后续扩展
|
15
|
+
def __init__(self, session: Session, *args, **kwargs) -> None:
|
16
|
+
# 建议将 super().__init__()放在类型init的首句代码,该代码用于对装饰器@alias等函数所装饰的对象进行管理
|
17
|
+
# 调用super().__init__()时,会自动将session传递给父类,以便后续使用。
|
18
|
+
# 因此此处无需再使用self.session = session来保存传递的会话类型
|
19
|
+
#
|
20
|
+
super().__init__(session, *args, **kwargs)
|
21
|
+
|
22
|
+
# 所有自行构建的对象, 建议统一放到self._objs中,方便管理和卸载。
|
23
|
+
# 目前加载卸载可以支持字典、列表、单个对象均可。此处使用字典,是为了方便后续处理其中某个单个对象。
|
24
|
+
# 对象创建时将自动增加到会话中,不需要手动调用session.addObject操作了
|
25
|
+
self._objs = {
|
26
|
+
# 别名,触发器可以通过创建一个对应类型的实例来生成
|
27
|
+
"tri_gem" : SimpleTrigger(self.session ,r'^[> ]*从.+身上.+[◎☆★].+', "pack gem", group = "sys"),
|
28
|
+
"ali_yz_xm" : SimpleAlias(self.session ,'^yz_xm$', "w;#wa 100;w;#wa 100;w;#wa 100;w", group = "sys")
|
29
|
+
}
|
30
|
+
|
31
|
+
# 将自定义的状态窗口函数赋值给会话的status_maker属性,这样会话就会使用该函数来显示状态信息。
|
32
|
+
self.session.status_maker = self.status_window
|
33
|
+
|
34
|
+
|
35
|
+
# 如果仅使用了装饰器定义的PyMUD对象(Alias,Trigger等),则无需实现__unload__方法。
|
36
|
+
# 但如果自定义了PyMUD对象,那么必须实现__unload__方法,否则会导致加载的对象无法被正常卸载。
|
37
|
+
# 如果实现了__unload__方法,那么在该方法中必须调用super().__unload__(),否则会导致@alias等函数装饰器生成的对象不能被正常卸载
|
38
|
+
def __unload__(self):
|
39
|
+
# 在__unload__方法中定义卸载时需要从会话中清除的对象。
|
40
|
+
# 目前加载卸载可以支持字典、列表、单个对象均可。
|
41
|
+
self.session.delObjects(self._objs)
|
42
|
+
|
43
|
+
# 不要遗漏 super().__unload__(),否则会导致@alias等函数装饰器生成的对象不能被正常卸载
|
44
|
+
super().__unload__()
|
45
|
+
|
46
|
+
# 别名, gp gold = get gold from corpse
|
47
|
+
@alias(r"^gp\s(.+)$", id = "ali_get", group = "sys")
|
48
|
+
def getfromcorpse(self, id, line, wildcards):
|
49
|
+
cmd = f"get {wildcards[0]} from corpse"
|
50
|
+
self.session.writeline(cmd)
|
51
|
+
|
52
|
+
# 定时器,每5秒打印一次信息
|
53
|
+
@timer(5)
|
54
|
+
def onTimer(self, id, *args, **kwargs):
|
55
|
+
self.session.info("每5秒都会打印本信息", "定时器测试")
|
56
|
+
|
57
|
+
# 导航触发器示例
|
58
|
+
@trigger('^http://fullme.pkuxkx.net/robot.php.+$', group = "sys")
|
59
|
+
def ontri_webpage(self, id, line, wildcards):
|
60
|
+
webbrowser.open(line)
|
61
|
+
|
62
|
+
# 若多个对象共用同一个处理函数,也可以同时使用多个装饰器实现
|
63
|
+
@trigger(r"^\s+你可以获取(.+)")
|
64
|
+
@trigger(r"^\s+这里位于(.+)和(.+)的.+")
|
65
|
+
def ontri_multideco(self, id, line, wildcards):
|
66
|
+
self.session.info("触发器触发,ID: {0}, 内容: {1}, 匹配项: {2}".format(id, line, wildcards), "测试")
|
67
|
+
|
68
|
+
# 多行触发器示例
|
69
|
+
@trigger([r'^[> ]*#(\d+.?\d*[KM]?),(\d+),(\d+),(\d+),(\d+),(\d+)$', r'^[> ]*#(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)$', r'^[> ]*#(\d+),(\d+),(-?\d+),(-?\d+),(\d+),(\d+)$'], group = "sys")
|
70
|
+
def ontri_hpbrief_3lines(self, id, line, wildcards):
|
71
|
+
# 注意注意,此处捕获的额内容在wildcards里都是str类型,直接用下面这种方式赋值的时候,保存的变量也是str类型,因此这种在status_window直接调用并用于计算时,需要另行处理
|
72
|
+
self.session.setVariables([
|
73
|
+
"combat_exp", "potential", "max_neili", "neili", "max_jingli", "jingli",
|
74
|
+
"max_qi", "eff_qi", "qi", "max_jing", "eff_jing", "jing",
|
75
|
+
"vigour/qi", "vigour/yuan", "food", "water", "fighting", "busy"
|
76
|
+
]
|
77
|
+
, wildcards)
|
78
|
+
# 因为GMCP.Status传递来的是busy和fighting,与hpbrief逻辑相反,因此重新处理下,保证hpbrief和GMCP.Status一致
|
79
|
+
is_busy = not wildcards[-1]
|
80
|
+
is_fighting = not wildcards[-2]
|
81
|
+
self.session.setVariables(['is_busy', 'is_fighting'], [is_busy, is_fighting])
|
82
|
+
|
83
|
+
# gmcp定义式,name的大小写必须与GMCP的大小写一致,否则无法触发
|
84
|
+
@gmcp("GMCP.Status")
|
85
|
+
def ongmcp_status(self, id, line, wildcards):
|
86
|
+
# GMCP.Status in pkuxkx
|
87
|
+
# 自己的Status和敌人的Status均会使用GMCP.Status发送
|
88
|
+
# 区别在于,敌人的Status会带有id属性。但登录首次自己也会发送id属性,但同时有很多属性,因此增加一个实战经验属性判定
|
89
|
+
if isinstance(wildcards, dict): # 正常情况下,GMCP.Status应该是一个dict
|
90
|
+
if ("id" in wildcards.keys()) and (not "combat_exp" in wildcards.keys()):
|
91
|
+
# 说明是敌人的,暂时忽略
|
92
|
+
#self.session.info(f"GMCP.Status 收到非自己信息: {wildcards}")
|
93
|
+
pass
|
94
|
+
|
95
|
+
else:
|
96
|
+
# GMCP.status收到的wildcards是一个json格式转换过来的字典信息,可以直接用于变量赋值
|
97
|
+
# 但json过来的true/false时全小写字符串,此处转换为bool类型使用
|
98
|
+
#self.session.info(f"GMCP.Status 收到个人信息: {wildcards}")
|
99
|
+
for key, value in wildcards.items():
|
100
|
+
if value == "false": value = False
|
101
|
+
elif value == "true": value = True
|
102
|
+
self.session.setVariable(key, value)
|
103
|
+
|
104
|
+
# 如果这些变量显示在状态窗口中,可以调用下面代码强制刷新状态窗口
|
105
|
+
self.session.application.invalidate()
|
106
|
+
|
107
|
+
# 创建自定义的健康条用作分隔符
|
108
|
+
def create_status_bar(self, current, effective, maximum, barlength = 20, barstyle = "—"):
|
109
|
+
from wcwidth import wcswidth
|
110
|
+
barline = list()
|
111
|
+
stylewidth = wcswidth(barstyle)
|
112
|
+
filled_length = int(round(barlength * current / maximum / stylewidth))
|
113
|
+
# 计算有效健康值部分的长度
|
114
|
+
effective_length = int(round(barlength * effective / maximum / stylewidth))
|
115
|
+
|
116
|
+
# 计算剩余部分长度
|
117
|
+
remaining_length = barlength - effective_length
|
118
|
+
|
119
|
+
# 构造健康条
|
120
|
+
barline.append(("fg:lightcyan", barstyle * filled_length))
|
121
|
+
barline.append(("fg:yellow", barstyle * (effective_length - filled_length)))
|
122
|
+
barline.append(("fg:red", barstyle * remaining_length))
|
123
|
+
|
124
|
+
return barline
|
125
|
+
|
126
|
+
# 自定义状态栏窗口
|
127
|
+
def status_window(self):
|
128
|
+
from pymud.settings import Settings
|
129
|
+
try:
|
130
|
+
formatted_list = list()
|
131
|
+
|
132
|
+
# line 0. hp bar
|
133
|
+
jing = self.session.getVariable("jing", 0)
|
134
|
+
effjing = self.session.getVariable("eff_jing", 0)
|
135
|
+
maxjing = self.session.getVariable("max_jing", 0)
|
136
|
+
jingli = self.session.getVariable("jingli", 0)
|
137
|
+
maxjingli = self.session.getVariable("max_jingli", 0)
|
138
|
+
qi = self.session.getVariable("qi", 0)
|
139
|
+
effqi = self.session.getVariable("eff_qi", 0)
|
140
|
+
maxqi = self.session.getVariable("max_qi", 0)
|
141
|
+
neili = self.session.getVariable("neili", 0)
|
142
|
+
maxneili = self.session.getVariable("max_neili", 0)
|
143
|
+
|
144
|
+
barstyle = "━"
|
145
|
+
screenwidth = self.session.application.get_width()
|
146
|
+
barlength = screenwidth // 2 - 1
|
147
|
+
span = screenwidth - 2 * barlength
|
148
|
+
qi_bar = self.create_status_bar(qi, effqi, maxqi, barlength, barstyle)
|
149
|
+
jing_bar = self.create_status_bar(jing, effjing, maxjing, barlength, barstyle)
|
150
|
+
|
151
|
+
formatted_list.extend(qi_bar)
|
152
|
+
formatted_list.append(("", " " * span))
|
153
|
+
formatted_list.extend(jing_bar)
|
154
|
+
formatted_list.append(("", "\n"))
|
155
|
+
|
156
|
+
# line 1. char, menpai, deposit, food, water, exp, pot
|
157
|
+
formatted_list.append((Settings.styles["title"], "【角色】"))
|
158
|
+
formatted_list.append((Settings.styles["value"], "{0}({1})".format(self.session.getVariable('name'), self.session.getVariable('id'))))
|
159
|
+
formatted_list.append(("", " "))
|
160
|
+
|
161
|
+
formatted_list.append((Settings.styles["title"], "【食物】"))
|
162
|
+
|
163
|
+
food = int(self.session.getVariable('food', '0'))
|
164
|
+
max_food = self.session.getVariable('max_food', 350)
|
165
|
+
if food < 100:
|
166
|
+
style = Settings.styles["value.worst"]
|
167
|
+
elif food < 200:
|
168
|
+
style = Settings.styles["value.worse"]
|
169
|
+
elif food < max_food:
|
170
|
+
style = Settings.styles["value"]
|
171
|
+
else:
|
172
|
+
style = Settings.styles["value.better"]
|
173
|
+
|
174
|
+
formatted_list.append((style, "{}".format(food)))
|
175
|
+
formatted_list.append(("", " "))
|
176
|
+
|
177
|
+
formatted_list.append((Settings.styles["title"], "【饮水】"))
|
178
|
+
water = int(self.session.getVariable('water', '0'))
|
179
|
+
max_water = self.session.getVariable('max_water', 350)
|
180
|
+
if water < 100:
|
181
|
+
style = Settings.styles["value.worst"]
|
182
|
+
elif water < 200:
|
183
|
+
style = Settings.styles["value.worse"]
|
184
|
+
elif water < max_water:
|
185
|
+
style = Settings.styles["value"]
|
186
|
+
else:
|
187
|
+
style = Settings.styles["value.better"]
|
188
|
+
formatted_list.append((style, "{}".format(water)))
|
189
|
+
formatted_list.append(("", " "))
|
190
|
+
formatted_list.append((Settings.styles["title"], "【经验】"))
|
191
|
+
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('combat_exp'))))
|
192
|
+
formatted_list.append(("", " "))
|
193
|
+
formatted_list.append((Settings.styles["title"], "【潜能】"))
|
194
|
+
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('potential'))))
|
195
|
+
formatted_list.append(("", " "))
|
196
|
+
|
197
|
+
formatted_list.append((Settings.styles["title"], "【门派】"))
|
198
|
+
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('family/family_name'))))
|
199
|
+
formatted_list.append(("", " "))
|
200
|
+
formatted_list.append((Settings.styles["title"], "【存款】"))
|
201
|
+
formatted_list.append((Settings.styles["value"], "{}".format(self.session.getVariable('deposit'))))
|
202
|
+
formatted_list.append(("", " "))
|
203
|
+
|
204
|
+
# line 2. hp
|
205
|
+
# a new-line
|
206
|
+
formatted_list.append(("", "\n"))
|
207
|
+
|
208
|
+
formatted_list.append((Settings.styles["title"], "【精神】"))
|
209
|
+
if int(effjing) < int(maxjing):
|
210
|
+
style = Settings.styles["value.worst"]
|
211
|
+
elif int(jing) < 0.8 * int(effjing):
|
212
|
+
style = Settings.styles["value.worse"]
|
213
|
+
else:
|
214
|
+
style = Settings.styles["value"]
|
215
|
+
|
216
|
+
if maxjing == 0:
|
217
|
+
pct1 = pct2 = 0
|
218
|
+
else:
|
219
|
+
pct1 = 100.0*float(jing)/float(maxjing)
|
220
|
+
pct2 = 100.0*float(effjing)/float(maxjing)
|
221
|
+
formatted_list.append((style, "{0}[{1:3.0f}%] / {2}[{3:3.0f}%]".format(jing, pct1, effjing, pct2)))
|
222
|
+
|
223
|
+
formatted_list.append(("", " "))
|
224
|
+
|
225
|
+
formatted_list.append((Settings.styles["title"], "【气血】"))
|
226
|
+
if int(effqi) < int(maxqi):
|
227
|
+
style = Settings.styles["value.worst"]
|
228
|
+
elif int(qi) < 0.8 * int(effqi):
|
229
|
+
style = Settings.styles["value.worse"]
|
230
|
+
else:
|
231
|
+
style = Settings.styles["value"]
|
232
|
+
|
233
|
+
if maxqi == 0:
|
234
|
+
pct1 = pct2 = 0
|
235
|
+
else:
|
236
|
+
pct1 = 100.0*float(qi)/float(maxqi)
|
237
|
+
pct2 = 100.0*float(effqi)/float(maxqi)
|
238
|
+
formatted_list.append((style, "{0}[{1:3.0f}%] / {2}[{3:3.0f}%]".format(qi, pct1, effqi, pct2)))
|
239
|
+
formatted_list.append(("", " "))
|
240
|
+
|
241
|
+
# 内力
|
242
|
+
formatted_list.append((Settings.styles["title"], "【内力】"))
|
243
|
+
if int(neili) < 0.6 * int(maxneili):
|
244
|
+
style = Settings.styles["value.worst"]
|
245
|
+
elif int(neili) < 0.8 * int(maxneili):
|
246
|
+
style = Settings.styles["value.worse"]
|
247
|
+
elif int(neili) < 1.2 * int(maxneili):
|
248
|
+
style = Settings.styles["value"]
|
249
|
+
else:
|
250
|
+
style = Settings.styles["value.better"]
|
251
|
+
|
252
|
+
if maxneili == 0:
|
253
|
+
pct = 0
|
254
|
+
else:
|
255
|
+
pct = 100.0*float(neili)/float(maxneili)
|
256
|
+
formatted_list.append((style, "{0} / {1}[{2:3.0f}%]".format(neili, maxneili, pct)))
|
257
|
+
formatted_list.append(("", " "))
|
258
|
+
|
259
|
+
# 精力
|
260
|
+
formatted_list.append((Settings.styles["title"], "【精力】"))
|
261
|
+
if int(jingli) < 0.6 * int(maxjingli):
|
262
|
+
style = Settings.styles["value.worst"]
|
263
|
+
elif int(jingli) < 0.8 * int(maxjingli):
|
264
|
+
style = Settings.styles["value.worse"]
|
265
|
+
elif int(jingli) < 1.2 * int(maxjingli):
|
266
|
+
style = Settings.styles["value"]
|
267
|
+
else:
|
268
|
+
style = Settings.styles["value.better"]
|
269
|
+
|
270
|
+
if maxjingli == 0:
|
271
|
+
pct = 0
|
272
|
+
else:
|
273
|
+
pct = 100.0*float(jingli)/float(maxjingli)
|
274
|
+
|
275
|
+
formatted_list.append((style, "{0} / {1}[{2:3.0f}%]".format(jingli, maxjingli, pct)))
|
276
|
+
formatted_list.append(("", " "))
|
277
|
+
|
278
|
+
return formatted_list
|
279
|
+
|
280
|
+
except Exception as e:
|
281
281
|
return f"{e}"
|