· 6 years ago · Jul 31, 2019, 06:46 AM
1<?xml version="1.0" encoding="iso-8859-1"?>
2<!DOCTYPE muclient>
3<muclient>
4<plugin
5 name="WinkleWinkle_Mapper_Extender_4_0"
6 author="WinkleWinkle"
7 id="b6eae87ccedd84f510b74715"
8 language="Lua"
9 purpose="Extends mapper functionality"
10 date_written="2017-12-10 16:37:14"
11 requires="4.76"
12 version="4.0"
13 save_state="y"
14 >
15
16<description trim="n">
17<![CDATA[
18
19MAPPER EXTENDER USAGE:
20
21===== SHOW THIS HELP =============>
22> extender help
23 - shows only this help
24> ww help
25 - all winklewinkle(tm) plugins show help
26
27===== RUNNING ====================>
28> xrunto [areaname]
29 - Runs you via mapper goto/walkto to the first room you discovered in that area
30
31> xrt [areaname]
32 - Same as "xrunto"
33
34> xset mark
35 - Sets the current room you are in to be the "first" room of that area
36
37> xset mark [roomnumber]
38 - Sets room [roomnumber] as the first room in the area that it belongs to
39
40> xset speed
41 - Toggles the use of mapper goto/walkto for all movement commands
42
43> xset speed <walk|run>
44 - changes the use of mapper goto/walkto for all movement commands
45
46> xmapper move <roomid>
47 - uses set movement speed to move to the specified room id
48
49> xmapper move <roomid> <walk|run>
50 - uses a temporary movement speed to move to the specified room id
51
52===== SEARCHING ==================>
53> xm [roomname]
54 - Lists and numbers rooms that match the [roomname] exactly, and then partial matches in the current area
55
56> xmall [roomname]
57 - Lists and numbers rooms that match the [roomname] exactly, and then partial matches in all areas
58
59===== ROOMS ======================>
60> go [index]
61 - Will run you with mapper goto/walkto to the first room in a numbered room list
62
63> go
64 - The same as typing "go 1"
65
66> nx
67 - Will run you to the next numbered room, "go" then "nx" would be the same as typing "go 1" then "go 2"
68
69===== CAMPAIGNS ==================>
70> xcp
71 - Lists all active campaign mobs in a numbered list (see xcp [index])
72
73> xcp [index]
74 - Area CP runs you to the area of that CP item and does a Quick-Where on your mob. Type "go [index]" after this to go to the first known room found (if any)
75 - Room CP lists all known rooms that exactly match your CP room name. Type "go [index]" to run to the right room (if any).
76
77===== NOTES ======================>
78> roomnote
79 - Lists all mapper notes for the current room (if any).
80
81> roomnote area
82 - Lists all mapper notes for the current area (if any). Useful for mazes
83
84===== SETTINGS ======================>
85> xset pk
86 - Toggles the display of PK flag in room searches
87
88> xset vidblain
89 - Toggles a hack that will allow you to speedwalk to vidblain areas if you do not have a portal to use
90
91> xset reset gui
92 - Will reset the X, Y and Z position of the Extender GUI
93
94== v3 ==
95===== GLOBAL QUESTS ==============>
96> qq
97 - refresh the global quest list (if you are on a global quest)
98 This will also refresh the GUI
99
100> qqreport <channel>
101 - will send a list of your incomplete GQ mobs to the channel of your choosing (eg qqreport gt)
102
103> xset gqrefresh
104 - Toggles the automatic refreshing of the GQ listing when a GQ mob is killed (for faster performance!)
105
106== v4 ==
107===== Performance Improv. & Unscramble Names ==============>
108> xname <index#>
109 - Execute while in area and it will search in-game mobdeath
110 Use xname gq <indedx#> for global QUESTS
111
112===== Bast Specific (requires Bast) ==============>
113> bna(ame) <mob name>
114 - Execute from anywhere and search personal Bast db
115
116> bast update
117 - Updates Bast database with unique mobs previously killed
118 Used for unscrambling names
119
120===== TO CREATE A CEXIT / MAP A PORTAL ==========>
121
122http://code.google.com/p/aardwolf-scriptalicious/wiki/MapperHelp
123
124]]>
125</description>
126
127</plugin>
128
129<!-- Timers -->
130
131<timers>
132
133 <timer
134 name="tim_init_plugin"
135 script="init_plugin"
136 enabled="y"
137 second="1">
138 </timer>
139
140 <timer
141 name="execute_in_area_timer"
142 script="execute_in_area_tick"
143 enabled="n"
144 second="0.25">
145 </timer>
146
147</timers>
148
149<!-- finding aliases -->
150
151<aliases>
152
153 <!-- debug -->
154 <alias
155 name=""
156 match="^michael$"
157 regexp="y"
158 enabled="y"
159 sequence="100"
160 script="tmp"
161 >
162 </alias>
163
164 <alias
165 name="ali_toggle_debug"
166 match="^ext debug$"
167 regexp="y"
168 enabled="y"
169 sequence="100"
170 script="ext_debug"
171 >
172 </alias>
173
174 <alias match="^(?:ww|extender) help$"
175 enabled="y"
176 sequence="100"
177 send_to="12"
178 regexp="y"
179 keep_evaluating="y"
180 >
181 <send>
182 ColourNote("MediumSeaGreen", "", GetPluginInfo (GetPluginID (), 3))
183 </send>
184 </alias>
185
186 <!-- Settings -->
187
188 <alias
189 name="ali_set_pk"
190 match="^xset pk$"
191 regexp="y"
192 enabled="y"
193 sequence="100"
194 script="xset_pk"
195 >
196 </alias>
197
198 <alias match="^xset mark$"
199 enabled="y"
200 sequence="100"
201 script="xset_to_mark"
202 regexp="y"
203 >
204 </alias>
205
206 <alias match="^xset vidblain$"
207 enabled="y"
208 sequence="99"
209 script="set_check_vidblain"
210 regexp="y"
211 >
212 </alias>
213
214 <alias match="^xru?n?to? (.+)$"
215 enabled="y"
216 sequence="100"
217 script="xrun_to"
218 regexp="y"
219 >
220 </alias>
221
222 <alias
223 name="xm_request"
224 match="^xm(?:\ {(?<mob>[^\}]+)\})? (?<loc>.+)$"
225 enabled="y"
226 sequence="100"
227 script="map_area"
228 regexp="y"
229 >
230 </alias>
231
232 <alias match="^xmal?l?(?:\ {(?<mob>[^\}]+)\})? (?<loc>.+)$"
233 enabled="y"
234 sequence="99"
235 script="map_area_all"
236 regexp="y"
237 keep_evaluating="n"
238 >
239 </alias>
240
241
242 <alias match="^(?<cmd>cp|ca|cam|camp|campa|campai|campaig|campaign) (?<param>c|ch|che|check)$"
243 enabled="y"
244 sequence="5"
245 script="campaign_check"
246 regexp="y"
247 >
248 </alias>
249 <alias match="^(?<cmd>xcp) ?(?<param>c|ch|che|chec|check|test)?$"
250 enabled="y"
251 sequence="6"
252 script="campaign_check"
253 regexp="y"
254 >
255 </alias>
256
257 <alias match="^got?o?( (?<id>.+))?$"
258 enabled="y"
259 sequence="100"
260 script="goto_number"
261 regexp="y"
262 >
263 </alias>
264
265 <alias match="^nx$"
266 enabled="y"
267 sequence="100"
268 script="goto_next"
269 regexp="y"
270 >
271 </alias>
272
273 <alias match="^(xcp|cp|ca|cam|camp|campa|campaign) (?<index>[0-9]+)$"
274 enabled="y"
275 sequence="100"
276 script="goto_cp"
277 regexp="y"
278 >
279 </alias>
280 --- descramble mob name
281 <alias
282 name="xname_cp"
283 match="^(xname|xnam|xna|xn) (?<index>[0-9]{1,2})$"
284 enabled="y"
285 sequence="100"
286 script="xname_start"
287 regexp="y"
288 >
289 </alias>
290 <alias
291 name="xname_gq"
292 match="^(xname|xnam|xna|xn) gq (?<index>[0-9]{1,2})$"
293 enabled="y"
294 sequence="100"
295 script="xname_start"
296 regexp="y"
297 >
298 </alias>
299 <alias
300 name="xname_custom"
301 match="^(xname|xnam|xna|xn) (?P<mob>[\w ]{1,20})$"
302 enabled="y"
303 sequence="100"
304 script="xname_start"
305 regexp="y"
306 >
307 </alias>
308 <alias
309 name="xname_bast"
310 match="^(bname|bnam|bna) (?<mob>.+)$"
311 enabled="y"
312 sequence="100"
313 script="xname_start"
314 regexp="y"
315 >
316 </alias>
317 <alias
318 name="bast_update"
319 match="bast update"
320 enabled="y"
321 sequence="100"
322 script="bast_update"
323 regexp="n"
324 >
325 </alias>
326
327 <!-- speed -->
328
329 <alias match="^xset speed ?(?<speed>run|walk)?$"
330 enabled="y"
331 sequence="100"
332 script="set_speed"
333 regexp="y"
334 >
335 </alias>
336
337 <alias match="^xma?p?p?e?r? move (?<roomid>[0-9]+|light|nomap_Camp Room_light) ?(?<speed>run|walk)?$"
338 enabled="y"
339 sequence="95"
340 ignore_case="y"
341 script="move_trigger"
342 regexp="y"
343 >
344 </alias>
345
346 <!-- roomnotes -->
347
348 <alias match="^r(?:oomnote|n)$"
349 enabled="y"
350 sequence="100"
351 script="room_note"
352 regexp="y"
353 >
354 </alias>
355
356 <alias match="^r(?:oomnote|n) a(?:rea)?(?: (?<areaid>.+))?$"
357 enabled="y"
358 sequence="99"
359 script="room_note_area"
360 regexp="y"
361 >
362 </alias>
363
364 <alias match="^xmapper purge room$"
365 enabled="y"
366 sequence="100"
367 script="map_purgeroom"
368 regexp="y"
369 >
370 </alias>
371
372 <!-- Sql Execution -->
373
374 <alias name="runsql"
375 match="^runsql (?<sql>.+)$"
376 enabled="y"
377 sequence="1"
378 script="RunSql"
379 regexp="y"
380 >
381 </alias>
382
383 <alias name="execsql"
384 match="^execsql (?<sql>.+)$"
385 enabled="y"
386 sequence="1"
387 script="ExecSql"
388 regexp="y"
389 >
390 </alias>
391 <alias name="ali_simulate_list"
392 match="^qq(?<debug>test)$"
393 enabled="y"
394 sequence="1"
395 script="gq_list_simulate"
396 regexp="y"
397 >
398 </alias>
399
400 <!-- GQ -->
401 <!-- v3 -->
402 <alias match="^qqrep(?:ort)? (?<channel>.+)$"
403 enabled="y"
404 sequence="100"
405 script="qq_report"
406 regexp="y"
407 >
408 </alias>
409
410 <alias match="^xset gqrefresh$"
411 enabled="y"
412 sequence="100"
413 script="set_gq_refresh"
414 regexp="y"
415 >
416 </alias>
417
418 <alias name="ali_gq_list"
419 match="^qq$"
420 enabled="y"
421 sequence="2"
422 script="gq_list"
423 regexp="y"
424 >
425 </alias>
426
427 <alias name="ali_goto_gq"
428 match="^qq (?<index>[0-9]+)$"
429 enabled="y"
430 sequence="2"
431 script="goto_gq"
432 regexp="y"
433 >
434 </alias>
435
436</aliases>
437
438<triggers>
439 <trigger
440 name="trg_cp_request"
441 match="^Commander Barcett tells you \'Good luck in your campaign\!\'$"
442 enabled="y"
443 regexp="y"
444 sequence="100"
445 script="campaign_check"
446 >
447 </trigger>
448
449 <trigger
450 name="trg_cp_mob_dead"
451 match="Congratulations, that was one of your CAMPAIGN mobs!"
452 enabled="y"
453 sequence="100"
454 script="campaign_check"
455 >
456 </trigger>
457
458 <trigger match="^You still have to kill \* (?<mob>[^\(]+) \((?<where>.+?)(?<isdead> - Dead)?\)\.?$"
459 name="trg_xcp_line"
460 script="capture_index_line"
461 enabled="n"
462 regexp="y"
463 omit_from_output="y"
464 sequence="500">
465 </trigger>
466
467 <trigger match="^(?!You still have to kill \*)"
468 name="trg_xcp_line_end"
469 script="xcp_index_line_end"
470 enabled="n"
471 regexp="y"
472 omit_from_output="y"
473 sequence="500">
474 </trigger>
475
476 <trigger match="You are not currently on a campaign."
477 name="trg_xcp_line_end_none"
478 script="xcp_index_line_end"
479 enabled="y"
480 regexp="n"
481 omit_from_output="n"
482 sequence="500">
483 </trigger>
484
485 <!-- area grabber -->
486 <trigger match=" [ Listing all areas in range * to * ]"
487 name="trg_area_index_start_gag"
488 script="area_index_start_gag"
489 enabled="y"
490 regexp="n"
491 omit_from_output="n"
492 sequence="100">
493 </trigger>
494
495 <trigger match="^From To Lock Builder Area Name"
496 name="trg_area_index_start"
497 script="area_index_start"
498 enabled="n"
499 regexp="y"
500 omit_from_output="n"
501 sequence="100">
502 </trigger>
503
504 <trigger match="---- ---- ---- --------------- ------------------------------"
505 name="trg_area_index_gag1"
506 enabled="n"
507 regexp="n"
508 omit_from_output="n"
509 sequence="100">
510 </trigger>
511 <trigger match="---------------------------------------------------------------"
512 name="trg_area_index_gag2"
513 enabled="n"
514 regexp="n"
515 omit_from_output="n"
516 sequence="100">
517 </trigger>
518
519 <trigger match="^ (?<min>[0-9 ]{3}) (?<max>[0-9 ]{3}) (?<lock>[0-9 ]{3}) (?<author>.{15}) (?<area>.+)$"
520 name="trg_area_index_line"
521 script="area_index_line"
522 enabled="n"
523 regexp="y"
524 omit_from_output="n"
525 sequence="100">
526 </trigger>
527
528 <trigger match="'Lock' means you cannot enter until you are that level or higher."
529 name="trg_area_index_end"
530 script="area_index_end"
531 enabled="n"
532 regexp="n"
533 omit_from_output="n"
534 sequence="100">
535 </trigger>
536
537
538 <!-- gq helper -->
539 <!-- v3 -->
540 <trigger match="^You still have to kill (?<qty>[0-9]) \* (?<mob>[^\(]+) \((?<where>.+?)(?<isdead> - Dead)?\)$"
541 name="x_gq_line"
542 group="x_gq"
543 enabled="n"
544 regexp="y"
545 omit_from_output="y"
546 sequence="500"
547 script="capture_index_line"
548 >
549 </trigger>
550
551 <trigger match="^(?!You still have to kill )"
552 name="x_gq_line_end"
553 group="x_gq"
554 enabled="n"
555 regexp="y"
556 omit_from_output="y"
557 sequence="500"
558 script="capture_gq_line_end"
559 >
560 </trigger>
561
562 <trigger match="You are not in a global quest."
563 name="x_gq_line_end_none"
564 enabled="y"
565 regexp="n"
566 omit_from_output="n"
567 sequence="500"
568 script="capture_gq_line_finished"
569 >
570 </trigger>
571
572 <trigger match="^You are no longer part of Global Quest # (?:\d+) and will be unable to rejoin.$"
573 name="x_gq_line_end_none2"
574 enabled="y"
575 regexp="y"
576 omit_from_output="n"
577 sequence="500"
578 script ="capture_gq_line_finished"
579 >
580 </trigger>
581 <trigger
582 match="You were the first to complete this quest!"
583 name="x_gq_line_end_none4"
584 enabled="y"
585 regexp="n"
586 omit_from_output="n"
587 sequence="500"
588 script ="capture_gq_line_finished"
589 >
590 </trigger>
591
592 <trigger
593 match="You have already completed this global quest."
594 name="x_gq_line_end_none3"
595 enabled="y"
596 regexp="n"
597 omit_from_output="n"
598 sequence="500"
599 script ="capture_gq_line_finished"
600 >
601 </trigger>
602
603 <trigger match="You have finished this global quest."
604 name="x_gq_line_end_none5"
605 enabled="y"
606 regexp="n"
607 omit_from_output="n"
608 sequence="500"
609 script="capture_gq_line_finished"
610 >
611 </trigger>
612
613 <trigger
614 enabled="y"
615 group="GlobalQuest"
616 match="^Global Quest\: The global quest for levels .+ to .+ has now started\.$"
617 regexp="y"
618 script="gq_list"
619 sequence="100"
620 >
621 </trigger>
622
623 <trigger
624 name="trigger_gq_mob_dead"
625 enabled="n"
626 group="GlobalQuest"
627 match="Congratulations, that was one of the GLOBAL QUEST mobs!"
628 script="gq_refresh"
629 sequence="100"
630 >
631 </trigger>
632
633 <!-- v4 Descramble Names -->
634 <trigger
635 name="xname_first"
636 group="xname_ends"
637 enabled="n"
638 regexp="y"
639 match="^\s+\[ Most popular kills .+ \]$"
640 sequence="100"
641 script="xname_end_point"
642 omit_from_output="y"
643 >
644 </trigger>
645 <trigger
646 name="xname_detail"
647 enabled="n"
648 regexp="y"
649 match="^(?:\s+)?[0-9]+ - (?P<mob>.+) (?<level>[0-9]+) (?P<long_name>.+) (?<kills>[0-9]+)$"
650 sequence="100"
651 script="xname_capture_list"
652 omit_from_output="y"
653 >
654 </trigger>
655 <trigger
656 name="xname_hide"
657 enabled="n"
658 regexp="y"
659 match="^.+$"
660 sequence="100"
661 send_to="12"
662 omit_from_output="y"
663 >
664 </trigger>
665 <trigger
666 name="xname_last"
667 group="xname_ends"
668 enabled="n"
669 regexp="n"
670 match="See also: Mobkills, Areakills and Areadeaths commands."
671 sequence="100"
672 script="xname_end_point"
673 omit_from_output="y"
674 >
675 </trigger>
676
677 ---v4 adding highlight to mobs
678 <trigger
679 enabled="y"
680 match="{scan}"
681 script="togglescan"
682 omit_from_output="y"
683 name="scanon"
684 sequence="100"
685 group="scantag"
686 />
687 <trigger
688 enabled="y"
689 match="{/scan}"
690 script="togglescan"
691 omit_from_output="y"
692 name="scanoff"
693 sequence="100"
694 group="scantag"
695 />
696 <trigger
697 enabled="n"
698 script="checkmob"
699 match="^ \- (\(.*\))* *(.+)$"
700 name="checkmob"
701 omit_from_output="y"
702 regexp="y"
703 sequence="100"
704 group="scan"
705 />
706
707--- v4 adding missing triggers
708
709<trigger
710 match="You are not currently on a campaign."
711 script="xcp_index_line_end"
712 name="xcp_not_on_cp"
713 enabled="y"
714 regexp="n"
715 omit_from_output="n"
716 sequence="100"
717 >
718</trigger>
719<trigger
720 match="You will have to level before you can go on another campaign."
721 script="xcp_index_line_end"
722 name="xcp_wait_on_cp"
723 enabled="n"
724 regexp="n"
725 omit_from_output="n"
726 sequence="100"
727 >
728</trigger>
729</triggers>
730<variables>
731 <variable name="example"></variable>
732</variables>
733
734<!-- Get our standard constants -->
735<include name="constants.lua"/>
736
737<!-- Script -->
738<script>
739
740
741<![CDATA[
742
743 require "serialize"
744 require "gmcphelper"
745 require "tprint"
746
747 -- Variables --
748 local showDebug = 0
749
750 local search_destroy_id = "e50b1d08a0cfc0ee9c442001"
751 local mob_mapper_id = "b555825a4a5700c35fa80800"
752
753 local searchResult = {}
754 local searchIndex = 0
755 local cpList = {}
756 local listIndex = 1
757
758 local mode = nil
759 local gotoList = {}
760 local gotoIndex = 1
761 local currentRoom = ""
762
763 local char_status
764
765 local next_room = -1
766 local last_area = ""
767
768
769
770 local mapper_area_index = 0
771
772 local last_substitute
773
774 local speed = "run"
775
776
777 local showPK = GetVariable("showPK") or "true"
778 local USER_check_vidblain = GetVariable("XRunToCheckVidblain") or "false"
779 local USER_show_help = "true"
780 --local USER_run_if_one_room = true
781
782 local init_called = 0
783
784 local area_range = {}
785
786 local area_range = {}
787
788 local areaStartRooms = {}
789 if (GetVariable("areaStartRooms") ~= nil) then
790 luastmt = "obj = " .. GetVariable("areaStartRooms")
791 assert (loadstring (luastmt or "")) ()
792 areaStartRooms = obj
793 end
794
795
796 -------- GQ -------
797 -- v3 --
798
799 local gqList = {}
800 local gqIndex = 1
801 local USER_gq_mob_dead_refresh = GetVariable("GQMobDeadRefresh") or "false"
802 ---------------------
803
804 -------- V4 -------
805 local cpList_old = {}
806 local gqList_old = {}
807 local old_list = {}
808 local xname_mobs = {}
809 local name_mode = ""
810 local has_bast = 1
811
812 function init_plugin()
813
814 if (init_called < 2) then
815
816 Execute("sendgmcp request char")
817
818 local localchar = char_status
819 if (localchar ~= nil and tonumber(localchar.state) == 3) then
820
821 if (init_called == 0) then
822 Execute("xset suspend page size")
823 init_called = 1
824 else
825
826 EnableTimer("tim_init_plugin", false)
827 init_called = 2
828
829 Execute("sendgmcp request room")
830
831 -- trigger a search for area limits
832 SendNoEcho("area 0 298")
833
834 init_triggers()
835
836 end
837
838 end
839 end
840
841
842
843 end
844
845
846 -- v3 --
847 function init_triggers()
848
849 DebugNote("init - " ..USER_gq_mob_dead_refresh)
850 if (USER_gq_mob_dead_refresh == "true") then
851 EnableTrigger("trigger_gq_mob_dead", true)
852 else
853 EnableTrigger("trigger_gq_mob_dead", false)
854 end
855
856 -- v3 --
857 local msg = string.format("GQ Mob Dead Refresh : %s", tostring(GetTriggerInfo("trigger_gq_mob_dead", 8)))
858 DebugNote(msg)
859 end
860
861 local questMob = ""
862 local onQuest = false
863 function OnPluginBroadcast (msg, id, name, text)
864
865 -- Look for GMCP handler.
866 if (id == '3e7dedbe37e44942dd46d264') then
867 if (text == "room.info") then
868 res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","room.info")
869
870 luastmt = "gmcpdata = " .. gmcparg
871 assert (loadstring (luastmt or "")) ()
872
873 currentRoom = {
874 roomid = gmcpval("num"),
875 areaid = gmcpval("zone")
876 }
877 elseif (text == "char.status") then
878 res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","char.status")
879 luastmt = "gmcpdatacharstatus = " .. gmcparg
880 assert (loadstring (luastmt or "")) ()
881 char_status = gmcpdatacharstatus
882 --tprint(char_status)
883
884 --currentState = tonumber(gmcpval("status.state"))
885
886 ---v4 adding highlight to mobs
887 elseif text == ("comm.quest") then
888 res, gmcparg = CallPlugin("3e7dedbe37e44942dd46d264","gmcpval","comm.quest")
889 stuff = assert (loadstring ('return ' .. gmcparg or ""))()
890
891 if stuff.action == "ready" then
892 -- did not work first time
893 --Note("ready")
894 elseif stuff.action == "start" then
895 -- worked first time
896 --Note("start")
897 onQuest = true
898 questMob = stuff.targ
899 --Note("got a mob: " .. tostring(questMob))
900 elseif stuff.action == "killed" then
901 -- worked for me the first time
902 --Note("action kill ")
903 onQuest = false
904 questMob = ""
905 --Note("Quest mob killed, s/b blank : " .. tostring(questMob))
906 elseif stuff.action == "comp" then
907 -- worked for me first time
908 --Note("completed")
909 onQuest = false
910 end
911
912 if stuff.action == "fail" or stuff.action == "timeout" then
913 Note("fail or timeout")
914 onQuest = false
915 questMob = ""
916 Note("Quest mob fail/timeout, s/b blank : " .. tostring(questMob))
917 end
918
919 if stuff.target == "killed" then
920 Note("target kill ")
921 onQuest = false
922 questMob = ""
923 Note("Quest mob killed v2, s/b blank : " .. tostring(questMob))
924 end
925 end
926 end
927
928 end
929
930 function set_speed(name, line, wildcards)
931 if (wildcards.speed ~= "") then
932 speed = wildcards.speed
933 else
934 if (speed == "walk") then
935 speed = "run"
936 else
937 speed = "walk"
938 end
939 end
940 ColourNote("darkorange", "", "Move speed:" .. speed)
941 end
942
943
944 function move_trigger(name, line, wildcards)
945
946 if (wildcards.roomid ~= "") then
947
948 move(wildcards.roomid, wildcards.speed)
949 end
950
951
952 end
953
954 function move(roomid, temp_speed)
955 if (temp_speed == nil or temp_speed == "") then
956 temp_speed = speed
957 end
958 if (temp_speed == "walk") then
959 Note("walking to " .. roomid)
960 Execute("mapper walkto " .. roomid)
961 else
962 Execute("mapper goto " .. roomid)
963 end
964 end
965
966 local last_cp_check = os.time()
967 local xcp_flag = false
968
969--- V4
970function campaign_check(name, line, args)
971
972 --Note("campaign list old check is " .. #cpList_old)
973 --Note("campaign cpList has " .. #cpList)
974 if has_bast and name == "trg_cp_mob_dead" then
975 -- no need b/c bast already sends a cp check
976 return
977 end
978 DebugNote("campaign_check " .. tostring(name))
979
980 xcp_flag = true
981
982 -- prevent double cp checks from different plugins
983 local time_check = os.time()
984 if ((time_check - last_cp_check) < 2) and name ~= "trg_cp_mob_dead" then
985 return
986 end
987
988 last_cp_check = time_check
989
990 cpList_old = cpList
991 cpList = {}
992 onCp = true
993
994 EnableTrigger("trg_xcp_line", true)
995 EnableTrigger("trg_xcp_line_end", false)
996
997 if (args.param == "test") then
998 cp_simulate()
999 elseif has_bast == false then
1000 Send("cp check")
1001 else
1002 -- bast's broadcast_cp.xml will take care of sending cp checks
1003 -- use zhalut's modifies copy of broadcast_cp.xml
1004 if name == "trg_cp_mob_dead" then
1005 -- should not reach here. taken care of at the top of the function
1006 Note("campaign_check: campaign mob")
1007 else
1008 Note("campaign_check: here")
1009 --Send("cp check")
1010 end
1011 end
1012end
1013
1014
1015function capture_index_line(name, line, args)
1016 -- for both GQ and CP
1017 DebugNote("check_exist")
1018 local mobQty = 1
1019 if name == "trg_xcp_line" then
1020 EnableTrigger("trg_xcp_line_end", true)
1021 --if cpList == nil then cpList = {} end
1022 --if cpList_old == nil then cpList_old = {} end
1023 old_list = cpList_old
1024 list = cpList
1025 elseif name == "x_gq_line" then -- gq
1026 EnableTrigger("x_gq_line_end", true)
1027 mobQty = tostring(args.qty)
1028 old_list = gqList_old
1029 list = gqList
1030 else
1031 ColourNote("darkorange","", "Unknown source in index_line")
1032 return
1033 end
1034 local skip = false
1035 if #list == 0 or #old_list == 0 then skip = true end -- go right to sql to gather data
1036
1037 local fnd = false
1038
1039 if not skip then -- increment if exists
1040 for i, v in ipairs(list) do
1041 if args.mob == v.origMob and args.where == v.where then
1042 list[i].qty = list[i].qty + mobQty
1043 fnd = true
1044 end
1045 end
1046 end
1047
1048
1049 if not fnd then -- look for it in old list
1050 for i , v in ipairs (old_list) do
1051 --if not fnd then
1052 if v.origMob == args.mob and v.where == args.where then
1053 copy_mob(list, args.mob, i, mobQty, args.where, args.isdead,old_list)
1054 --or else it could duplicate records
1055 fnd = true
1056 end
1057 --end
1058 end
1059 end
1060
1061 --function get_rooms_areas(list, place, mobName, qty, isDead, listType)
1062 if not fnd then -- doesn't exist, get run query to get info
1063-- Note("get " .. args.mob)
1064 if name == "trg_xcp_line" then
1065 get_rooms_areas(list, args.where, args.mob, mobQty, args.isdead,"cp")
1066 elseif name == "x_gq_line" then
1067 get_rooms_areas(list, args.where, args.mob, mobQty, args.isdead,"gq")
1068 end
1069 end
1070end
1071
1072function copy_mob(cpList, mob, old_index, qty, place, isDead, old_list)
1073
1074 --DebugNote("copy_mob " .. tostring(mob) .. " " .. tostring(old_index) .. " " .. tostring(qty) .. " " .. tostring(isDead))
1075 -- copy from old to new
1076 local listIndex = #list + 1
1077 list[listIndex] = {
1078 qty = qty,
1079 mob = old_list[old_index].mob,
1080 origMob = old_list[old_index].origMob,
1081 distance = old_list[old_index].distance,
1082 type = old_list[old_index].type,
1083 roomId = old_list[old_index].roomId,
1084 roomName = old_list[old_index].roomName,
1085 landingRoom = old_list[old_index].landingRoom,
1086 areaId = old_list[old_index].areaId,
1087 sortId = old_list[old_index].sortId,
1088 areaName = old_list[old_index].areaName,
1089 area = old_list[old_index].area,
1090 isDead = isDead,
1091 min = old_list[old_index].min,
1092 max = old_list[old_index].max,
1093 info = old_list[old_index].info,
1094 bast_kills = old_list[old_index].bast_kills,
1095 where = old_list[old_index].where,
1096 is_multi_area = old_list[old_index].is_multi_area,
1097 is_clean = old_list[old_index].is_clean
1098 }
1099
1100 --Note("copied " .. list[listIndex].mob .. " " .. list[listIndex].qty .. " " .. list[listIndex].type)
1101end
1102
1103------- V4 END -------
1104 local get_rooms_areas_sql =
1105 " SELECT r.uid as room, r.name as roomName, a.uid as area, a.name as areaName, 'room' as type, info " ..
1106 " FROM rooms r " ..
1107 " INNER JOIN areas a ON r.area = a.uid " ..
1108 " WHERE r.name = %s " ..
1109 " UNION " ..
1110 " SELECT -1 as room, '' as roomName, uid as area, name as areaName, 'area' as type, '' as info " ..
1111 " FROM areas " ..
1112 " WHERE name = %s " ..
1113 " ORDER BY type ASC "
1114-- get_rooms_areas(cpList, args.where, args.mob, 1, args.isdead)
1115
1116 function get_rooms_areas(list, place, mobName, qty, isDead, listType)
1117 local localLevel = -1
1118 if (char_status == nill) then
1119 DebugNote("Unknown char status")
1120 return
1121 else
1122 localLevel = tonumber(char_status.level)
1123 end
1124
1125 -- update quantity in table
1126 local skip = false
1127 for i, mob in ipairs(list) do
1128 if mobName == mob.origMob and place == mob.where then
1129 list[i].qty = list[i].qty + tonumber(qty)
1130 Note("get rooms: update qty" .. mobName .. "x " .. list[i].qty .. " " .. list[i].type )
1131 skip = true
1132 end
1133 end
1134
1135 if skip then
1136 return
1137 end
1138
1139 local listIndex = 0
1140 if listType == "cp" then
1141 listIndex = #cpList + 1
1142 elseif listType == "gq" then
1143 listIndex = #gqList + 1
1144 end
1145
1146 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
1147 local db = assert(sqlite3.open(worldPath .. ".db"))
1148
1149 -- room/area
1150 local select = string.format (get_rooms_areas_sql, fixsql(place), fixsql(place))
1151 --DebugNote(select)
1152
1153 local index = 0
1154 local lastMobSignature = ""
1155
1156 local cnt = 0
1157
1158 for row in db:nrows(select) do
1159 local tolerance = 11
1160 local area_tolerance = 50
1161 local min = (area_range[row.areaName] or {min = 0}).min
1162 local max = (area_range[row.areaName] or {max = 300}).max
1163 -- debug
1164 --min = 0
1165 --max = 300
1166
1167 if (row.type == "room") then
1168 --Note("room")
1169
1170 -- filter out spammy neighbouring rooms.. too much spam!
1171 local mobSignature = row.areaName .. "|" .. mobName
1172
1173 --DebugNote("lastMobSignature:" .. lastMobSignature .. ":mobSignature:" .. mobSignature)
1174
1175 -- sanitize text room ids for "unmappable" rooms that are now being mapped
1176 row.room = (tonumber(row.room) or "nomap")
1177
1178 if (lastMobSignature ~= mobSignature) then
1179 if (localLevel >= (min - tolerance) and localLevel <= (max + tolerance)) then
1180 --Note(mobName .. " | " .. " Room cnt: " .. tostring(cnt))
1181 --Note(mobName .. " | " .. tostring(mob_guess) .. " guess: " .. tostring(dist))
1182 local is_multi_area = 0
1183 cnt = cnt + 1
1184 if cnt > 1 then is_multi_area = 1 end
1185
1186 local sortId = row.area
1187
1188 --ColourNote("lime","","get rooms " .. place .. " " .. mobName .. " " .. row.area .. " " .. bast_kills)
1189
1190 index = index + 1
1191
1192 list[listIndex] = {
1193 qty = tonumber(qty),
1194 mob = mobName,
1195 origMob = mobName,
1196 distance = 0,
1197 type = row.type,
1198 roomId = row.room,
1199 roomName = row.roomName,
1200 landingRoom = -1,
1201 areaId = row.area,
1202 sortId = row.area,
1203 areaName = row.areaName,
1204 area = row.area,
1205 isDead = isDead,
1206 min = min,
1207 max = max,
1208 info = row.info,
1209 bast_kills = 0,
1210 where = place,
1211 is_multi_area = 0,
1212 is_clean = false}
1213
1214 listIndex = listIndex + 1
1215 else
1216 local link = string.format("Ignoring due to level : %s in '%s' (%s) [%s-%s]", mobName, row.roomName, row.area, min, max)
1217 Hyperlink("xm move " .. row.room, link, "Move to room " .. row.room, "Khaki", "black", 0)
1218 print("")
1219 end
1220 end
1221
1222 lastMobSignature = mobSignature
1223
1224 else -- area
1225 --Note("area")
1226 --if (localLevel >= (min - area_tolerance) and localLevel <= (max + area_tolerance)) then
1227 --Note(mobName .. " | " .. " Area cnt: " .. tostring(cnt))
1228 --Note(mobName .. " | " .. tostring(mob_guess) .. " guess: " .. tostring(dist))
1229
1230 local is_multi_area = 0
1231 cnt = cnt + 1
1232 if cnt > 1 then is_multi_area = 1 end
1233
1234 index = index + 1
1235
1236 --DebugNote("get_rooms_areas - area:" .. index .. ":" .. mobName)
1237 --listIndex = #cpList + 1
1238 -- Note("list: " .. listType)
1239 list[listIndex] = {
1240 qty = tonumber(qty),
1241 mob = mobName,
1242 origMob = mobName,
1243 distance = 0,
1244 type = row.type,
1245 roomId = row.room,
1246 roomName = row.roomName,
1247 landingRoom = -1,
1248 areaId = row.area,
1249 sortId = row.area,
1250 areaName = row.areaName,
1251 area = row.area,
1252 isDead = isDead,
1253 bast_kills = 0,
1254 where = place,
1255 is_multi_area = 0,
1256 is_clean = false}
1257
1258 listIndex = listIndex + 1
1259 --end
1260 end
1261
1262 end
1263 db:close_vm()
1264
1265 DebugNote(mobName .. " index:" .. index)
1266 -- add unknown mobs
1267 if (index == 0) then
1268 listIndex = #list + 1
1269
1270 list[listIndex] = {
1271 qty = tonumber(qty),
1272 mob = mobName,
1273 origMob = mobName,
1274 distance = 0,
1275 type = "unknown",
1276 roomId = 0,
1277 roomName = place,
1278 landingRoom = -1,
1279 areaId = "UNKNOWN",
1280 sortId = "UNKNOWN",
1281 areaName = "UNKNOWN",
1282 area = "UNKNOWN",
1283 isDead = isDead,
1284 bast_kills = 0,
1285 where = place,
1286 is_multi_area = 0,
1287 is_clean = false}
1288
1289 end
1290 end
1291 function clean_list(list)
1292 if #list == 0 then
1293 return
1294 end
1295 --------- BEGIN: remove dupes ---------
1296 for i, v in ipairs (list) do
1297 if not v.is_clean and v.type == "area" then -- favor areas over rooms
1298 for k, m in ipairs(list) do
1299 if m.origMob == v.origMob and m.type == "room" and m.areaId == v.areaId then
1300 table.remove(list,k)
1301 end
1302 end
1303 end
1304 end
1305
1306 --------- END: remove dupes ---------
1307
1308 --------- BEGIN: guess mob name ---------
1309 if has_bast == 1 then
1310 db_bast = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
1311 end
1312 ---- zhalut
1313 if has_bast == 1 then
1314 --db_bast = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
1315 local sql_bast = ""
1316 for i, v in ipairs (list) do -- list of cp mobs
1317 if not v.is_clean then
1318 local stringlength = string.len(v.origMob)
1319 local lowerMob = string.lower(v.origMob)
1320 if (stringlength>25) then
1321 lowerMob=string.sub(lowerMob,1,25)
1322 end
1323 local resMob = v.origMob
1324 -- threshold for how many corrections
1325 local resDist = 4
1326 local fnd = false
1327 sql_bast = [[select mob from mob_areas where area = "]] .. v.areaId .. [["]]
1328 for row in db_bast:nrows(sql_bast) do
1329 local distance = EditDistance(row.mob,lowerMob)
1330 --DebugNote("EditDist : " .. row.mob .. " --- " .. lowerMob .. " =" .. distance)
1331 if(distance <= tonumber(resDist)) then
1332 fnd = true
1333 DebugNote(lowerMob.." ~~~ ".. row.mob)
1334 if(tonumber(resDist) > 0 or (stringlength > math.abs(string.len(row.mob)-string.len(lowerMob)) or string.match(lowerMob,row.mob)~=nil)) then
1335 resMob = row.mob
1336 DebugNote("resMob -> "..resMob)
1337 resDist = distance
1338 stringlength = math.abs(string.len(row.mob)-string.len(lowerMob))
1339 end
1340 end
1341 end
1342 if fnd then
1343 v.mob = resMob
1344 v.distance = resDist
1345 else
1346 v.distance = -1
1347 end
1348 end
1349 --Note("orig mob: " .. v.origMob .. " final name: " .. v.mob .. " distance: " .. v.distance)
1350 end
1351 --db_bast:close()
1352 end
1353 --------- END: guess mob name ---------
1354
1355 --------- BEGIN: add mobcount ---------
1356
1357 local mob_count = 0
1358 if has_bast == 1 then
1359 local sql_bast = ""
1360 --db_bast = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
1361 for i, v in ipairs (list) do
1362 if not v.is_clean then
1363
1364 --sql_bast = [[where mk.name like '%]] .. v.origMob .. [[%']]
1365 --sql_bast = [[where mk.name like "%]] .. v.mob .. [[%"]]
1366 --sql_bast = [[where mk.name like '%]] .. (string.gsub (v.origMob, "'", "''")) .. [[%']]
1367 sql_bast = [[where mk.name = ]] .. fixsql(v.origMob)
1368 sql_bast = sql_bast .. " and " .. [[mk.area = "]] .. v.areaId .. [["]]
1369 if type == "room" then
1370 sql_bast = sql_bast .. " and " .. [[mk.room_id = "]] .. v.where .. [["]]
1371 end
1372
1373 sql_bast = [[select count(*) as kills, count(distinct mk.room_id) as rooms, max(mk.room_id) as max_rm_id
1374 from mobkills mk]] .. "\n" ..
1375 sql_bast
1376
1377 --Note(sql_bast)
1378 -- update mob killed count
1379 for row in db_bast:nrows(sql_bast) do
1380 v.bast_kills = row.kills
1381 if row.rooms == 1 then
1382 v.known_room = row.max_rm_id
1383 end
1384 --Note(row.kills .. " " .. tostring(row.rooms) .. " " .. tostring(row.max_rm_id))
1385 end
1386 end -- clean check
1387 end -- end for
1388 --db_bast:close()
1389
1390
1391 end
1392
1393 --------- END: add mobcount ---------
1394
1395 --------- BEGIN: group duplicate areas and sort ---------
1396
1397 for i, v in ipairs (list) do
1398 local cnt = 0
1399 for k, m in ipairs(list) do
1400 if v.origMob == m.origMob and v.where == m.where then
1401 cnt = cnt + 1
1402 if v.bast_kills > m.bast_kills then
1403 m.sortId = v.areaId
1404 else
1405 v.sortId = m.sortId
1406 end
1407 end
1408 end
1409 if cnt > 1 then
1410 v.is_multi_area = 1
1411 end
1412 v.is_clean = true
1413 end
1414
1415 -- sort
1416
1417 --[[ show current list
1418 for i,v in ipairs(list) do
1419
1420 Note(v.origMob .. " " .. v.qty .. " " .. v.areaId .. " " .. v.sortId .. " " .. v.bast_kills .. " " .. v.type .. ": " .. i)
1421 end
1422 ]]
1423
1424 table.sort(list, sort_cp_list2)
1425
1426 if has_bast == 1 then
1427 db_bast:close()
1428 end
1429
1430 end
1431 --------- END: group duplicate areas and sort ---------
1432
1433 function print_rooms_areas(list, command)
1434
1435 DebugNote("print_rooms_areas:" .. command .. ":" .. #list)
1436
1437 --reset signature for next search
1438 lastMobSignature = ""
1439
1440
1441 if (USER_show_help == "true") then
1442 ColourNote("Gray", "", "Type '" .. command .. " <Index>' or click link, to go to that item")
1443 ColourNote("Gray", "", " Index Target - Location")
1444 ColourNote("Gray", "", "------------------------------------------------------------------------------")
1445 end
1446
1447 local index = 0
1448 for key, value in ipairs(list) do
1449 local skip = false
1450 local multi = ""
1451 index = index + 1
1452 local qty = ""
1453 if (value.qty > 1) then
1454 qty = string.format("%s * ", value.qty)
1455 end
1456
1457 local mobText = qty .. value.mob
1458 --Note(tostring(value.origMob) .. " " .. tostring(value.sortId) .. " " .. tostring(value.mob))
1459 --local mobText = tostring(value.origMob) .. " " .. value.is_multi_area .. " " .. tostring(value.mob) .. " " .. value.type
1460
1461 local origMob = ""
1462 local include_orig = false
1463 if value.distance == -1 then
1464 --origMob = " d: Unknown"
1465 --include_orig = false
1466 origMob = " unknown"
1467 include_orig = true
1468 elseif value.origMob ~= value.mob and value.distance > 3 then
1469 --origMob = " Dist :" .. tostring(value.origMob) .. " " .. tostring(value.distance)
1470 origMob = " d: " .. tostring(value.distance) .. " " .. tostring(value.origMob)
1471 include_orig = true
1472 elseif value.origMob ~= value.mob and value.distance > 0 then
1473 --origMob = " Dist:" .. tostring(value.distance)
1474 origMob = " d: " .. tostring(value.distance)
1475 include_orig = true
1476 end
1477 -- build the kill count info off the bast database
1478 local display_kills = tostring(value.bast_kills)
1479 --[[
1480 if value.distance == -1 then
1481 display_kills = -1
1482 end
1483 ]]
1484 -- build the output for room and area
1485 local bast_len = 1
1486 if value.type == "area" then bast_len = 12 end
1487 local bast = padRight(" k: " .. display_kills ,bast_len, " ")
1488
1489 local deadFlag = false
1490 if (value.isDead ~= nil and value.isDead ~= "") then
1491 mobText = mobText .. " [Dead]"
1492 deadFlag = true
1493 end
1494 --zhal
1495 --DebugNote("xcp_index_line_end:" .. value.mob)
1496 local link
1497 local color
1498 if (value.type == "area") then
1499 link = string.format("~~ %s %s - %s",
1500 padRight(key, 6, " "),
1501 padRight(mobText, 20, " "),
1502 padRight(value.areaId, 12, " ")
1503 )
1504
1505 --link = string.format("~~~ %s %s - %s", padRight(key, 6, " "), padRight(mobText, 20, " "), padRight(value.areaId, 12, " "))
1506 if (deadFlag == false) then
1507 color = "Snow"
1508 else
1509 color = "DimGray"
1510 end
1511 elseif (value.type == "room") then
1512 link = string.format("~~ %s %s - '%s' (%s) - %s [%s-%s]",
1513 padRight(key, 6, " "),
1514 padRight(mobText, 20, " "),
1515 value.roomName,
1516 padRight(value.roomId, 5, " "),
1517 value.areaId,
1518 value.min, value.max
1519 )
1520 if (deadFlag == false) then
1521 color = "lightblue"
1522 else
1523 color = "DimGray"
1524 end
1525 else -- unknown
1526 link = string.format("~ %s%s - '%s' is Unknown",
1527 padRight(key, 5, " "),
1528 padRight(mobText, 26, " "),
1529 value.roomName
1530 )
1531 if (deadFlag == false) then
1532 color = "Crimson"
1533 else
1534 color = "DarkRed"
1535 end
1536 end
1537
1538 -- create colours for cp/gq list outut default will be dead and you are not in current area
1539 local cDefault, cMobName, cRoomName,cRoomId,cAreaId,cMinMax,cBast,cNotes, cBackground =
1540 "DimGray", "DimGray", "DimGray", "DimGray", "DimGray", "DimGray", "DimGray", "DimGray", "black"
1541 -- what you see if the person isn't dead
1542 if (deadFlag == false) then
1543 cDefault = "white"
1544 cMobName = "white"
1545 cRoomName = "orange"
1546 cRoomId = "yellow"
1547 cAreaId = "lime"
1548 cMinMax = "snow"
1549 cBast = "slateblue"
1550 cNotes = "linen"
1551 cBackground = "black"
1552 end
1553 local noUnderline = true
1554 -- override if in current area
1555 if (currentRoom.areaid == value.areaId) and (deadFlag == false) then
1556 cMobName = "yellow"
1557 cRoomName = "lime"
1558 cAreaId = "white"
1559 --noUnderline = false
1560 end
1561
1562 if value.type ~= "room" and value.type ~= "area" then
1563 -- must be unknown
1564 --Note(value.mob .. " " .. value.type)
1565 Hyperlink(command .. " " .. key, link, "Start CP item " .. key, color, cBackground, 0, noUnderline)
1566 else
1567
1568 Hyperlink(command .. " " .. key, "~ " .. padRight(key, 5, " "), "Start CP item " .. key, cDefault, cBackground, 0, noUnderline)
1569
1570 Hyperlink(command .. " " .. key, padRight(mobText, 26, " "), "Start CP item " .. key, cMobName, cBackground, 0, noUnderline)
1571
1572 -- build output for just room
1573 if (value.type == "room") then
1574
1575 Hyperlink(command .. " " .. key, " - " .. padRight(value.areaId, 0, " "), "Start CP item " .. key, cAreaId, cBackground, 0, noUnderline)
1576
1577 Hyperlink(command .. " " .. key, " - '" .. value.roomName .. "'", "Start CP item " .. key, cRoomName, cBackground, 0, noUnderline)
1578
1579 Hyperlink(command .. " " .. key, " " .. padRight(" (" .. value.roomId .. ")", 5, " "), "Start CP item " .. key, cRoomId, cBackground, 0, noUnderline)
1580
1581
1582 local min_max = ""
1583 if (value.type == "room") then
1584 min_max = " [" .. value.min .. "-" .. value.max .. "]"
1585 end
1586 Hyperlink(command .. " " .. key, min_max, "Start CP item " .. key, cMinMax, cBackground, 0, noUnderline)
1587 if has_bast == 1 then
1588 Hyperlink(command .. " " .. key , bast, "Start CP item " .. key, cBast, cBackground, 0, noUnderline)
1589 end
1590
1591 -- build output for just area
1592 elseif value.type == "area" then
1593
1594 Hyperlink(command .. " " .. key, " - " .. padRight(value.areaId, 12, " "), "Start CP item " .. key, cAreaId, cBackground, 0, noUnderline)
1595 if has_bast == 1 then
1596 Hyperlink(command .. " " .. key , bast, "Start CP item " .. key, cBast, cBackground, 0, noUnderline)
1597 end
1598
1599 Hyperlink("roomnote area " .. value.areaId , " [notes]", "Show notes for " .. key, cNotes , cBackground, 0,noUnderline)
1600 end
1601 if include_orig then
1602 Hyperlink(command .. " " .. key , origMob, "Start CP item " .. key, cBast, cBackground, 0, noUnderline)
1603 end
1604 end
1605 print("")
1606
1607 if currentRoom.roomid == value.roomId then
1608 ColourNote("darkorange", "", " You are in room (","yellow","",value.roomId,"DarkOrange","",") for mob: ","lime","", value.mobText)
1609 end
1610 end
1611
1612 if (index == 0) then
1613 ColourNote("darkorange", "", " No campaign items to show.")
1614 end
1615
1616 if (USER_show_help == "true") then
1617 ColourNote("Gray", "", "------------------------------------------------------------------------------")
1618 end
1619
1620 end
1621
1622
1623 function xcp_index_line_end(name, line, wildcards)
1624 if #cpList > 0 then clean_list(cpList) end
1625 DebugNote("xcp_index_line_end")
1626
1627 EnableTrigger("trg_xcp_line", false)
1628 EnableTrigger("trg_xcp_line_end", false)
1629
1630 if (xcp_flag == false) then
1631 return
1632 end
1633 xcp_flag = false
1634 if name == "xcp_not_on_cp" or name == "xcp_wait_on_cp" then
1635 -- not on a campaign based on these messages after requesting one
1636 onCp = false
1637 else
1638 -- add by Zhal
1639 --[[
1640 if #cpList > 0 then
1641 -- table.sort(cpList, sort_cp_list)
1642 end
1643 ]]
1644
1645 print_rooms_areas(cpList, "xcp")
1646 end
1647
1648 -- broadcast this data for other plugins to consume
1649 local ser = serialize.save_simple(cpList)
1650 --print(ser)
1651 BroadcastPlugin(669, ser)
1652
1653 end
1654
1655
1656 function goto_number(name, line, wildcards)
1657 DebugNote("goto_number: " .. wildcards.id)
1658
1659 if (wildcards.id == nil or wildcards.id == "") then
1660 gotoIndex = 1
1661 else
1662 gotoIndex = tonumber(wildcards.id)
1663 end
1664
1665 if (gotoList[gotoIndex] ~= nil) then
1666 if (tonumber(gotoList[gotoIndex]) == nil) then
1667 -- go to an area
1668 Execute("xrt " .. gotoList[gotoIndex])
1669 else
1670 --Note("other")
1671 DebugNote("goto_number matched room: " .. tostring(gotoList[gotoIndex]))
1672 next_room = gotoList[gotoIndex]
1673 goto_roomid(gotoList[gotoIndex])
1674 end
1675 else
1676 ColourNote("darkorange", "", "No destination exists")
1677 end
1678 end
1679
1680 function goto_roomid(roomid)
1681
1682 local dest_in_vidblain = is_vidblain_area(roomid)
1683 local both_in_vidblain = dest_in_vidblain and is_vidblain_area(currentRoom.roomid)
1684
1685
1686 if (dest_in_vidblain == true and both_in_vidblain == false) then
1687 Execute("xmapper move 11910")
1688 Execute("enter hole")
1689
1690 local func = function() Execute("xmapper move " .. roomid) end
1691 execute_in_area("vidblain_hack", "vidblain", func)
1692
1693 else
1694 Execute("xmapper move " .. roomid)
1695 end
1696 end
1697
1698 local is_vidblain_area_sql =
1699 "SELECT area " ..
1700 "FROM rooms " ..
1701 "WHERE uid = %s "
1702
1703 function is_vidblain_area(roomid)
1704
1705 if (USER_check_vidblain == "false") then
1706 return false
1707 end
1708
1709 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
1710 local db = assert(sqlite3.open(worldPath .. ".db"))
1711
1712 local select = string.format (is_vidblain_area_sql, fixsql(roomid))
1713 for row in db:nrows(select) do
1714 --Note(row.area)
1715 local areaid = row.area
1716 if (areaid == "vidblain" or
1717 areaid == "imperial" or
1718 areaid == "darklight" or
1719 areaid == "sendhian" or
1720 areaid == "omentor") then
1721
1722 db:close_vm()
1723 return true
1724 end
1725 end
1726 db:close_vm()
1727
1728 return false
1729
1730 end
1731
1732 function goto_next(name, line, wildcards)
1733 DebugNote("next:" .. next_room .. ":" .. currentRoom.roomid)
1734 if (tonumber(next_room) == tonumber(currentRoom.roomid)) then
1735 gotoIndex = gotoIndex + 1
1736 end
1737
1738 if (gotoList[gotoIndex] ~= nil) then
1739
1740 ColourNote("darkorange", "", "Goto - " .. gotoIndex .. " of " .. #gotoList)
1741 next_room = gotoList[gotoIndex]
1742 Execute("xmapper move " .. next_room)
1743 else
1744 ColourNote("darkorange", "", "No destination exists")
1745 end
1746 end
1747
1748 function goto_cp(name, line, wildcards)
1749
1750 listIndex = tonumber(wildcards.index)
1751 mode = "cp"
1752
1753 DebugNote("goto_cp:" .. wildcards.index)
1754
1755 BroadcastPlugin(670, "cp")
1756
1757 goto_list_item(cpList, listIndex)
1758
1759 end
1760
1761 -- v3 --
1762 function goto_gq(name, line, wildcards)
1763
1764 gqIndex = tonumber(wildcards.index)
1765 mode = "gq"
1766
1767 DebugNote("goto_gq:" .. wildcards.index)
1768
1769 BroadcastPlugin(670, "gq")
1770
1771 goto_list_item(gqList, gqIndex)
1772
1773 end
1774
1775 function goto_list_item(list, index)
1776
1777 -- reset room list
1778 gotoList = {}
1779 gotoIndex = 1
1780
1781 local localItem = list[index]
1782 local localRoom = currentRoom
1783
1784 if (localItem ~= nil and localRoom ~= nil and localRoom.areaid ~= nil) then
1785
1786 -- send this mob name to S&D plugin
1787 -- why is localitem blank sometimes?
1788 DebugTPrint("goto_list_item - localItem", localItem)
1789
1790 if (localItem.type == "area") then
1791 DebugNote("area type")
1792 remote_guess_mob_name(localItem.mob, localItem.areaId, true)
1793 local func = function()
1794 -- added once gq mobs became eligible to hunt i.e., fooling hunt trick
1795 if #gqList == 0 or onGq == false then
1796 Execute("x_ht " .. localItem.mob)
1797 --Execute("x_qw " .. localItem.mob)
1798 else
1799 -- michael
1800 Execute("x_qw " .. localItem.mob)
1801 end
1802 end
1803
1804
1805 if localItem.landingRoom > 0 then
1806 Note("gooo mapper goto " .. localItem.landingRoom)
1807 Execute("mapper goto " .. localItem.landingRoom)
1808
1809 elseif (localRoom.areaid ~= localItem.areaId) then
1810 Execute("xrt " .. localItem.areaId)
1811 end
1812
1813 execute_in_area("goto_list_item_area", localItem.areaId, func)
1814
1815 else -- "room"
1816 DebugNote("room type")
1817 remote_guess_mob_name(localItem.mob, localItem.areaId, true)
1818
1819 search_rooms(localItem.roomName .. "|" .. localItem.areaId, "area", localItem.mob)
1820
1821 end
1822 else
1823 ColourNote("darkorange", "", "No item exists, or data busy (try again)")
1824 end
1825
1826 end
1827
1828 local xrun_to_sql_uid =
1829 "SELECT r.uid, r.name as room, r.area " ..
1830 "FROM rooms r " ..
1831 "WHERE r.area like %s " ..
1832 "ORDER BY r.name "
1833
1834 local xrun_to_sql_name =
1835 "SELECT r.uid, r.name as room, r.area " ..
1836 "FROM rooms r " ..
1837 "INNER JOIN areas a ON a.uid = r.area " ..
1838 "WHERE r.area like %s OR a.name like %s " ..
1839 "ORDER BY r.name "
1840
1841 function xrun_to(name, line, wildcards)
1842 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
1843 local db = assert(sqlite3.open(worldPath .. ".db"))
1844
1845 -- HACK for ftii
1846 if (wildcards[1] == "ft2") then
1847 wildcards[1] = "ftii"
1848 end
1849
1850 -- Check for xset marked room
1851 local startRoom = get_start_room(wildcards[1])
1852 if (startRoom ~= -1) then
1853 -- start room has been marked, we are done here
1854 ColourNote("darkorange", "", "x-runto (" .. startRoom .. ") xset marked as start room")
1855 goto_roomid(startRoom)
1856 else
1857 -- Room has not been marked for the area
1858 -- Search mapper DB for room with lowest id for the area
1859
1860 -- try exact hit first
1861 local select = string.format (xrun_to_sql_uid, fixsql(wildcards[1]))
1862 DebugNote("xrun_to (1)- " .. select)
1863
1864 for row in db:nrows(select) do
1865 ColourNote("darkorange", "", "x-runto (" .. row.uid .. ") " .. row.room .. " in " .. row.area .. " - exact match")
1866
1867 goto_roomid(row.uid)
1868
1869 db:close_vm()
1870 return
1871 end
1872 db:close_vm()
1873
1874 -- try a wildcard match
1875 local like = fixsql("%" .. wildcards[1] .. "%")
1876 select = string.format (xrun_to_sql_name, like, like)
1877 DebugNote("xrun_to (2)- " .. select)
1878
1879 for row in db:nrows(select) do
1880 ColourNote("darkorange", "", "x-runto (" .. row.uid .. ") " .. row.room .. " in " .. row.area .. " - 'like' match")
1881
1882 goto_roomid(row.uid)
1883
1884 db:close_vm()
1885 return
1886 end
1887 db:close_vm()
1888
1889 ColourNote("darkorange", "", "No matching rooms found. Using aardwolf runto...")
1890 Execute("xmapper move 32418") -- recall
1891 Execute("runto " .. wildcards[1])
1892 end
1893 end
1894
1895 function xset_pk(name, line, wildcards)
1896
1897 if (showPK == "true") then
1898 showPK = "false"
1899 else
1900 showPK = "true"
1901 end
1902
1903 SetVariable("showPK", showPK)
1904 ColourNote("DarkOrange", "", "Show PK room flag : " .. showPK)
1905
1906 end
1907
1908 function xset_to_mark(name, line, wildcards)
1909 areaStartRooms[currentRoom.areaid] = { areaname = currentRoom.areaname, roomid = currentRoom.roomid }
1910 ColourNote("darkorange", "", currentRoom.roomid .. " set as starting room for " .. currentRoom.areaid)
1911 SetVariable("areaStartRooms", serialize.save_simple(areaStartRooms))
1912 end
1913
1914 function get_start_room(area)
1915 local cleanedArea = string.lower(area)
1916 if (areaStartRooms[cleanedArea] ~= nil) then
1917 -- exact match on area id
1918 return areaStartRooms[cleanedArea].roomid
1919 end
1920
1921 for key, val in pairs(areaStartRooms) do
1922 if (string.match(string.lower(key), cleanedArea) ~= nil) then
1923 -- string match on key
1924 return val.roomid
1925 elseif val.areaname ~= nil and (string.match(string.lower(val.areaname), cleanedArea) ~= nil) then
1926 -- string match on area name
1927 return val.roomid
1928 end
1929 end
1930
1931 -- found nothing
1932 return -1
1933 end
1934
1935 ---- room notes --------
1936
1937 function room_note_area(name, line, wildcards)
1938 if (wildcards.areaid == "") then
1939 get_notes(currentRoom.areaid, nil)
1940 else
1941 get_notes(wildcards.areaid, nil)
1942 end
1943 end
1944
1945 function room_note(name, line, wildcards)
1946 get_notes(nil, currentRoom.roomid)
1947 end
1948
1949 function get_notes(areaid, roomid, text_only)
1950
1951 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
1952 local db = assert(sqlite3.open(worldPath .. ".db"))
1953
1954 local sql = " SELECT b.uid, b.notes "
1955 sql = sql .. " FROM bookmarks b "
1956 if (areaid ~= nil) then
1957 sql = sql .. " INNER JOIN rooms r ON b.uid = r.uid "
1958 sql = sql .. " WHERE r.area = " .. fixsql(areaid)
1959 else
1960 sql = sql .. " WHERE b.uid = " .. fixsql(roomid)
1961 end
1962 sql = sql .. " ORDER BY b.uid "
1963 DebugNote(sql)
1964
1965 local index = 0
1966
1967 if (areaid ~= nil) then
1968 Simulate("\nNotes for " .. getAreaName(areaid) .. "\n")
1969 end
1970
1971 for row in db:nrows(sql) do
1972 index = index + 1
1973 if (text_only == true) then
1974 local line = string.format(" note:'%s'", row.notes)
1975 Hyperlink("xmapper move " .. row.uid, line, "go to room " .. row.uid, "lightblue", "black", 0, true)
1976 else
1977 local line = string.format(" (%s) %s", row.uid, row.notes)
1978 Hyperlink("xmapper move " .. row.uid, line, "go to room " .. row.uid, "lightblue", "black", 0, true)
1979 print("")
1980 end
1981 end
1982 db:close_vm()
1983 if (areaid ~= nil and index == 0 and text_only ~= true) then
1984 Simulate("\tNo notes.\n")
1985 end
1986 end
1987
1988
1989
1990 function getRoomByMob(mobName)
1991 -- unused
1992 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
1993 local db = assert(sqlite3.open(worldPath .. ".db"))
1994
1995 local sql = "SELECT roomid, mobname, count "
1996 sql = sql .. "FROM mobs "
1997 sql = sql .. "WHERE mobname = %s "
1998 sql = sql .. "ORDER BY count desc "
1999
2000 for row in db:nrows(string.format (sql, fixsql(uid))) do
2001 db:close_vm()
2002 return row.name
2003 end
2004 db:close_vm()
2005 end
2006
2007
2008 function getAreaName(uid)
2009 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2010 local db = assert(sqlite3.open(worldPath .. ".db"))
2011
2012 local sql = "SELECT name FROM areas WHERE uid = %s"
2013 for row in db:nrows(string.format (sql, fixsql(uid))) do
2014 db:close_vm()
2015 return row.name
2016 end
2017 db:close_vm()
2018
2019 return uid
2020 end
2021
2022 function getAreaUid(name)
2023
2024 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2025 local db = assert(sqlite3.open(worldPath .. ".db"))
2026
2027 local sql = "SELECT uid FROM areas WHERE name = %s order by uid "
2028
2029 local areas = {}
2030 local index = 0
2031 DebugNote("getAreaUid:" .. fixsql(name))
2032 for row in db:nrows(string.format (sql, fixsql(name))) do
2033 DebugNote(row.uid .. ":" .. name)
2034 index = index + 1
2035 areas[index] = {uid = row.uid, name = name}
2036 end
2037
2038 db:close_vm()
2039 return areas
2040 end
2041
2042
2043 function map_area(name, line, wildcards)
2044 search_rooms(wildcards.loc, 'area', wildcards.mob)
2045 end
2046
2047 function map_area_all(name, line, wildcards)
2048 search_rooms(wildcards.loc .. "|all", 'all', wildcards.mob)
2049 end
2050
2051 local search_rooms_sql =
2052 "SELECT r.uid as uid, r.name as name, info, r.area as area, " ..
2053 "ifnull(a.name, r.area) as area_name, 1 as DisplayOrder " ..
2054 "FROM rooms r " ..
2055 "LEFT OUTER JOIN areas a ON r.area = a.uid " ..
2056 "WHERE r.name = %s " ..
2057 "AND (%s = 'all' OR (a.name = %s OR r.area = %s)) " ..
2058
2059 "UNION " ..
2060
2061 "SELECT r.uid, r.name, info, r.area, " ..
2062 "ifnull(a.name, r.area) as area_name, 0 as DisplayOrder " ..
2063 "FROM rooms r " ..
2064 "LEFT OUTER JOIN areas a ON r.area = a.uid " ..
2065 "WHERE r.name <> %s " ..
2066 "AND r.name LIKE %s " ..
2067 "AND (%s = 'all' OR (a.name = %s OR r.area = %s)) " ..
2068 "ORDER BY Area, DisplayOrder DESC "
2069
2070 function search_rooms(room, searchType, fullMobName)
2071
2072 DebugNote("search_rooms(" .. room .."," .. searchType .. "," .. fullMobName .. ")")
2073
2074 if (room == nil or room == "") then
2075 Note("map_area() error : room is not known")
2076 return
2077 end
2078
2079 -- room|area
2080 local parts = split(room, "[^|]+") -- pipe delimited
2081 local room = parts[1]
2082 local area_id
2083 if (#parts == 2) then
2084 area_id = parts[2]
2085 else
2086 if (currentRoom ~= nil) then
2087 area_id = currentRoom.areaid
2088 else
2089 ColourNote("darkorange", "", "Area not known, falling back to mapper list")
2090 Execute("mapper list " .. parts[1])
2091 end
2092 end
2093
2094 if (room == nil) then
2095 Note("map_area() - Room not known")
2096 return
2097 end
2098
2099 like = "%"..room.."%"
2100
2101 -- i forget what this does? Strip out a leading " ?
2102 --if string.sub(room,1,1) == "\"" and string.sub(room,-1) == "\"" then
2103 -- like = string.sub(room,2,-2)
2104 --end
2105
2106 local select = string.format(search_rooms_sql,
2107 fixsql(room),
2108 fixsql(area_id),
2109 fixsql(area_id),
2110 fixsql(area_id),
2111 fixsql(room),
2112 fixsql(like),
2113 fixsql(area_id),
2114 fixsql(area_id),
2115 fixsql(area_id))
2116 DebugNote(select)
2117
2118 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2119 local db = assert(sqlite3.open(worldPath .. ".db"))
2120
2121 local results = {}
2122 local roomid_list = {}
2123
2124 for row in db:nrows(select) do
2125 -- sanitize text room ids for "unmappable" rooms that are now being mapped
2126 local id = (tonumber(row.uid) or -1)
2127 -- make safe against bad dbs
2128 local areaid_lookup = row.area or row.area_name
2129 local full_mobName = string.lower(fullMobName)
2130 local bast_kills = mob_count(full_mobName,areaid_lookup,id)
2131 --Note(fullMobName .. " " .. areaid_lookup .. " " .. id)
2132 results[#results + 1] = {
2133 uid = id,
2134 name = row.name,
2135 info = row.info,
2136 area = row.area_name,
2137 areaid = areaid_lookup,
2138 mob = fullMobName,
2139 bast_kills = bast_kills
2140
2141 }
2142 -- make a list of room ids zhal this goes nowhere
2143 if (id > 0) then
2144 roomid_list[#roomid_list + 1] = id
2145 end
2146
2147 end -- finding rooms
2148 db:close_vm()
2149
2150
2151 local mob_mapping = {}
2152
2153 local freq_total = mob_mapping[-1] or 0
2154 DebugNote("freq_total:" .. freq_total)
2155
2156 -- add mob to room mapping
2157 for key, value in ipairs(results) do
2158
2159 local freq = mob_mapping[value.uid]
2160 if (freq ~= nil) then
2161 value.freq = math.floor((freq / freq_total) * 100)
2162 else
2163 value.freq = 0
2164 end
2165 end
2166
2167 table.sort(results, sort3_func)
2168
2169 print_rooms(results)
2170 end
2171
2172 function IPRINT_ROOMS(json)
2173 -- load serialize.save_simple data
2174 luastmt = "gPrintRooms = " .. json
2175 assert (loadstring (luastmt or "")) ()
2176
2177 print_rooms(gPrintRooms)
2178 end
2179
2180 -- uses results{ areaid, area, info, name, uid, freq }
2181 function print_rooms(results)
2182 -- print results
2183 gotoList = {}
2184 mapper_area_index = 0
2185 local last_area = ""
2186
2187 DebugTPrint("results", results)
2188
2189 if (USER_show_help == "true") then
2190 ColourNote("Gray", "", "Type 'go <Index>' or click link, to go to that room")
2191 ColourNote("Gray", "", " Index Room Name (uid)")
2192 ColourNote("Gray", "", "-------------------------------------------------")
2193 end
2194
2195 for key, value in ipairs(results) do
2196 DebugNote("area: " .. value.areaid )
2197 --Note("gmcp vs script " .. tostring(currentRoom.roomid) .. " vs " .. tostring(value.uid))
2198 -- create colors
2199 -- this is default, which is when you are in the same room
2200 local cBackground,cIndex,cRoomName,cRoomId,cBast,cDirections = "whitesmoke", "black", "black", "black", "black", "black"
2201 if tostring(currentRoom.roomid) ~= tostring(value.uid) then
2202 -- you are not in the same room
2203 cBackground = "black"
2204 cIndex = "white"
2205 cRoomName = "white"
2206 cRoomId = "yellow"
2207 cBast = "white"
2208 cDirections = "white"
2209 end
2210
2211 if (last_area ~= value.areaid) then
2212 -- michael
2213 local min = (area_range[value.area_name] or {min = 0}).min
2214 local max = (area_range[value.area_name] or {max = 300}).max
2215 local min_max = "[" .. min .. "-" .. max .. "]"
2216
2217 if (mapper_area_index == 0) then
2218 -- first line
2219 -- mapper_area_index <-- idk why bast had thi in the next line
2220 local areaLine = string.format(" %s %s",min_max, value.areaid)
2221 -- header that shows above hunt trick. No need to change color, used to be silver
2222 Hyperlink("go " .. mapper_area_index, areaLine, "go to area (go) " .. value.areaid, "darkorange", "black", 0)
2223 gotoList[mapper_area_index] = value.areaid
2224 mapper_area_index = mapper_area_index + 1
2225 else
2226 Note("")
2227 -- when multiple areas appear, e.g., search all database and multiple areas appear (xmall blah)
2228 -- could make this brighter and maybe even add lvl range
2229 -- area_range.mine and max
2230 --local areaLine = string.format("~~ %s", value.areaid)
2231 local areaLine = string.format(" %s %s",min_max, value.areaid)
2232 Hyperlink("xrt " .. value.areaid, areaLine, "go to area (xrt) " .. value.areaid, "darkorange", "black", 0)
2233 end
2234 print("")
2235 last_area = value.areaid
2236 end
2237
2238 -- v3 --
2239 local isPK = string.find((value.info or ""), "pk") ~= nil
2240 local isPKText = " "
2241 DebugNote("isPK: " .. tostring(isPK))
2242 if (isPK == true and showPK == "true") then
2243 isPKText = "[PK] "
2244 end
2245
2246 -- this is the first thing on the left, the ~~ #
2247 local line1 = string.format("~~ %s ",
2248
2249 padRight(mapper_area_index, 3, " "))
2250
2251 Hyperlink("go " .. mapper_area_index, line1, "go to item ht " .. mapper_area_index, cIndex, cBackground, 0,true)
2252
2253 local line2 = string.format("%s (%s) %s",
2254 padRight(string.gsub(value.name, "@[a-zA-Z]", ""), 20, " "),
2255 value.uid,value.bast_kills)
2256
2257 -- showed as room results and Quick-Where
2258 -- v4 --
2259 -- color isn't changed
2260 local namePad = 25
2261 if isPK then
2262 Hyperlink("go " .. mapper_area_index, isPKText, "go to item (pk) " .. mapper_area_index, "red", cBackground, 0, true)
2263 namePad = 20
2264 end
2265
2266 local noUnderline = true
2267 local line10 = padRight(string.gsub(value.name, "@[a-zA-Z]", ""), namePad, " ")
2268 local line11 = padRight(" (" .. value.uid .. ")", 2, " ")
2269 local bast = padRight(" Cnt: " .. tostring(value.bast_kills),1, " ")
2270
2271 -- room name
2272 Hyperlink("go " .. mapper_area_index, line10,"go to item line (line 2.2) " .. mapper_area_index,
2273 cRoomName, cBackground, 0, noUnderline)
2274
2275 -- room id #
2276 Hyperlink("go " .. mapper_area_index, line11 , "go to item line (line 2.2) " .. mapper_area_index,
2277 cRoomId, cBackground, 0, noUnderline)
2278
2279 if has_bast == 1 then
2280 -- count of bast kills
2281 Hyperlink("go " .. mapper_area_index, bast, "go to item line (line 2.2) " .. mapper_area_index,
2282 cBast, cBackground, 0,noUnderline)
2283 end
2284 -- original
2285 --Hyperlink("go " .. mapper_area_index, line2, "go to item line (line 2.2) " .. mapper_area_index, "lightblue", "black", 0,noUnderline)-
2286
2287 -- this is at the right of every line. shows speedwalk but doesnt go
2288 Hyperlink("mapper where " .. value.uid,
2289 string.format("%-3s"," {?}"),
2290 "click for speedwalk to this room",
2291 cDirections,
2292 cBackground,
2293 0, noUnderline)
2294 gotoList[mapper_area_index] = value.uid
2295
2296 -- show room notes
2297 DebugNote("get note : " .. value.uid)
2298 get_notes(nil, value.uid, true)
2299
2300 print("")
2301 --ColourTell("","","\n")
2302
2303 mapper_area_index = mapper_area_index + 1
2304 end
2305
2306
2307 if (mapper_area_index == 0) then
2308 ColourNote("darkorange", "", "No matching rooms found.")
2309 end
2310
2311 if (USER_show_help == "true") then
2312 ColourNote("Gray", "", "-------------------------------------------------")
2313 Note("")
2314 end
2315
2316 end
2317
2318 function map_purgeroom (name, line, wildcards)
2319 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2320 local db = assert(sqlite3.open(worldPath .. ".db"))
2321
2322 Note(string.format ("delete from exits WHERE fromuid = %s;", fixsql(currentRoom.roomid)))
2323 dbcheck (db:execute (string.format ("delete from exits WHERE fromuid = %s;", fixsql(currentRoom.roomid))))
2324 Note(string.format ("delete from exits WHERE touid = %s;", fixsql(currentRoom.roomid)))
2325 dbcheck (db:execute (string.format ("delete from exits WHERE touid = %s;", fixsql(currentRoom.roomid))))
2326 Note(string.format ("delete from rooms_lookup WHERE uid = %s;", fixsql(currentRoom.roomid)))
2327 dbcheck (db:execute (string.format ("delete from rooms_lookup WHERE uid = %s;", fixsql(currentRoom.roomid))))
2328 Note(string.format ("delete from rooms WHERE uid = %s;", fixsql(currentRoom.roomid)))
2329 dbcheck (db:execute (string.format ("delete from rooms WHERE uid = %s;", fixsql(currentRoom.roomid))))
2330 db:close_vm()
2331
2332 ColourNote("darkorange", "", "Purged room (" .. currentRoom.roomid .. ") from the mapper database.")
2333 end
2334
2335 local cp_simulate_toggle = 0
2336 function cp_simulate(name, line, wildcards)
2337
2338 Simulate("\n")
2339
2340 if (cp_simulate_toggle == 0) then
2341 --Simulate("You still have to kill * a slinky sylph (A corner in the bull pen)\n")
2342 Simulate("You still have to kill * a reoging lotus eater (Land of the Lotus-Eaters)\n")
2343 Simulate("You still have to kill * a satyr (The Labyrinth)\n")
2344 --Simulate("You still have to kill * a A mad bird (On A Pinnacle)\n")
2345 -- swirl good one
2346 --Simulate("You still have to kill * a swirl of orange and purple (Fantasy Creek)\n")
2347 --Simulate("You still have to kill * a swirl of orange and purple (Fantasy Creek)\n")
2348 --Simulate("You still have to kill * a patient drow miner (The Amber Mine)\n")
2349 --Simulate("You still have to kill * a giant mosquito (Jungles of Verume)\n")
2350 -- Simulate("You still have to kill * a giant mosquito (Jungles of Verume)\n")
2351 Simulate("You still have to kill * the head necromancer (Necromancers' Guild)\n")
2352 --Simulate("You still have to kill * a transparent gardener (Garden)\n")
2353 --Simulate("You still have to kill * a burst of anger (Anger and Violence)\n")
2354 Simulate("You still have to kill * a centaur stallion (The Labyrinth)\n")
2355 --Simulate("You still have to kill * a field rat (Inside the Northeast Watchtower)\n")
2356 --Simulate("You still have to kill * a shambling mound (The Labyrinth)\n")
2357 Simulate("You still have to kill * a blo ball (Nearing The Top Of The Pathway)\n")
2358 --Simulate("You still have to kill * an adventurous spelunker (An Underground River)\n")
2359 --Simulate("You still have to kill * a chipmunk (The Labyrinth)\n")
2360 Simulate("You still have to kill * a tall peasant (At the bonfire)\n")
2361 Simulate("You still have to kill * Gunnlod (Gunnlod's Home)\n")
2362 --Simulate("You still have to kill * a repairs troll (Observation stands)\n")
2363 --Simulate("You still have to kill * Michael (Blue Roomee)\n")
2364 Simulate("You still have to kill * Prince Rich'Erd (Sho'aram, Castle in the Sand)\n")
2365 Simulate("You still have to kill * Doctor Cameroon " .. [["]] .. "Rusty" .. [["]] .. " Baboon (Canyon Memorial Hospital)\n")
2366 --Note("You still have to kill * Doctor Cameroon " .. [["]] .. "Rusty" .. [["]] .. " Baboon (Canyon Memorial Hospital)")
2367 cp_simulate_toggle = 1
2368 else
2369
2370 Simulate("You still have to kill * a burst of anger (Anger and Violence)\n")
2371 Simulate("You still have to kill * a shambling mound (The Labyrinth)\n")
2372 Simulate("You still have to kill * a swirl of orange and purple (Fantasy Creek)\n")
2373 Simulate("You still have to kill * a field rat (Inside the Northeast Watchtower)\n")
2374 Simulate("You still have to kill * a transparent gardener (Garden)\n")
2375 Simulate("You still have to kill * a slinky sylph (A corner in the bull pen)\n")
2376 Simulate("You still have to kill * a tall peasant (At the bonfire)\n")
2377 cp_simulate_toggle = 0
2378 end
2379 Simulate("Note: Dead means that the target is dead, not that you have killed it.\n")
2380 Simulate("\n")
2381 Simulate("You have 6 days, 23 hours and 56 minutes left to finish this campaign.\n")
2382 Simulate("\n")
2383
2384 end
2385 function cp_simulate1(name, line, wildcards)
2386
2387 Simulate("\n")
2388
2389 if (cp_simulate_toggle == 0) then
2390 --Simulate("You still have to kill * Isscheburqua (Insanitaria)\n")
2391 Simulate("You still have to kill * a satyr (The Labyrinth)\n")
2392 Simulate("You still have to kill * a rook citizen (Avian Kingdom)\n")
2393 Simulate("You still have to kill * Lea, the farmer's daughter (Farmyard)\n")
2394 Simulate("You still have to kill * a rook citizen (Nesting Home)\n")
2395 Simulate("You still have to kill * a demon school student (The School of Horror)\n")
2396 Simulate("You still have to kill * a hookle fish (Black Lagoon)\n")
2397 Simulate("You still have to kill * Harry (Unknown Tower - Dead)\n")
2398 Simulate("You still have to kill * a former court jester (The Labyrinth)\n")
2399 Simulate("You still have to kill * Parent (The Kitchen)\n")
2400 Simulate("You still have to kill * a wealth redistribution specialist (Empyrean, Streets of Downfall)\n")
2401 Simulate("You still have to kill * the reaching thorns (Eternal Autumn)\n")
2402 Simulate("You still have to kill * Redtooth (Mossflower Wood - Dead)\n")
2403 Simulate("You still have to kill * Castle Guard (Rebellion of the Nix)\n")
2404 Simulate("You still have to kill * Jules (The Amazon Nation)\n")
2405 Simulate("You still have to kill * an earth fiend (The Broken Halls of Horath)\n")
2406 Simulate("You still have to kill * the spirit of Bakarne (The Empire of Aiighialla)\n")
2407 Simulate("You still have to kill * Elfgar Sous-Fled (Some Place)\n")
2408 Simulate("You still have to kill * the heart of a sandstorm (Living Mines of Dak'Tai)\n")
2409 cp_simulate_toggle = 1
2410 else
2411 Simulate("You still have to kill * a former court jester (The Labyrinth)\n")
2412 Simulate("You still have to kill * the heart of a sandstorm (Buried in the Great Desert's unrelenting dunes)\n")
2413 Simulate("You still have to kill * Parent (The Kitchen)\n")
2414 Simulate("You still have to kill * a rhino seraph (A Corridor of Cinnamon and Silver)\n")
2415 Simulate("You still have to kill * A sprite prisoner (A cell)\n")
2416
2417 cp_simulate_toggle = 0
2418 end
2419 Simulate("Note: Dead means that the target is dead, not that you have killed it.\n")
2420 Simulate("\n")
2421 Simulate("You have 6 days, 23 hours and 56 minutes left to finish this campaign.\n")
2422 Simulate("\n")
2423
2424 end
2425 function cp_simulate2(name, line, wildcards)
2426
2427 Simulate("\n")
2428
2429 if (cp_simulate_toggle == 0) then
2430 Simulate("You still have to kill * a practicing demon (The Arena)\n")
2431 Simulate("You still have to kill * Savinga, prince of death (In the clouds)\n")
2432 Simulate("You still have to kill * the cell keeper (A Hallway of Cells)\n")
2433 Simulate("You still have to kill * the ghost (The Silver Volcano)\n")
2434 Simulate("You still have to kill * Gabried, archangel of fire (In the clouds)\n")
2435 Simulate("You still have to kill * a demon berserker (On the Floor of the Arena)\n")
2436 Simulate("You still have to kill * the storm spirit (Storm Ships of Lem-Dagor)\n")
2437 Simulate("You still have to kill * Valefor, prince od theft (The Flying Citadel)\n")
2438 Simulate("You still have to kill * a huge Wave runner sergeant (The Storm Cruiser, Tempest)\n")
2439 Simulate("You still have to kill * a giggling girl (Inside Pumice Library)\n")
2440 Simulate("You still have to kill * a demon soldier (In the Stands surrounding the Arena)\n")
2441 Simulate("You still have to kill * Trey, the Unforgiven (A Hidden Den)\n")
2442 Simulate("You still have to kill * Prince Rich'Erd (Sho'aram, Castle in the Sand)\n")
2443 Simulate("You still have to kill * Doctor Cameroon " .. [["]] .. "Rusty" .. [["]] .. " Baboon (Canyon Memorial Hospital)\n")
2444 cp_simulate_toggle = 1
2445 else
2446 Simulate("You still have to kill * a former court jester (The Labyrinth)\n")
2447 Simulate("You still have to kill * the heart of a sandstorm (Buried in the Great Desert's unrelenting dunes)\n")
2448 Simulate("You still have to kill * a barber (The Labyrinth)\n")
2449 Simulate("You still have to kill * Parent (The Kitchen)\n")
2450 Simulate("You still have to kill * a rhino seraph (A Corridor of Cinnamon and Silver)\n")
2451 Simulate("You still have to kill * A sprite prisoner (A cell)\n")
2452
2453 cp_simulate_toggle = 0
2454 end
2455 Simulate("Note: Dead means that the target is dead, not that you have killed it.\n")
2456 Simulate("\n")
2457 Simulate("You have 6 days, 23 hours and 56 minutes left to finish this campaign.\n")
2458 Simulate("\n")
2459
2460 end
2461 -------- Area level capture -------
2462
2463
2464 --Commander Barcett tells you ' Good luck in your campaign!''
2465
2466 function area_index_start_gag(name, line, wildcards)
2467 DebugNote("area_index_start_gag - " .. wildcards[1] .. ":" .. wildcards[2])
2468 if (wildcards[1] == "0" and wildcards[2] == "298") then
2469 EnableTrigger("trg_area_index_start", true)
2470 EnableTrigger("trg_area_index_line", false)
2471 EnableTrigger("trg_area_index_end", false)
2472 EnableTrigger("trg_area_index_gag1", true)
2473 EnableTrigger("trg_area_index_gag2", true)
2474 else -- not an area index command
2475 EnableTrigger("trg_area_index_start", false)
2476 EnableTrigger("trg_area_index_line", false)
2477 EnableTrigger("trg_area_index_end", false)
2478 EnableTrigger("trg_area_index_gag1", false)
2479 EnableTrigger("trg_area_index_gag2", false)
2480 end
2481 end
2482
2483 function area_index_start(name, line, wildcards)
2484 DebugNote("area_index_start")
2485 EnableTrigger("trg_area_index_start", false)
2486 EnableTrigger("trg_area_index_line", true)
2487 EnableTrigger("trg_area_index_end", true)
2488
2489 area_range = {}
2490
2491 ColourNote("DarkOrange", "", "*** Indexing area levels...")
2492 end
2493
2494 function area_index_line(name, line, wildcards)
2495 DebugNote("area_index_line")
2496
2497 area_range[Trim(wildcards.area)] = {
2498 area = Trim(wildcards.area),
2499 min = tonumber(Trim(wildcards.min)),
2500 max = tonumber(Trim(wildcards.max)),
2501 lock = tonumber(Trim(wildcards.lock)) or 0 }
2502 --tprint(area_range[wildcards.area])
2503
2504 end
2505
2506 function area_index_end(name, line, wildcards)
2507 DebugNote("area_index_end")
2508
2509 EnableTrigger("trg_area_index_start", false)
2510 EnableTrigger("trg_area_index_line", false)
2511 EnableTrigger("trg_area_index_end", false)
2512 EnableTrigger("trg_area_index_gag1", false)
2513 EnableTrigger("trg_area_index_gag2", false)
2514
2515 ColourNote("DarkOrange", "", "*** Area levels indexed!")
2516
2517 DoAfterSpecial(2, "xset resume page size", sendto.execute)
2518
2519 SetVariable("areas_serial", serialize.save( "areas_ser", area_range ))
2520 Execute("cp check")
2521 end
2522
2523 function clean_sql(val)
2524 val = string.gsub(val , "'", "''")
2525 return val
2526 end
2527 -------- GQ ---------
2528 -- v2 --
2529
2530 function capture_gq_line(name, line, args)
2531
2532 EnableTrigger("x_gq_line_end", true)
2533
2534 if (gqList == nil) then
2535 gqList = {}
2536 gqIndex = 1
2537 end
2538
2539 --gqIndex = get_rooms_areas(gqList, gqIndex, wildcards.where, wildcards.mob, wildcards.qty)
2540 get_rooms_areas(gqList, args.where, args.mob, args.qty, "","gq")
2541
2542 end
2543
2544 function capture_gq_line_finished(name, line, wildcards)
2545 DebugNote("capture_gq_line_finished")
2546 EnableTriggerGroup("x_gq", false)
2547
2548 gqList = {}
2549 onGq = false
2550 -- broadcast this data for other plugins to consume
2551 local ser = serialize.save_simple(gqList)
2552 --print(ser)
2553 BroadcastPlugin(667, ser)
2554 end
2555
2556 function capture_gq_line_end(name, line, wildcards)
2557
2558 DebugNote("capture_gq_line_end")
2559
2560 EnableTriggerGroup("x_gq", false)
2561 clean_list(gqList)
2562 --[[
2563 if #gqList > 0 and has_bast == 1 then
2564 table.sort(gqList, sort_cp_list)
2565 end
2566 ]]
2567 print_rooms_areas(gqList, "qq")
2568
2569 if #gqList == 0 then onGq = false end
2570 -- broadcast this data for other plugins to consume
2571 local ser = serialize.save_simple(gqList)
2572 --print(ser)
2573 BroadcastPlugin(667, ser)
2574 end
2575
2576 local test_toggle = 0
2577
2578 function gq_list (name, line, wildcards)
2579
2580 gqList = {}
2581 gqList_old = gqList
2582 gqIndex = 1
2583
2584 EnableTrigger("x_gq_line", true)
2585 onGq = true
2586 if has_bast then
2587 Execute("gq check")
2588 else
2589 Send("gq c")
2590 end
2591 end
2592
2593 function gq_list_simulate (name, line, wildcards)
2594
2595 gqList = {}
2596 gqIndex = 1
2597 onGq = true
2598 EnableTrigger("x_gq_line", true)
2599
2600 if (test_toggle == 0) then
2601 Simulate("\nYou still have to kill 1 * A kicking patient (A FAKE-private room)\n")
2602 Simulate("You still have to kill 1 * A snoring patient (Canyon Memorial Hospital)\n")
2603 Simulate("You still have to kill 1 * Sergeant Steel (The Armory)\n")
2604 Simulate("You still have to kill 1 * An abominable snowman (The Snowy Path)\n")
2605 Simulate("You still have to kill 1 * The senior assassin (Assassins' Scrying Chamber)\n")
2606 Simulate("You still have to kill 1 * Lord Kyron (The DarkLight)\n")
2607 Simulate("You still have to kill 1 * Buck (Imperial Nation)\n")
2608 Simulate("You still have to kill 1 * Bjorn (Realm of the Firebird)\n")
2609 Simulate("You still have to kill 2 * a crow (Realm of the Firebird)\n")
2610 Simulate("You still have to kill 2 * a gate guard (Realm of the Firebird)\n")
2611 Simulate("You still have to kill 1 * Destroyer of Minds (Deathtrap Dungeon)\n")
2612 Simulate("You still have to kill 1 * Rudolph (In the Air)\n")
2613 Simulate("You still have to kill 1 * a tester of fire (The experimenting room (Fire))\n")
2614 Simulate("You still have to kill 2 * a Bad Apple (Umari's Castle)\n")
2615 Simulate("You still have to kill 1 * the third little pig (Pig Pen)\n\n")
2616
2617 test_toggle = 1
2618 elseif (test_toggle == 1) then
2619 -- TODO add 1 room and others area test here
2620 Simulate("\nYou still have to kill 1 * A kicking patient (A FAKE-private room)\n")
2621 Simulate("You still have to kill 1 * A snoring patient (Canyon Memorial Hospital-FAKE)\n")
2622 Simulate("You still have to kill 1 * An abominable snowman (The Snowy Path)\n")
2623 Simulate("You still have to kill 1 * The senior assassin (Assassins' Scrying Chamber)\n")
2624 Simulate("You still have to kill 1 * Bjorn (Realm of the Firebird)\n")
2625 Simulate("You still have to kill 2 * a crow (Realm of the Firebird)\n")
2626 Simulate("You still have to kill 2 * a gate guard (Realm of the Firebird)\n")
2627 Simulate("You still have to kill 1 * Destroyer of Minds (Deathtrap Dungeon)\n")
2628 Simulate("You still have to kill 1 * a tester of fire (The experimenting room (Fire))\n")
2629 Simulate("You still have to kill 1 * the third little pig (Pig Pen)\n")
2630 Simulate("You still have to kill 1 * The emperor's counselor (Faerie Tales II)\n\n")
2631 test_toggle = 0
2632
2633 end
2634 end
2635
2636 function qq_report (name, line, wildcards)
2637
2638 if (wildcards.channel ~= "") then
2639
2640 local output = ""
2641 local last_mob = ""
2642 local index = 0
2643
2644 for key, value in ipairs(gqList) do
2645 if (last_mob ~= gqList[key].mob) then
2646 index = index + 1
2647 if (gqList[key].type == "area") then
2648 output = string.format("%s %s) %s - %s, ", output, index, gqList[key].mob, gqList[key].areaName)
2649 else
2650 output = string.format("%s %s) %s - %s (%s), ", output, index, gqList[key].mob, gqList[key].roomName, gqList[key].areaId)
2651 end
2652 end
2653
2654 last_mob = gqList[key].mob
2655 end
2656
2657 if (output ~= "") then
2658 SendNoEcho( wildcards.channel .. " " .. output)
2659 end
2660 end
2661 end
2662
2663 function set_gq_refresh(name, line, wildcards)
2664 Note("set " .. USER_gq_mob_dead_refresh)
2665 if (USER_gq_mob_dead_refresh == "true") then
2666 USER_gq_mob_dead_refresh = "false"
2667 else
2668 USER_gq_mob_dead_refresh = "true"
2669 end
2670
2671 SetVariable("GQMobDeadRefresh", USER_gq_mob_dead_refresh)
2672
2673 init_triggers()
2674
2675 --ColourNote ("darkorange", "", "GQ Mob Dead Refresh : " .. USER_gq_mob_dead_refresh)
2676
2677 end
2678
2679 function OnPluginSaveState()
2680 SetVariable("GQMobDeadRefresh", USER_gq_mob_dead_refresh)
2681 end
2682
2683
2684 ------ Execute in Area ------
2685
2686 local execute_in_area_array = {}
2687
2688 function execute_in_area(id, areaId, functionPointer)
2689
2690 execute_in_area_array[id] = {
2691 areaId = areaId,
2692 func = functionPointer,
2693 index = 0,
2694 active = true,
2695 lastState = 3, -- standing
2696 standIndex = 0 -- count of stands in a row
2697 }
2698 --tprint(execute_in_area_array)
2699 EnableTimer("execute_in_area_timer", true)
2700
2701 end
2702
2703 function execute_in_area_tick(name, line, wildcards)
2704
2705 local localRoom = currentRoom
2706 local localState
2707
2708
2709 -- thread safety
2710 if (localRoom == nil) then
2711 DebugNote("Unknown Room")
2712 return
2713 end
2714
2715 if (char_status == nill) then
2716 DebugNote("Unknown char status")
2717 return
2718 else
2719 localState = tonumber(char_status.state)
2720 end
2721
2722 local isActive = false
2723
2724 --tprint(execute_in_area_array)
2725
2726 for index, value in pairs(execute_in_area_array) do
2727
2728 DebugNote("loop - " .. index)
2729 if (value.active == true) then
2730
2731 value.index = value.index + 1
2732
2733 if (value.index > 100) then
2734 value.active = false
2735 print("** aborting quickwhere timer for " .. index .. ", took too long to get to destination")
2736
2737 else
2738
2739 DebugNote("state:" .. localState .. ",:" .. value.areaId .. "==" .. localRoom.areaid)
2740
2741 if ((localState == 3 and value.lastState == 3)
2742 and value.areaId == localRoom.areaid) then
2743
2744 -- skip first timer tick
2745 value.index = value.index + 1
2746 value.standIndex = value.standIndex + 1
2747 if (value.standIndex < 2) then
2748 DebugNote("skip - index:" .. value.index)
2749 else
2750 DebugNote("executing - index:" .. value.index)
2751 value.func()
2752 value.active = false
2753 end
2754 else
2755 -- still moving.. reset index
2756 value.standIndex = 0
2757 end
2758 end
2759 end
2760
2761 value.lastState = localState
2762
2763 if (value.active == true) then
2764 isActive = true
2765 end
2766
2767 end
2768
2769 -- no timer items active.. disable
2770 if (isActive == false) then
2771 DebugNote("disable timer")
2772 EnableTimer("execute_in_area_timer", false)
2773 end
2774 end
2775
2776 -- v4
2777
2778 function gq_refresh(name, line, args)
2779 Execute("gq p")
2780 Execute("qq")
2781 end
2782
2783 ----------- EXTERNAL CALLOUTS -----------------------------
2784
2785 function remote_guess_mob_name(mobName, areaId, broadcast)
2786
2787 DebugNote("remote_guess_mob_name call:" .. mobName .. ":" .. areaId)
2788
2789 local rc, mobGuess, subMob = CallPlugin(
2790 search_destroy_id,
2791 "IGuessMobNameBroadcast",
2792 mobName,
2793 areaId)
2794
2795 if (subMob ~= nil) then
2796 DebugNote(subMob)
2797 end
2798
2799 DebugNote("remote_guess_mob_name return:" .. mobGuess)
2800 return mobGuess
2801
2802 end
2803
2804
2805 ------ Utils ------
2806
2807 function padRight(text, length, padChar)
2808 local padding = length - string.len(text)
2809 for i = 1, padding do
2810 text = text .. padChar
2811 end
2812 return text
2813 end
2814
2815 function sanitize_filename(str)
2816 str = string.gsub(str, "[^%w%s()_-]", "")
2817 return str
2818 end
2819
2820 function quote(str)
2821 return "\""..str.."\""
2822 end
2823
2824 function dbcheck(code)
2825
2826 if code ~= sqlite3.OK and -- no error
2827 code ~= sqlite3.ROW and -- completed OK with another row of data
2828 code ~= sqlite3.DONE then -- completed OK, no more rows
2829 local err = db:errmsg () -- the rollback will change the error message
2830 db:exec("ROLLBACK") -- rollback any transaction to unlock the database
2831 error (err, 2) -- show error in caller's context
2832 end -- if
2833
2834 end -- dbcheck
2835
2836 function fixsql(s)
2837
2838 if s then
2839 return "'" .. (string.gsub (s, "'", "''")) .. "'" -- replace single quotes with two lots of single quotes
2840 else
2841 return "NULL"
2842 end -- if
2843 end -- fixsql
2844
2845 function fixbool(b)
2846 if b then
2847 return 1
2848 else
2849 return 0
2850 end -- if
2851 end -- fixbool
2852
2853 function split(line, delim)
2854
2855 local result = {}
2856 local index = 1
2857
2858 for token in string.gmatch(line, delim) do
2859 result[index] = token
2860 index = index + 1
2861 end
2862
2863 return result
2864 end
2865
2866 function set_check_vidblain(name, line, wildcards)
2867
2868 if (USER_check_vidblain == "true") then
2869 USER_check_vidblain = "false"
2870 else
2871 USER_check_vidblain = "true"
2872 end
2873
2874 local msg = "off"
2875 if (USER_check_vidblain == "true") then
2876 msg = "on"
2877 end
2878 ColourNote ("darkorange", "", "No-portal vidblain assistance: " .. msg)
2879 end
2880
2881 function OnPluginSaveState()
2882
2883 SetVariable("XRunToCheckVidblain", USER_check_vidblain)
2884
2885 end
2886
2887 --------- Sql Execution ------------
2888
2889 function RunSql(name, line, wildcards)
2890
2891 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2892 local db = assert(sqlite3.open(worldPath .. ".db"))
2893
2894 local index = 0
2895 local sql = wildcards.sql
2896 ColourNote("darkorange", "", "running :" .. sql)
2897 for row in db:nrows(sql) do
2898 index = index + 1
2899 print("----------- record " .. index .. " -----------" )
2900 tprint(row)
2901 -- print (serialize.save ("row", row))
2902 end
2903
2904 db:close_vm()
2905 end
2906
2907 function ExecSql (name, line, wildcards)
2908 local worldPath = GetInfo(66)..Trim(sanitize_filename(WorldName()))
2909 local db = assert(sqlite3.open(worldPath .. ".db"))
2910
2911 Note("executing " .. wildcards.sql)
2912 -- dbcheck (db:execute (fixsql(wildcards.sql)))
2913 db:execute(fixsql(wildcards.sql))
2914
2915 db:close_vm()
2916 Note("ok")
2917 end
2918
2919 -------------- DEBUG --------------------
2920
2921 function ext_debug(name, line, wildcards)
2922 if (showDebug == 0) then
2923 showDebug = 1
2924 else
2925 showDebug = 0
2926 end
2927 Note("Ext debug:" .. showDebug)
2928 end
2929
2930 function DebugNote(text)
2931 if (showDebug == 1) then
2932 Note("Extender ~ " .. text)
2933 end
2934 end
2935
2936 function DebugTPrint(title, obj)
2937 if (showDebug == 1) then
2938 DebugNote(title .. " : " .. serialize.save_simple(obj))
2939 end
2940 end
2941
2942 -------------- INSTALL MESSAGE ------------------
2943
2944 function InstallMessage()
2945 ColourNote("MediumSeaGreen", "", "+=======================================================+")
2946 ColourNote("MediumSeaGreen", "", "+ Extender Installed - type 'extender help' for options +")
2947 ColourNote("MediumSeaGreen", "", "+=======================================================+")
2948 end
2949
2950 InstallMessage()
2951
2952-------------- SORTING ------------------
2953
2954 function sort_cp_list(a,b)
2955 -- order by sortId, dupe, name,count
2956 -- '>' is descending and '<' is ascending
2957
2958 -- Note(a.sortId .. " " .. a.origMob .. " " .. a.bast_kills .. " " .. b.origMob)
2959 return (a.sortId > b.sortId)
2960 or (a.sortId == b.sortId and a.is_multi_area < b.is_multi_area)
2961 or (a.sortId == b.sortId and a.is_multi_area== b.is_multi_area and a.origMob > b.origMob)
2962 or (a.sortId == b.sortId and a.is_multi_area== b.is_multi_area and a.origMob == b.origMob and a.bast_kills > b.bast_kills)
2963 -- e.g,table.sort(tablename, sort_cp_list)
2964 end
2965 -- sort_cp_list2 is trash and for testing
2966 --[[
2967 function sort_cp_list2(a,b)
2968 -- order by sortId, dupe, name,count
2969 -- '>' is descending and '<' is ascending
2970 return (tostring(a.sortId) > tostring(b.sortId))
2971 or (tostring(a.sortId) == tostring(b.sortId) and a.is_multi_area < b.is_multi_area)
2972 or (tostring(a.sortId) == tostring(b.sortId) and a.is_multi_area== b.is_multi_area and a.origMob > b.origMob)
2973 or (tostring(a.sortId) == tostring(b.sortId) and a.is_multi_area== b.is_multi_area and a.origMob == b.origMob and a.bast_kills > b.bast_kills)
2974 -- e.g,table.sort(tablename, sort_cp_list)
2975 end
2976 ]]
2977 function sort_cp_list2(a,b)
2978 -- '>' is descending and '<' is ascending
2979 -- this big ass sort will take forever but it only fires once per cp
2980 return (a.sortId > b.sortId)
2981 or (a.sortId == b.sortId and a.is_multi_area < b.is_multi_area)
2982 or (a.sortId == b.sortId and a.is_multi_area == b.is_multi_area and a.origMob > b.origMob)
2983 or (a.sortId == b.sortId and a.is_multi_area == b.is_multi_area and a.origMob == b.origMob and a.type < b.type)
2984 or (a.sortId == b.sortId and a.is_multi_area == b.is_multi_area and a.origMob == b.origMob and a.type == b.type and a.bast_kills > b.bast_kills)
2985 -- e.g,table.sort(tablename, sort_cp_list)
2986 end
2987 function sort_distance(a,b)
2988 -- '>' is descending and '<' is ascending
2989 return (a.distance > b.distance)
2990 -- e.g,table.sort(tablename, sort_distance)
2991 end
2992 function sort1_func(a,b)
2993 -- sorts table on one column
2994 return tonumber(a.mrank) > tonumber(b.mrank)
2995 -- e.g,table.sort(tablename, sort1_func)
2996 end
2997
2998 function sort2_func(a, b)
2999 -- sorts two columns
3000 -- e.g., table.sort(tablename, sort2_func)
3001 return (a.name < b.name) or (a.name == b.name and tonumber(a.bast_kills) > tonumber(b.bast_kills))
3002 end
3003 function sort3_func(a, b)
3004 -- sorts two columns
3005 -- e.g., table.sort(tablename, sort3_func)
3006 return (a.area > b.area) or (a.area == b.area and tonumber(a.bast_kills) > tonumber(b.bast_kills))
3007 or (a.area == b.area and tonumber(a.bast_kills) == tonumber(b.bast_kills) and a.name > b.name)
3008 end
3009 function descramble_name(mobName)
3010 --enei
3011 if (string.len(mobName)>25) then
3012 mobName=string.sub(mobName,1,25)
3013 end
3014 local stringlength = string.len(mobName)
3015
3016 for i = 1, #mobs, 1 do
3017 DebugNote("EditDist : " .. mobs[i] .. " --- " .. mobName .. " =" .. EditDistance(mobs[i],mobName))
3018 if( EditDistance(mobs[i]:lower(),mobName:lower()) <= tonumber(resDist)) then
3019 DebugNote(mobName.." ~~~ "..mobs[i])
3020 if(tonumber(resDist) > 0 or (stringlength > math.abs(string.len(mobs[i])-string.len(mobName)) or string.match(mobName:lower(),mobs[i]:lower())~=nil)) then
3021 res_pos = i
3022 resMob = mobs[i]
3023 DebugNote("resMob -> "..resMob)
3024 resCom = comments[i]
3025 resDist = EditDistance(mobs[i]:lower(),mobName:lower())
3026 stringlength = math.abs(string.len(mobs[i])-string.len(mobName))
3027 end
3028 end
3029 end
3030 end
3031 function mob_count(mob,area,room)
3032 local mob_count = 0
3033 local known_room = -1
3034
3035 if has_bast ~= 1 then
3036 --ColourNote("darkorange", "", " Bast Stat Monitor and Broadcast Plugins AKA stats.db not installed.")
3037 return mob_count, known_room
3038 end
3039 local sql = ""
3040 --local sql_bast = [[where mk.name like "%]] .. mob .. [[%"]]
3041 --local sql_bast = [[where mk.name like '%]] .. (string.gsub (mob, "'", "''")) .. [[%']]
3042
3043 local sql_bast = [[where lower(mk.name) = ]] .. fixsql(mob)
3044 if area ~= "" then
3045 --sql_bast = sql_bast .. " and " .. [[r.area = "]] .. area .. [["]]
3046 sql_bast = sql_bast .. " and " .. [[mk.area = "]] .. area .. [["]]
3047 end
3048 if room ~= "" then
3049 --sql_bast = sql_bast .. " and " .. [[r.uid = "]] .. room .. [["]]
3050 sql_bast = sql_bast .. " and " .. [[mk.room_id = "]] .. room .. [["]]
3051 end
3052
3053 sql_bast = [[select count(*) as kills, count(distinct mk.room_id) as rooms, max(mk.room_id) as max_rm_id
3054 from mobkills mk ]] .. "\n" ..
3055 sql_bast
3056 --Note(sql_bast)
3057
3058 db_bast = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
3059 for row in db_bast:nrows(sql_bast) do
3060 mob_count = row.kills
3061 if row.rooms == 1 then
3062 known_room = row.max_rm_id
3063 end
3064 end
3065
3066 db_bast:close()
3067
3068 return mob_count, known_room
3069 end
3070--------- Mob Name Decrypt : START ------------
3071 function compare_names()
3072 table.sort(xname_mobs, sort_distance)
3073 DebugNote("compare_names, Matching: " .. xname_target .. "\n")
3074 for i, mob in ipairs (xname_mobs) do
3075 if mob.distance < 6 then
3076 local str = ""
3077 if mob.distance == 0
3078 then str = "Exact match (++): "
3079 elseif mob.distance < 4 then
3080 str = "Close match (-" .. tostring(mob.distance) .. "): "
3081 else str = "Poor match (-" .. tostring(mob.distance) .. "): "
3082 end
3083 ColourNote("lime","",str,"white","", mob.mob)
3084 end
3085 end --Note("\n")
3086 name_mode = ""
3087 end
3088 function compare_names_bast(target)
3089 if has_bast ~= 1 then
3090 ColourNote("darkorange", "", " Bast Stat Monitor and Broadcast Plugins AKA stats.db not installed.")
3091 return
3092 end
3093
3094 local comparison = {}
3095 local dist
3096 local select = [[SELECT * FROM tbl_tmp]]
3097
3098 db = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
3099
3100 for row in db:nrows(select) do
3101 dist = EditDistance(target,row.name)
3102
3103 if dist < 6 then
3104 table.insert(comparison, {mob = row.name, distance = dist})
3105 end
3106 end
3107
3108 -- retrieve the top 4 matches
3109 local max = 4
3110
3111 if #comparison == 0 then ColourNote("darkorange","","No matching names")
3112 else
3113 table.sort(comparison, sort_distance)
3114 for i, mobName in ipairs(comparison) do
3115 --Note("hi")
3116 ColourNote("lime","","Compared: ","white","", mobName.mob ,
3117 "lime",""," results in distance of ","white","",mobName.distance)
3118
3119 if i == max then break end
3120 end
3121
3122 end
3123 comparison = {}
3124 db:close_vm()
3125 end
3126--------- Mob Name Decrypt : END ------------
3127
3128 function bast_update(name,line,args)
3129 Note("")
3130 if has_bast ~= 1 then
3131 Note("")
3132 ColourNote("darkorange", ""," Bast Stat Monitor and Broadcast Plugins AKA stats.db not installed.")
3133 return
3134 end
3135 ColourNote("darkorange", "", "Updating Bast database") Note("")
3136
3137 db = assert(sqlite3.open(GetInfo(66).."\\logs\\stats.db"))
3138
3139 local sql_count = [[select count(*) as start_cnt from mob_areas]]
3140 for row in db:nrows(sql_count) do
3141 local start_cnt = row.start_cnt
3142 end
3143
3144 -- update missing areas in mobkills
3145 local sql_update = [[update mobkills
3146 set area = (
3147 select b.area
3148 from mobkills a
3149 join rooms b ON (a.room_id = b.uid)
3150 where a.area is null
3151 );commit;
3152 ]]
3153 --rslt_update = db:exec(sql_update)
3154 local sql_insert = [[ INSERT OR IGNORE INTO mob_areas (mob, area)
3155 INSERT OR IGNORE INTO mob_areas (mob, area)
3156 select
3157 distinct lower(a.name) as mob,
3158 (
3159 case when IFNULL(a.area,"") <> "" then a.area
3160 else
3161 case when IFNULL(b.area,"") <> "" then b.area
3162 else "unknown"
3163 end
3164 end) as area
3165 from mobkills a
3166 join rooms b on (a.room_id = b.uid)
3167 where lower(a.name) <> 'unknown';
3168 commit;
3169 ]]
3170
3171 rslt = db:exec(sql_insert)
3172 --ColourNote("darkorange", "", "Result: " .. tostring(rslt))
3173
3174 if rslt ~= 0 then
3175 ColourNote("darkorange", "", "Update Unsuccessful")
3176 else
3177 for row in db:nrows(sql_count) do
3178 local end_cnt = row.start_cnt
3179 end
3180 local mobs = tostring(end_cnt-start_cnt)
3181 ColourNote("darkorange", "", "Update Successful, added: " .. mobs)
3182 end
3183 Note("")
3184 db:close_vm()
3185 end
3186
3187 function xname_start(name,line,args)
3188 DebugNote("xname_start")
3189 if args.index == nil and args.mob == nil then
3190 Send(line)
3191 return
3192 end
3193 local list = ""
3194 if name == "xname_cp" then
3195 -- if args.index ~= "" and args.index ~= nil then
3196 list = cpList
3197 name_mode = "winkle"
3198 elseif name == "xname_gq" and args.index ~= "" and args.index ~= nil then
3199 list = gqList
3200 name_mode = "winkle"
3201 elseif name == "xname_bast" then
3202 if has_bast ~= 1 then
3203 ColourNote("darkorange", "", " Bast Stat Monitor and Broadcast Plugins AKA stats.db not installed.")
3204 return
3205 end
3206 name_mode = "bast"
3207 xname_target = args.mob
3208 compare_names_bast(xname_target)
3209
3210 return-- start it
3211 elseif name == "xname_custom" then
3212 -- you entered a mob name
3213 xname_target = trim(args.mob)
3214 name_mode = "custom"
3215 else
3216 ColourNote("darkorange", "", "No item exists, or data busy (try again)")
3217 return
3218 end
3219
3220 if name_mode == "winkle" then
3221 local listCount = #list
3222 local index = tonumber(args.index)
3223 if listCount == 0 or listCount == "" or listCount < index then
3224 ColourNote("darkorange", "", "No item exists, or data busy (try again)")
3225 return
3226 else
3227 -- mob name to descramble
3228 xname_target = list[index].mob
3229 if currentRoom.areaid ~= list[index].areaId then
3230 ColourNote("darkorange", "",
3231 "Function works when in the same area as mob. You: " .. currentRoom.areaid .. " vs. Mob: " .. list[index].areaId)
3232 end
3233 end
3234 end
3235
3236 EnableTriggerGroup("xname_ends", true)
3237 DebugNote("xname_start: looking for mob: " .. xname_target)
3238 xname_mobs = {}
3239 Send("mobdeaths here")
3240
3241 end
3242 function xname_capture_list(name,line,args)
3243 local insert_mob = string.lower(trim(args.mob))
3244 local dist = EditDistance(xname_target,insert_mob)
3245 local check = [["]] .. insert_mob .. [["]]
3246 if xname_mobs[check] == nil then
3247 table.insert(xname_mobs, {mob = insert_mob, distance = dist})
3248 end
3249 --Note(mob_list[insert_mob])
3250
3251 end
3252
3253 function xname_end_point(name,line,args)
3254 if name == "xname_first" then
3255 EnableTrigger("xname_detail",true)
3256 EnableTrigger("xname_hide",true)
3257 elseif name == "xname_last" then
3258 EnableTrigger("xname_detail",false)
3259 EnableTriggerGroup("xname_ends", false)
3260 EnableTrigger("xname_hide",false)
3261 compare_names()
3262 end
3263 end
3264 function trim(str)
3265 -- from PiL2 20.4
3266 return (str:gsub("^%s*(.-)%s*$", "%1"))
3267 end
3268 function sort_distance(a,b)
3269 -- sorts table on one column
3270 return tonumber(a.distance) < tonumber(b.distance)
3271 -- e.g,table.sort(tablename, sort1_func)
3272 end
3273
3274 --------- Scan Highlight Mob ------------
3275 -- need scan tags turned on for this to work
3276
3277
3278function togglescan(name, line, wildcards)
3279 if name == 'scanon' then
3280 EnableTriggerGroup("scan",true)
3281 if onQuest or onGq or onCp then
3282 --print('turning on scan matching')
3283 --phelper:enabletriggroup('scan', true)
3284 EnableTriggerGroup("scan",true)
3285 end
3286 elseif name == 'scanoff' then
3287 --print('turning off scan matching')
3288 --phelper:enabletriggroup('scan', false)
3289 EnableTriggerGroup("scan",false)
3290 end
3291end
3292
3293function checkmob(name, line, wildcards, styles)
3294 DebugNote("checkmob")
3295 -- need to make sure scan tags are on
3296 local found = false
3297 local addTxt = ""
3298 local mob = wildcards[2]
3299 mob = mob:lower()
3300 mob = trim(mob)
3301
3302 local color = "turquoise"
3303
3304 if not found and onQuest then
3305 if mob == questMob:lower() then
3306 found = 'quest'
3307 color = "red"
3308 addTxt = "[QUEST]"
3309 end
3310 end
3311
3312 if not found and onGq then
3313 for i,v in ipairs(gqList) do
3314 if mob == v.mob:lower() then
3315 found = 'gq'
3316 color = "turquoise"
3317 addTxt = "[GQ]"
3318 end
3319
3320 end
3321
3322 end
3323
3324 if not found and onCp then
3325 for i,v in ipairs(cpList) do
3326 if mob == v.mob:lower() then
3327 found = 'cp'
3328 color = "magenta"
3329 addTxt = "[CP]"
3330 end
3331 end
3332 end
3333
3334 if found then
3335 -- local textcolour = RGBColourToName(phelper[tostring(found) .. 'textcolour'])
3336 -- local backcolour = RGBColourToName(phelper[tostring(found) .. 'backcolour'])
3337
3338 for i,v in ipairs(styles) do
3339 ColourTell("black", color, v.text)
3340 end
3341 ColourTell("black", color, " " .. addTxt)
3342 -- ColourTell(textcolour, backcolour, ' - (' .. tostring(found):upper() .. ')')
3343 else
3344 for i,v in ipairs(styles) do
3345 ColourTell(RGBColourToName(v.textcolour), v.backcolour, v.text)
3346 end
3347 end
3348 ColourNote("", "", "")
3349end
3350
3351
3352
3353function OnPluginDisable ()
3354 -- SendNoEcho('tags scan off')
3355
3356
3357end -- OnPluginDisable
3358function boo ()
3359 --enei
3360 if (string.len(mobName)>25) then
3361 mobName=string.sub(mobName,1,25)
3362 end
3363 local stringlength = string.len(mobName)
3364
3365 for i = 1, #mobs, 1 do
3366 DebugNote("EditDist : " .. mobs[i] .. " --- " .. mobName .. " =" .. EditDistance(mobs[i],mobName))
3367 if( EditDistance(mobs[i]:lower(),mobName:lower()) <= tonumber(resDist)) then
3368 DebugNote(mobName.." ~~~ "..mobs[i])
3369 if(tonumber(resDist) > 0 or (stringlength > math.abs(string.len(mobs[i])-string.len(mobName)) or string.match(mobName:lower(),mobs[i]:lower())~=nil)) then
3370 res_pos = i
3371 resMob = mobs[i]
3372 DebugNote("resMob -> "..resMob)
3373 resCom = comments[i]
3374 resDist = EditDistance(mobs[i]:lower(),mobName:lower())
3375 stringlength = math.abs(string.len(mobs[i])-string.len(mobName))
3376 end
3377 end
3378 end
3379
3380end
3381function lev(str1, str2)
3382 local len1 = string.len(str1)
3383 local len2 = string.len(str2)
3384 local matrix = {}
3385 local cost = 0
3386
3387 -- quick cut-offs to save time
3388 if (len1 == 0) then
3389 return len2
3390 elseif (len2 == 0) then
3391 return len1
3392 elseif (str1 == str2) then
3393 return 0
3394 end
3395
3396 -- initialise the base matrix values
3397 for i = 0, len1, 1 do
3398 matrix[i] = {}
3399 matrix[i][0] = i
3400 end
3401 for j = 0, len2, 1 do
3402 matrix[0][j] = j
3403 end
3404
3405 -- actual Levenshtein algorithm
3406 for i = 1, len1, 1 do
3407 for j = 1, len2, 1 do
3408 if (str1:byte(i) == str2:byte(j)) then
3409 cost = 0
3410 else
3411 cost = 1
3412 end
3413
3414 matrix[i][j] = math.min(matrix[i-1][j] + 1, matrix[i][j-1] + 1, matrix[i-1][j-1] + cost)
3415 end
3416 end
3417
3418 -- return the last value - this is the Levenshtein distance
3419 return matrix[len1][len2]
3420 end
3421function tmp ()
3422
3423
3424end
3425]]>
3426</script>
3427
3428</muclient>
3429
3430
3431<!-- BUGS
3432
3433
3434-->