-
Notifications
You must be signed in to change notification settings - Fork 15
/
BatMUD_Analyzer.xml
261 lines (220 loc) · 7.44 KB
/
BatMUD_Analyzer.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="BatMUD_Analyzer"
author="Nick Gammon"
id="cff91f04c0d78149c0dd6258"
language="Lua"
purpose="Detects BatMUD sequences"
date_written="2016-11-21 08:20"
date_modified="2016-11-22 09:30"
requires="4.80"
version="1.1"
>
<description trim="y">
Detects incoming packets in the BatMUD format.
</description>
</plugin>
<!-- Script -->
<script>
<![CDATA[
local ESC = "\027"
local REGEXP = ESC .. "<(%d%d)(.-)" .. ESC .. ">%1" -- ESC < nn (args) ESC > nn
local ARG_DELIMITER = ESC .. "|"
-- breaks up a line into AAAAA ESC| BBBBB
function splitArgs (args)
local a, b = string.match (args, "^(.*)" .. ARG_DELIMITER .. "(.*)$")
return a, b
end -- splitArgs
knownWindows = { }
function showInfoWindow (name, contents, left, top, fgColour, bgColour)
local win = GetPluginID () .. "_" .. name
local font = "f"
WindowCreate (win, left, top, 1, 1, miniwin.pos_top_left, 0, 0)
WindowFont (win, font, "Courier", 10, true)
height = WindowFontInfo (win, font, 1) + 10
width = WindowTextWidth (win, font, contents) + 10
WindowCreate (win, left, top, width, height, miniwin.pos_top_left, miniwin.create_absolute_location, ColourNameToRGB (bgColour))
WindowText (win, font, contents, 5, 5, 0, 0, ColourNameToRGB (fgColour))
WindowShow (win, true)
knownWindows [win] = true -- remember it exists
end -- showInfoWindow
function ResetOutput (args)
end -- ResetOutput
function ConnectedOK (args)
ColourNote ("green", "", "Connected to BatMUD OK")
end -- ConnectedOK
function ConnectionFailed (args)
ColourNote ("red", "", "Failed to connect: " .. args)
end -- ConnectionFailed
function OutputMessage (args)
local msgType, message = splitArgs (args)
if msgType == 'spec_prompt' then
showInfoWindow ("prompt",
message,
0, 50, "saddlebrown", "papayawhip")
else
msgs = utils.split (message, "\n")
ColourTell ("dodgerblue", "", msgType .. ": ")
for k, v in ipairs (msgs) do
AnsiNote (v)
end -- for each line
end -- if
end -- OutputMessage
function ClearScreen (args)
end -- ClearScreen
function ForegroundColour (args)
local colour, message = splitArgs (args)
ColourTell ("#" .. colour, "", message)
end -- ForegroundColour
function InGameLink (args)
local command, where = splitArgs (args)
ColourNote ("tomato", "", "Typing " .. command .. " gives " .. where)
end -- InGameLink
function ClearSpellStatus (args)
ColourNote ("yellow", "", "Spell/skill status cleared")
end -- ClearSpellStatus
function SpellStatus (args)
local spell, rounds = string.match (args, "^(%S+)%s+(%d+)$")
if not spell then
ColourNote ("white", "red", "Cannot interpret SpellStatus line: " .. args)
return
end -- if not recognized
rounds = tonumber (rounds)
if rounds == 0 then
rounds = "unknown"
end -- if
ColourNote ("yellow", "", "Spell: " .. spell .. " for " .. rounds .. " round(s)")
end -- ClearSpellStatus
function SkillStatus (args)
local skill, rounds = string.match (args, "^(%S+)%s+(%d+)$")
if not skill then
ColourNote ("white", "red", "Cannot interpret SkillStatus line: " .. args)
return
end -- if not recognized
rounds = tonumber (rounds)
if rounds == 0 then
rounds = "unknown"
end -- if
ColourNote ("yellow", "", "Skill: " .. skill .. " for " .. rounds .. " round(s)")
end -- SkillStatus
function PlayerHealth (args)
local hp, hpmax, sp, spmax, ep, epmax = string.match (args, "^(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)$")
if not hp then
ColourNote ("white", "red", "Cannot interpret PlayerHealth line: " .. args)
return
end -- if not recognized
showInfoWindow ("health",
string.format ("HP: %d, MaxHP: %d, SP: %d, MaxSP: %d, EP: %d, MaxEP: %d",
hp, hpmax, sp, spmax, ep, epmax),
0, 0, "blue", "bisque")
end -- PlayerHealth
function PlayerName (args)
local name, surname, race, level, gender, experience = string.match (args, "^([%a%d]+)%s+([%a%d]+)%s+([%a%d]+)%s+(%d+)%s+(%d+)%s+(%d+)$")
if not name then
ColourNote ("white", "red", "Cannot interpret PlayerName line: " .. args)
return
end -- if not recognized
if surname == '0' then
surname = "<none>"
end -- if
if gender == '0' then
gender = "Neutral"
elseif gender == '1' then
gender = "Male"
elseif gender == '2' then
gender = "Female"
end -- if gender
showInfoWindow ("name",
string.format ("Name: %s, Surname: %s, Race: %s, Level: %d, Gender: %s, Experience: %d",
name, surname, race, level, gender, experience),
0, 25, "darkorange", "papayawhip")
end -- PlayerName
function PlayerStatus (args)
unconscious, stunned, dead = string.match (args, "^(%d+)%s+(%d+)%s+(%d+)$")
if not unconscious then
ColourNote ("white", "red", "Cannot interpret PlayerStatus line: " .. args)
return
end -- if not recognized
if unconscious ~= '0' then
ColourNote ("yellow", "", "Unconscious")
end -- if
if stunned ~= '0' then
ColourNote ("yellow", "", "Stunned")
end -- if
if dead ~= '0' then
ColourNote ("yellow", "", "Dead")
end -- if
end -- PlayerStatus
function TargetInfo (args)
local target, health = string.match (args, "^(%S+)%s+(%d+)$")
if not target then
ColourNote ("white", "red", "Cannot interpret TargetInfo line: " .. args)
return
end -- if not recognized
health = tonumber (health)
if health == 0 and target == '0' then
ColourNote ("orange", "", "No targets")
else
ColourNote ("orange", "", "Target " .. target .. " has " .. health .. "% health")
end -- if
end -- TargetInfo
handlers = {
[0] = ResetOutput,
[5] = ConnectedOK,
[6] = ConnectionFailed,
[10] = OutputMessage,
[11] = ClearScreen,
[20] = ForegroundColour,
[31] = InGameLink,
[40] = ClearSpellStatus,
[41] = SpellStatus,
[42] = SkillStatus,
[50] = PlayerHealth,
[52] = PlayerName,
[54] = PlayerStatus,
[70] = TargetInfo,
} -- end of handlers
-- do something with the message from the MUD
function handleMessage (code, args)
--ColourNote ("yellow", "", "Got code " .. code .. ", args " .. args)
handler = handlers [code]
if handler then
handler (args)
else
ColourTell ("yellow", "", "Got code " .. code .. ", args " .. args)
end -- if
end -- handleMessage
function processSequence (code, args)
-- handle embedded sequence
args = string.gsub (args, REGEXP, processSequence) -- recursive call
-- put into a table for later processing
-- insert at position 1 because the embedded ones will be detected first
table.insert (incoming, 1, { code = tonumber (code), args = args } )
return "" -- omit from packet
end -- processSequence
-- strip BatMUD stuff out of packet, handle it separately
function OnPluginPacketReceived (s)
incoming = { }
s, count = string.gsub (s, REGEXP, processSequence)
if count > 0 then
for k, v in ipairs (incoming) do
handleMessage (v.code, v.args)
end -- for each one
end -- some codes found
return s -- return fixed packet
end -- function OnPluginPacketReceived
-- when connected, activate the client protocol
function OnPluginConnect ()
SendPkt("\027bc 3\n") -- enable BatClient stuff
end -- function
-- hide all miniwindows on disconnect
function OnPluginDisconnect ()
for k, v in pairs (knownWindows) do
WindowShow (k, false)
end -- for
end -- OnPluginDisconnect
]]>
</script>
</muclient>