-
Notifications
You must be signed in to change notification settings - Fork 15
/
Icon_Bar.xml
604 lines (464 loc) · 16.2 KB
/
Icon_Bar.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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE muclient [
<!ENTITY horizontal "y" >
<!ENTITY show_time "y" >
]>
<muclient>
<plugin
name="Icon_Bar"
author="Nick Gammon"
id="ede0920fc1173d5a03140f0e"
language="Lua"
purpose="Shows a bar of buttons you can click on to do things"
date_written="2009-02-26 09:00"
date_modified="2022-01-14 09:05"
requires="4.40"
save_state="y"
version="5.1"
>
<description trim="y">
<![CDATA[
Install this plugin to show a button bar.
Click on an icon to execute a script or send a command to the MUD.
Type: "press icon n" to activate that icon (and its cooldown etc.) from the keyboard
e.g. press icon 2 <--- where 2 refers to "button 2" in the list of buttons
]]>
</description>
</plugin>
<!-- Aliases -->
<aliases>
<alias
script="pressIcon"
match="^press icon (\d+)$"
enabled="y"
regexp="y"
send_to="12"
sequence="100"
>
</alias>
</aliases>
<!-- Timers -->
<timers>
<timer
script="handle_cooldowns"
enabled="y" second="1.00"
active_closed="y" >
</timer>
</timers>
<!-- Script -->
<script>
-- pull in entities outside the CDATA block
horizontal = ("&horizontal;"):lower ():sub (1, 1) == "y";
show_time = ("&show_time;"):lower ():sub (1, 1) == "y";
<![CDATA[
-- table of buttons
--[[
Each button can have:
icon - filename of the image to draw
text - text to write if no icon is set
tooltip - what to show if you hover the mouse over the button
send - what to send to the MUD
script - a script function to call
cooldown - time spell takes to cool down, in seconds
sound - sound to play when button pressed
done - a script function to call when the cooldown is up
--]]
buttons = {
-- button 1
{
icon = nil,
tooltip = "Heal self", -- tooltip help text
text = "Heal",
send = "echo doing heal", -- what to send
cooldown = 10, -- cooldown time in seconds
sound = "chimes.wav", -- sound to play when cast
done = function () print ("Healing done!") end -- what to do when done
}, -- end of button 1
-- button 2
{
icon = nil,
text = "Attack",
tooltip = "Attack the darkness", -- tooltip help text
send = "echo doing attack",
cooldown = 5,
}, -- end of button 2
--> add more buttons here
} -- end of buttons table
-- configuration
ICON_WIDTH = 48
ICON_HEIGHT = 32
BACKGROUND_COLOUR = ColourNameToRGB "dimgray"
BOX_COLOUR = ColourNameToRGB "royalblue"
BUTTON_EDGE = ColourNameToRGB "silver"
MOUSE_DOWN_COLOUR = ColourNameToRGB "darkorange"
-- where to put the window
WINDOW_POSITION = 6 -- top right
OFFSET = 6 -- gap inside box
EDGE_WIDTH = 2 -- size of border stroke
--[[
Useful positions:
4 = top left
5 = center left-right at top
6 = top right
7 = on right, center top-bottom
8 = on right, at bottom
9 = center left-right at bottom
--]]
-- font and size to use
FONT_NAME = "Lucida Sans Unicode"
FONT_SIZE = 18
FONT_SIZE_MEDIUM = 14
FONT_SIZE_SMALL = 10
FONT_SIZE_SMALLEST = 8
TEXT_COLOUR = ColourNameToRGB "white"
FADED_TEXT_COLOUR = ColourNameToRGB "darkgray"
COOLDOWN_TEXT_COLOUR = ColourNameToRGB "yellow"
-- sound to play if on cooldown
ON_COOLDOWN_SOUND = "ding.wav"
frames = {} -- remember where each icon was
require "commas"
function mousedown (flags, hotspot_id)
if hotspot_id == "_" then
-- find where mouse is so we can adjust window relative to mouse
startx, starty = WindowInfo (win, 14), WindowInfo (win, 15)
-- find where window is in case we drag it offscreen
origx, origy = WindowInfo (win, 10), WindowInfo (win, 11)
return
end -- if
local n = tonumber (hotspot_id)
-- draw the button border in another colour for visual feedback
WindowRectOp (win, 1,
frames [n].x1, frames [n].y1, frames [n].x2, frames [n].y2,
MOUSE_DOWN_COLOUR)
Redraw ()
end -- mousedown
function cancelmousedown (flags, hotspot_id)
local n = tonumber (hotspot_id)
-- draw the button border in original colour for visual feedback
WindowRectOp (win, 1,
frames [n].x1, frames [n].y1, frames [n].x2, frames [n].y2,
BUTTON_EDGE)
Redraw ()
end -- cancelmousedown
function mouseup (flags, hotspot_id)
-- fix border colour
cancelmousedown (flags, hotspot_id)
local n = tonumber (hotspot_id)
local button = buttons [n]
-- shift key clears cooldown
if bit.band (flags, 1) == 1 then
SetCooldown (n, nil)
return
end -- if
-- can't press button if on cooldown
if (button.cooldown_left or 0) > 0 then
Sound (ON_COOLDOWN_SOUND)
return
end -- still on cooldown
-- play sound if defined
if button.sound then
Sound (button.sound)
end -- sound to play
-- send to world if something specified
if type (button.send) == "string" and
button.send ~= "" then
local errors = {} -- no errors yet
-- function to do the replacements for string.gsub
local function replace_variables (s)
s = string.sub (s, 2) -- remove the @
replacement = GetPluginVariable ("", s) -- look up variable in global variables
if not replacement then -- not there, add to errors list
table.insert (errors, s)
return
end -- not there
return replacement -- return variable
end -- replace_variables
-- replace all variables starting with @
local command = string.gsub (button.send, "@%a[%w_]*", replace_variables)
-- report any errors
if #errors > 0 then
for k, v in ipairs (errors) do
ColourNote ("white", "red", "Variable '" .. v .. "' does not exist")
end -- for
return
end -- error in replacing
Execute (command)
end -- if
-- execute script if wanted
if type (button.script) == "function" then
button.script (n)
end -- if
SetCooldown (n, button.cooldown)
end -- mouseup
function pressIcon (name, line, wildcards)
local whichIcon = tonumber (wildcards [1])
if not whichIcon or whichIcon < 1 or whichIcon > #buttons then
ColourNote ("red", "", "That icon button does not exist")
return
end -- if
mouseup (0, whichIcon)
end -- pressIcon
function dragmove(flags, hotspot_id)
-- find where it is now
local posx, posy = WindowInfo (win, 17),
WindowInfo (win, 18)
-- move the window to the new location
WindowPosition(win, posx - startx, posy - starty, 0, 2);
-- change the mouse cursor shape appropriately
if posx < 0 or posx > GetInfo (281) or
posy < 0 or posy > GetInfo (280) then
SetCursor (11) -- X cursor
else
SetCursor (10) -- arrow (NS/EW) cursor
end -- if
end -- dragmove
function dragrelease(flags, hotspot_id)
local newx, newy = WindowInfo (win, 17), WindowInfo (win, 18)
-- don't let them drag it out of view
if newx < 0 or newx > GetInfo (281) or
newy < 0 or newy > GetInfo (280) then
-- put it back
WindowPosition(win, origx, origy, 0, 2);
end -- if out of bounds
end -- dragrelease
function SetCooldown (n, amount)
assert (n >= 1 and n <= #buttons,
"Bad button number " .. n .. " to SetCooldown")
if amount then
assert (amount >= 0, "Bad amount " .. amount .. " to SetCooldown")
end -- if
local frame = frames [n]
local x1, y1, x2, y2 = frame.x1 + 1, frame.y1 + 1, frame.x2 - 1, frame.y2 - 1
buttons [n].cooldown_left = amount -- cooldown time left in seconds
local max = buttons [n].cooldown or 0 -- max cooldown time
local percent -- how far cooled down we are as a percent
if max > 0 then
percent = (amount or 0) / max
else
percent = 0 -- don't divide by zero!
end -- if
-- reload the image
if WindowDrawImage(win, n,
x1, y1, -- left, top
x2, y2, -- right, bottom
2) -- mode - stretch or shrink
~= error_code.eOK then
WindowRectOp (win, 2, x1, y1, -- left, top
x2, y2, -- right, bottom
BACKGROUND_COLOUR)
local button_text = buttons[n].text
if button_text then
AddText(button_text, n, false, (amount == 0) and TEXT_COLOUR or FADED_TEXT_COLOUR)
end
end
if amount and amount > 0 then
-- calculate pie end point
local endx = math.cos (math.rad (percent * 360 + 90)) * ICON_WIDTH + ICON_WIDTH / 2
local endy = -1 * math.sin (math.rad (percent * 360 + 90)) * ICON_HEIGHT + ICON_HEIGHT / 2
-- clear temporary window
WindowRectOp (tempwin, 2, 0, 0, 0, 0, 0xFFFFFF) -- fill with white
-- draw the pie showing amount of cooldown
WindowCircleOp (tempwin, 5, -10, -10, ICON_WIDTH + 10, ICON_HEIGHT + 10, -- pie
0x000000, 5, 0, -- no pen
0x000000, 0, -- solid brush, black
ICON_WIDTH / 2, 0, -- from 12 o'clock position
endx, endy)
-- turn pie shape into an image
WindowImageFromWindow(win, "mask", tempwin)
-- blend in (darken mode) with 50% opacity
WindowBlendImage(win, "mask",
x1, y1, x2, y2, -- rectangle
5, -- darken
0.5) -- opacity
-- if they want to see the time left (text on top of the button) do that now
if show_time then
local time_left = convert_time (amount)
time_left = string.gsub (time_left, "[ s]", "") -- get rid of spaces, and "s"
AddText (time_left, n, true, COOLDOWN_TEXT_COLOUR)
end -- show_time
else
buttons [n].cooldown_left = nil
if buttons [n].done and type (buttons [n].done) == 'function' then -- script to call when done
buttons [n].done (n) -- pass button number to function
end -- if a function to be called
end -- if amount
Redraw ()
end -- function SetCooldown
function AddText (text, n, bold, colour)
local frame = frames [n]
local x1, y1, x2, y2 = frame.x1 + 1, frame.y1 + 1, frame.x2 - 1, frame.y2 - 1
local font = bold and "f1" or "f5"
local text_len = WindowTextWidth (win, font, text)
-- use smaller font if it doesn't fit
if text_len > ICON_WIDTH then
font = bold and "f2" or "f6"
text_len = WindowTextWidth (win, font, text)
-- still too big?
if text_len > ICON_WIDTH then
font = bold and "f3" or "f7"
text_len = WindowTextWidth (win, font, text)
-- still too big?
if text_len > ICON_WIDTH then
font = bold and "f4" or "f8"
text_len = WindowTextWidth (win, font, text)
end -- if
end -- if
end -- if
local font_height = WindowFontInfo (win, font, 1)
local x_offset = math.max ((ICON_WIDTH - text_len) / 2, 0)
local y_offset = math.max ((ICON_HEIGHT - font_height) / 2, 0)
WindowText (win, font, text, x1 + x_offset + 2, y1 + y_offset + 2, x2, y2, 0x000000)
WindowText (win, font, text, x1 + x_offset, y1 + y_offset, x2, y2, colour)
end
function OnPluginInstall ()
local x, y, mode, flags =
tonumber (GetVariable ("windowx")) or 0,
tonumber (GetVariable ("windowy")) or 0,
tonumber (GetVariable ("windowmode")) or WINDOW_POSITION, -- top right
tonumber (GetVariable ("windowflags")) or 0
-- check miniwindow visible
if x < 0 or x > GetInfo (281) or
y < 0 or y > GetInfo (280) then
x, y = 0, 0 -- reset to top left
end -- if not visible
win = GetPluginID () -- get a unique name
tempwin = win .. ":temp"
local gauge_height, gauge_width
if horizontal then
window_width = (#buttons * (ICON_WIDTH + OFFSET)) + OFFSET
window_height = ICON_HEIGHT + (OFFSET * 2)
else
window_width = ICON_WIDTH + (OFFSET * 2)
window_height = (#buttons * (ICON_HEIGHT + OFFSET)) + OFFSET
end -- if
-- make the miniwindow
WindowCreate (win,
x, y, -- left, top (auto-positions)
window_width, -- width
window_height, -- height
mode, -- position mode
flags, -- flags
BACKGROUND_COLOUR)
-- for drawing cooldowns (window not visible)
WindowCreate (tempwin,
0, 0, -- left, top
ICON_WIDTH, -- width
ICON_HEIGHT, -- height
12, -- position mode
0, -- flags
ColourNameToRGB "white")
-- grab bold fonts
WindowFont (win, "f1", FONT_NAME, FONT_SIZE, true)
WindowFont (win, "f2", FONT_NAME, FONT_SIZE_MEDIUM, true)
WindowFont (win, "f3", FONT_NAME, FONT_SIZE_SMALL, true)
WindowFont (win, "f4", FONT_NAME, FONT_SIZE_SMALLEST, true)
-- grab not-bold fonts
WindowFont (win, "f5", FONT_NAME, FONT_SIZE, false)
WindowFont (win, "f6", FONT_NAME, FONT_SIZE_MEDIUM, false)
WindowFont (win, "f7", FONT_NAME, FONT_SIZE_SMALL, false)
WindowFont (win, "f8", FONT_NAME, FONT_SIZE_SMALLEST, false)
-- draw the buttons
for n, v in ipairs (buttons) do
if v.icon then
if WindowLoadImage (win, n, GetInfo (66) .. v.icon) ~= error_code.eOK then
DoAfterSpecial (1, string.format ([[
ColourNote ("white", "red", "Could not load image '%s'")]],
string.gsub (GetInfo (66) .. v.icon, '\\', '\\\\')),
sendto.script)
end -- if
end -- if icon specified
local x1, y1, x2, y2
-- where to draw the icon
if horizontal then
x1, y1 = (n - 1) * (ICON_WIDTH + OFFSET) + OFFSET, OFFSET
x2, y2 = n * (ICON_WIDTH + OFFSET), ICON_HEIGHT + OFFSET
else
x1, y1 = OFFSET, (n - 1) * (ICON_HEIGHT + OFFSET) + OFFSET
x2, y2 = ICON_WIDTH + OFFSET, n * (ICON_HEIGHT + OFFSET)
end -- if
-- remember where to draw the frame, for mouse clicks
frames [n] = {
x1 = x1 - 1,
y1 = y1 - 1,
x2 = x2 + 1,
y2 = y2 + 1
}
-- draw the image
if WindowDrawImage(win, n,
x1, y1, -- left, top
x2, y2, -- right, bottom
2) -- mode - stretch or shrink
~= error_code.eOK then
WindowRectOp (win, 2, x1, y1, -- left, top
x2, y2, -- right, bottom
BACKGROUND_COLOUR)
if v.text then
AddText(v.text, n, false, TEXT_COLOUR)
end
end -- if
-- draw the button border
WindowRectOp (win, 1,
frames [n].x1, frames [n].y1, frames [n].x2, frames [n].y2,
BUTTON_EDGE)
-- make a hotspot we can click on
WindowAddHotspot(win, n,
frames [n].x1, frames [n].y1, frames [n].x2, frames [n].y2, -- rectangle
"", -- mouseover
"", -- cancelmouseover
"mousedown",
"cancelmousedown",
"mouseup",
v.tooltip, -- tooltip text
1, 0) -- hand cursor
end -- for each world
-- draw the border of the whole box
WindowCircleOp (win, 2, 0, 0, 0, 0, BOX_COLOUR, 6, EDGE_WIDTH, 0x000000, 1)
-- make a hotspot
WindowAddHotspot(win, "_",
0, 0, 0, 0, -- whole window
"", -- MouseOver
"", -- CancelMouseOver
"mousedown",
"", -- CancelMouseDown
"", -- MouseUp
"Drag to move", -- tooltip text
10, 0) -- arrow (NS/EW) cursor
WindowDragHandler(win, "_", "dragmove", "dragrelease", 0)
if GetVariable ("enabled") == "false" then
ColourNote ("yellow", "", "Warning: Plugin " .. GetPluginName ().. " is currently disabled.")
EnablePlugin (GetPluginID (), false)
return
end -- they didn't enable us last time
-- ensure window visible
WindowShow (win, true)
end -- OnPluginInstall
-- hide window on removal
function OnPluginClose ()
WindowShow (win, false) -- hide it
end -- OnPluginClose
-- show window on enable
function OnPluginEnable ()
WindowShow (win, true) -- show it
end -- OnPluginEnable
-- hide window on disable
function OnPluginDisable ()
WindowShow (win, false) -- hide it
end -- OnPluginDisable
function OnPluginSaveState ()
SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID (), 17)))
SetVariable ("windowx", WindowInfo (win, 10))
SetVariable ("windowy", WindowInfo (win, 11))
SetVariable ("windowmode", WindowInfo (win, 7))
SetVariable ("windowflags", WindowInfo (win, 8))
end -- OnPluginSaveState
-- called every second on a timer
function handle_cooldowns (name)
for n, v in ipairs (buttons) do
if buttons [n].cooldown_left then
SetCooldown (n, buttons [n].cooldown_left - 1)
end -- if some cooldown left
end -- for
end -- function handle_cooldowns
]]>
</script>
</muclient>