Advertisement
Guest User

Untitled

a guest
Jan 17th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 44.59 KB | None | 0 0
  1. <?xml version="1.0" encoding="iso-8859-1"?>
  2. <!DOCTYPE muclient [
  3. <!ENTITY show_vnums "true" >
  4. <!ENTITY show_timing "false" >
  5. <!ENTITY show_completed "false" >
  6. <!ENTITY show_database_mods "true" >
  7. <!ENTITY show_other_areas "false" >
  8. <!ENTITY show_area_exits "false" >
  9. <!ENTITY show_up_down "true" >
  10. <!ENTITY speedwalk_prefix "" >
  11. ]>
  12.  
  13. <muclient>
  14. <plugin
  15. name="Materia_Magica_Mapper"
  16. author="Nick Gammon"
  17. id="1c17ac2c83b2b66c402c80c6"
  18. language="Lua"
  19. purpose="Mapper for Materia Magica"
  20. save_state="y"
  21. date_written="2010-10-12"
  22. date_modified="2010-10-18 07:05"
  23. requires="4.61"
  24. version="1.5"
  25. >
  26.  
  27. <description trim="y">
  28. <![CDATA[
  29. AUTOMATIC MAPPER ... by Nick Gammon
  30.  
  31. The window can be dragged to a new location by dragging the room name.
  32.  
  33. Your current room is always in the center with a bolder border.
  34.  
  35. LH-click on a room to speed-walk to it. RH-click on a room for options.
  36.  
  37. LH-click on the "*" button on the bottom-left corner to configure it.
  38.  
  39. ** WHY DOES THE MAP CHANGE? **
  40.  
  41. The mapper draws from your room outwards - that is, it draws your room's exits
  42. first, then the rooms leading from those rooms, and so on.
  43.  
  44. Eventually it finds an overlap, and draws a short "stub" line to indicate there
  45. is a room there which there isn't space to draw. If you get closer to that
  46. room the stub will disappear and the room(s) in question will be drawn.
  47.  
  48. ACTIONS
  49.  
  50. mapper help --> this help (or click the "?" button on the bottom right)
  51. mapper zoom out --> zoom out
  52. mapper zoom in --> zoom in
  53. mapper hide --> hide map
  54. mapper show --> show map
  55.  
  56. FINDING THINGS
  57.  
  58. mapper bookmarks --> show nearby rooms that you bookmarked
  59. mapper find <text> --> full-text search (eg. shop OR baker)
  60. mapper shop --> show nearby shops/banks etc.
  61. mapper train --> show nearby trainers
  62. mapper where <room> --> show directions to a room
  63.  
  64. MOVING
  65.  
  66. mapper goto <room> --> walk to a room by its room number (partial)
  67. mapper stop --> cancel any current speedwalk
  68. mapper resume --> resume last speedwalk or hyperlinked speedwalk
  69.  
  70. ]]>
  71. </description>
  72.  
  73.  
  74. </plugin>
  75.  
  76.  
  77. <!-- Triggers -->
  78.  
  79. <triggers>
  80.  
  81. <trigger
  82. back_colour="8"
  83. bold="y"
  84. enabled="y"
  85. match="[Shop] *"
  86. match_back_colour="y"
  87. match_bold="y"
  88. match_inverse="y"
  89. match_italic="y"
  90. match_text_colour="y"
  91. name="Shop_Line"
  92. script="Shop_Line"
  93. sequence="200"
  94. text_colour="11"
  95.  
  96. >
  97. </trigger>
  98.  
  99. <trigger
  100. back_colour="8"
  101. bold="y"
  102. enabled="y"
  103. match="[Train] *"
  104. match_back_colour="y"
  105. match_bold="y"
  106. match_inverse="y"
  107. match_italic="y"
  108. match_text_colour="y"
  109. name="Train_Line"
  110. script="Train_Line"
  111. sequence="200"
  112. text_colour="11"
  113.  
  114. >
  115. </trigger>
  116.  
  117.  
  118.  
  119.  
  120.  
  121. <trigger
  122. enabled="y"
  123. match="kxwt_rshort *"
  124. name="process_room_name"
  125. sequence="100"
  126. send_to="14"
  127. >
  128. <send>name="%1"</send>
  129. </trigger>
  130. <trigger
  131. enabled="y"
  132. match="kxwt_rvnum *"
  133. name="process_room_desc"
  134. sequence="100"
  135. send_to="14"
  136. >
  137. <send>uid="%1"</send>
  138. </trigger>
  139. <trigger
  140. enabled="y"
  141. match="kxwt_terrain *"
  142. name="process_terrain"
  143. sequence="100"
  144. send_to="14"
  145. >
  146. <send>terrain="%1"</send>
  147. </trigger>
  148. <trigger
  149. enabled="y"
  150. match="kxwt_area * *"
  151. name="process_area"
  152. sequence="100"
  153. send_to="14"
  154. >
  155. <send>area="%2"</send>
  156. </trigger>
  157. <trigger
  158. enabled="y"
  159. match="[Exits: *]"
  160. name="Exits_Line"
  161. sequence="100"
  162. send_to="14"
  163. >
  164. <send>process_exits("%1")</send>
  165. </trigger>
  166.  
  167. <trigger
  168. enabled="y"
  169. match="^The (door|gate) is closed\.$"
  170. regexp="y"
  171. name="Door_Closed"
  172. script="Door_Closed"
  173. sequence="100"
  174. >
  175. </trigger>
  176.  
  177. <!-- various messages that cancel speedwalks -->
  178.  
  179. <trigger
  180. enabled="y"
  181. match="You are too exhausted. Better rest for a bit."
  182. regexp="y"
  183. script="mapper.cancel_speedwalk"
  184. sequence="100"
  185. >
  186. </trigger>
  187.  
  188. </triggers>
  189.  
  190.  
  191. <aliases>
  192.  
  193. <!-- zooming aliases -->
  194.  
  195. <alias
  196. match="mapper zoom out"
  197. enabled="y"
  198. sequence="100"
  199. omit_from_command_history="y"
  200. omit_from_output="y"
  201. script="mapper.zoom_out"
  202. >
  203. </alias>
  204.  
  205. <alias
  206. match="mapper zoom in"
  207. enabled="y"
  208. sequence="100"
  209. omit_from_command_history="y"
  210. omit_from_output="y"
  211. script="mapper.zoom_in"
  212. >
  213. </alias>
  214.  
  215.  
  216. <alias
  217. match="mapper goto *"
  218. enabled="y"
  219. sequence="100"
  220. script="map_goto"
  221. >
  222.  
  223. </alias>
  224.  
  225. <!-- finding aliases -->
  226.  
  227. <alias
  228. match="^mapper find ([\w* %d/&quot;]+)$"
  229. enabled="y"
  230. sequence="100"
  231. script="map_find"
  232. regexp="y"
  233. >
  234.  
  235. </alias>
  236.  
  237. <alias
  238. match="^mapper book\w*$"
  239. regexp="y"
  240. enabled="y"
  241. sequence="100"
  242. script="map_bookmarks"
  243. >
  244.  
  245. </alias>
  246.  
  247. <alias
  248. match="mapper where *"
  249. enabled="y"
  250. sequence="100"
  251. script="map_where"
  252. >
  253.  
  254. </alias>
  255. <alias
  256. match="mapper backup"
  257. enabled="y"
  258. sequence="100"
  259. omit_from_output="y"
  260. script="manual_backup"
  261. ></alias>
  262.  
  263. <alias
  264. match="^mapper shops?$"
  265. regexp="y"
  266. enabled="y"
  267. sequence="100"
  268. script="map_shops"
  269. >
  270.  
  271. </alias>
  272.  
  273. <alias
  274. match="^mapper train\w*$"
  275. regexp="y"
  276. enabled="y"
  277. sequence="100"
  278. script="map_trainers"
  279. >
  280.  
  281. </alias>
  282.  
  283. <alias
  284. match="mapper resume"
  285. enabled="y"
  286. sequence="100"
  287. script="map_resume"
  288. >
  289.  
  290. </alias>
  291.  
  292. <alias
  293. script="OnHelp"
  294. match="mapper help"
  295. enabled="y"
  296. >
  297. </alias>
  298.  
  299. <!-- cancel speedwalking -->
  300.  
  301. <alias
  302. match="mapper stop"
  303. enabled="y"
  304. sequence="100"
  305. script="mapper.cancel_speedwalk"
  306. >
  307. </alias>
  308.  
  309. <!-- show/hide mapper -->
  310.  
  311. <alias
  312. match="mapper hide"
  313. enabled="y"
  314. sequence="100"
  315. script="mapper.hide"
  316. >
  317. </alias>
  318.  
  319. <alias
  320. match="mapper show"
  321. enabled="y"
  322. sequence="100"
  323. script="mapper.show"
  324. >
  325. </alias>
  326.  
  327. </aliases>
  328.  
  329. <!-- Script -->
  330.  
  331.  
  332. <script>
  333.  
  334. local show_vnums = &show_vnums;
  335. local show_timing = &show_timing;
  336. local show_completed = &show_completed;
  337. local show_database_mods = &show_database_mods;
  338. local show_other_areas = &show_other_areas;
  339. local show_up_down = &show_up_down;
  340. local show_area_exits = &show_area_exits;
  341. local speedwalk_prefix = "&speedwalk_prefix;"
  342.  
  343. <![CDATA[
  344.  
  345. mapper = require "altermapper"
  346. require "serialize"
  347. require "copytable"
  348.  
  349. rooms = {}
  350. terrain = 0
  351. area = 0
  352. uid = 0
  353. current_room=0
  354. current_area = 0
  355. expected_exit=-666
  356. count = 0
  357. from_room=0
  358. last_direction_moved=0
  359. roomcount = 0
  360. exits_str = 0
  361.  
  362. valid_direction = {
  363. n = "n",
  364. s = "s",
  365. e = "e",
  366. w = "w",
  367. u = "u",
  368. d = "d",
  369. ne = "ne",
  370. sw = "sw",
  371. nw = "nw",
  372. se = "se",
  373. north = "n",
  374. south = "s",
  375. east = "e",
  376. west = "w",
  377. up = "u",
  378. down = "d",
  379. northeast = "ne",
  380. northwest = "nw",
  381. southeast = "se",
  382. southwest = "sw",
  383. ['in'] = "in",
  384. out = "out",
  385. } -- end of valid_direction
  386.  
  387. terrain_color = {}
  388.  
  389. -- -----------------------------------------------------------------
  390. -- Here on white coloured line - this is a room name or room exits
  391. -- -----------------------------------------------------------------
  392.  
  393. function Name_Or_Exits (name, line, wildcards)
  394.  
  395. exits = string.match (line, "^Exits: (.*)")
  396.  
  397. if exits then
  398. process_exits (exits)
  399. end -- if
  400.  
  401. roomname = name
  402.  
  403. end -- Name_Or_Exits
  404.  
  405.  
  406.  
  407.  
  408. function process_exits (exits_str)
  409.  
  410. -- generate a "room ID" by hashing the room name, description and exits
  411. -- break up exits into individual directions
  412. exits = {}
  413. for exit in string.gmatch (exits_str, "%w+") do
  414. local ex = valid_direction [exit]
  415. if ex then
  416. exits [ex] = "-666" -- don't know where it goes yet
  417. end -- if
  418. end -- for
  419. if not rooms [current_room] then
  420. rooms [uid] = { name = name, roomdesc = uid, exits = exits, area=area, fillcolour=terrain_color[terrain], fillbrush=0, bordercolour=0xffffff }
  421. end -- if
  422. -- save so we know current room later on
  423. current_room = uid
  424.  
  425.  
  426. -- ColourNote ("rosybrown", "", roomdesc)
  427. -- ColourNote ("olive", "", uid)
  428.  
  429. local room = rooms [current_room]
  430.  
  431. -- not cached - see if in database
  432. if not room then
  433. -- print ("Loading room", current_room, "from database")
  434. room = load_room_from_database (current_room)
  435. end -- not in cache
  436.  
  437.  
  438.  
  439. if not room then
  440. -- print ("Added room", uid) -- debugging
  441. -- print ("Name", name)
  442. -- ColourNote ("rosybrown", "", roomdesc)
  443.  
  444. db:exec ("BEGIN TRANSACTION;")
  445.  
  446. save_room_to_database (current_room, name, roomdesc)
  447. save_exits_to_database (current_room, exits)
  448.  
  449. db:exec ("COMMIT;")
  450.  
  451. -- get it back now
  452. room = load_room_from_database (current_room)
  453.  
  454. end -- if room not there
  455.  
  456. -- call mapper to draw this rom
  457. mapper.draw (uid) -- redraw room with name
  458.  
  459. -- try to work out where previous room's exit led
  460. if expected_exit == "-666" and from_room then
  461. fix_up_exit ()
  462. end -- exit was wrong
  463.  
  464. end -- process_exits
  465.  
  466. function fix_up_exit ()
  467.  
  468. -- where we were before
  469. local room = rooms [from_room]
  470.  
  471. -- leads to here
  472. room.exits [last_direction_moved] = current_room
  473.  
  474. -- clear for next time
  475. last_direction_moved = nil
  476. from_room = nil
  477.  
  478. end -- fix_up_exit
  479.  
  480.  
  481. function Shop_Line (name, line, wildcards)
  482.  
  483. -- location not known?
  484. if not current_room then
  485. return
  486. end -- if
  487.  
  488. if rooms [current_room].shop then
  489. return
  490. end -- already a shop
  491.  
  492. -- mark as shop
  493. rooms [current_room].shop = true
  494.  
  495. -- update database
  496. dbcheck (db:execute (string.format (
  497. "UPDATE rooms SET shop = %i WHERE uid = %s;",
  498. fixbool (rooms [current_room].shop),
  499. fixsql (current_room)
  500. )))
  501.  
  502. -- note it
  503. mapper.mapprint ("Room", current_room, "marked as a shop")
  504.  
  505. -- redraw
  506. mapper.draw (current_room)
  507.  
  508. end -- Shop_Line
  509.  
  510. function Train_Line (name, line, wildcards)
  511.  
  512. -- location not known?
  513. if not current_room then
  514. return
  515. end -- if
  516.  
  517. if rooms [current_room].train then
  518. return
  519. end -- already a train
  520.  
  521. -- mark as train
  522. rooms [current_room].train = true
  523.  
  524. -- update database
  525. dbcheck (db:execute (string.format (
  526. "UPDATE rooms SET train = %i WHERE uid = %s;",
  527. fixbool (rooms [current_room].train),
  528. fixsql (current_room)
  529. )))
  530.  
  531. -- note it
  532. mapper.mapprint ("Room", current_room, "marked as a training room")
  533.  
  534. -- redraw
  535. mapper.draw (uid)
  536.  
  537. end -- Train_Line
  538.  
  539. -- -----------------------------------------------------------------
  540. -- mapper 'get_room' callback - it wants to know about room uid
  541. -- -----------------------------------------------------------------
  542.  
  543. function get_room (uid)
  544.  
  545. -- check we got room at all
  546. if not rooms [uid] then
  547. -- return nil
  548. end -- if
  549.  
  550. -- look it up
  551. local ourroom = rooms [uid]
  552.  
  553. -- not cached - see if in database
  554. if not ourroom then
  555. ourroom = load_room_from_database (uid)
  556. rooms [uid] = ourroom -- cache for later
  557. end -- not in cache
  558.  
  559. if not ourroom then
  560. return nil
  561. end -- if
  562.  
  563. local room = copytable.deep (ourroom)
  564.  
  565. if uid == current_room then
  566. current_area = room.area
  567. end -- if
  568.  
  569. -- build hover message
  570.  
  571.  
  572. local shop = ""
  573. if room.shop then
  574. shop = "\nRoom is shop"
  575. end -- if shop
  576.  
  577. local train = ""
  578. if room.train then
  579. train = "\nRoom has trainer"
  580. end -- if train
  581.  
  582. local notes = ""
  583. if room.notes then
  584. notes = "\nBookmark: " .. room.notes
  585. end -- if notes
  586.  
  587. local texits = {}
  588. for dir in pairs (room.exits) do
  589. table.insert (texits, dir)
  590. end -- for
  591. table.sort (texits)
  592.  
  593. room.hovermessage = string.format (
  594. "%s\tExits: %s\nRoom: %s%s%s%s",
  595. room.name,
  596. table.concat (texits, ", "),
  597. uid,
  598. shop,
  599. train,
  600. notes
  601. -- depth,
  602. -- table.concat (path, ",")
  603. )
  604.  
  605.  
  606. -- special room fill colours
  607.  
  608. if room.shop then
  609. room.fillcolour = config.SHOP_FILL_COLOUR.colour
  610. room.fillbrush = 8
  611. end -- if
  612.  
  613. if room.train then
  614. room.fillcolour = config.TRAINER_FILL_COLOUR.colour
  615. room.fillbrush = 8
  616. end -- if
  617.  
  618. if uid == current_room then
  619. room.bordercolour = ColourNameToRGB "red"
  620. room.borderpenwidth = 2
  621. elseif room.area ~= current_area then
  622. room.bordercolour = config.DIFFERENT_AREA_COLOUR.colour
  623. end -- not in this area
  624.  
  625. return room
  626.  
  627. end -- get_room
  628.  
  629.  
  630.  
  631. -- -----------------------------------------------------------------
  632. -- We have changed rooms - work out where the previous room led to
  633. -- -----------------------------------------------------------------
  634.  
  635. function fix_up_exit ()
  636.  
  637. -- where we were before
  638. local room = rooms [from_room]
  639.  
  640. -- print ("Moved from", from_room, "to", current_room, "in direction", last_direction_moved)
  641.  
  642. -- leads to here
  643. if from_room ~= current_room then
  644.  
  645. dbcheck (db:execute (string.format ([[
  646. UPDATE exits SET touid = %s WHERE fromuid = %s AND dir = %s;
  647. ]],
  648. fixsql (current_room), -- destination room
  649. fixsql (from_room), -- from previous room
  650. fixsql (last_direction_moved) -- direction (eg. "n")
  651. )))
  652.  
  653. if show_database_mods then
  654. mapper.mapprint ("Fixed exit", last_direction_moved, "from room", from_room, "to be to", current_room)
  655. end -- if
  656.  
  657. room.exits [last_direction_moved] = current_room
  658. end -- if
  659.  
  660. -- clear for next time
  661. last_direction_moved = nil
  662. from_room = nil
  663.  
  664. end -- fix_up_exit
  665.  
  666. -- -----------------------------------------------------------------
  667. -- try to detect when we send a movement command
  668. -- -----------------------------------------------------------------
  669.  
  670. function OnPluginSent (sText)
  671. if valid_direction [sText] then
  672. last_direction_moved = valid_direction [sText]
  673. -- print ("Just moved", last_direction_moved)
  674. if current_room and rooms [current_room] then
  675. expected_exit = rooms [current_room].exits [last_direction_moved]
  676. if expected_exit then
  677. from_room = current_room
  678. end -- if
  679. -- print ("expected exit for this direction is to room", expected_exit)
  680. end -- if
  681. end -- if
  682. end -- function
  683.  
  684.  
  685. -- -----------------------------------------------------------------
  686. -- Plugin Install
  687. -- -----------------------------------------------------------------
  688.  
  689. function OnPluginInstall ()
  690.  
  691. config = {} -- in case not found
  692. setup_terrain_colors()
  693.  
  694. -- get saved configuration
  695. assert (loadstring (GetVariable ("config") or "")) ()
  696.  
  697.  
  698. -- initialize mapper
  699.  
  700. mapper.init { config = config,
  701. get_room = get_room,
  702. show_help = OnHelp, -- to show help
  703. room_click = room_click, -- called on RH click on room square
  704. timing = show_timing, -- want to see timing
  705. show_completed = show_completed, -- want to see "Speedwalk completed." message
  706. show_other_areas = show_other_areas, -- want to see areas other than the current one?
  707. show_up_down = show_up_down, -- want to follow up/down exits?
  708. show_area_exits = show_area_exits, -- want to see area exits?
  709. speedwalk_prefix = speedwalk_prefix, -- how to speedwalk
  710. }
  711. mapper.mapprint (string.format ("MUSHclient mapper installed, version %0.1f", mapper.VERSION))
  712.  
  713. -- open databases on disk
  714. db = assert (sqlite3.open(GetInfo (66) .. Trim (WorldAddress ()) .. "_" .. WorldPort () .. ".db"))
  715.  
  716. create_tables () -- create database structure if necessary
  717.  
  718. end -- OnPluginInstall
  719.  
  720. -- -----------------------------------------------------------------
  721. -- Plugin Save State
  722. -- -----------------------------------------------------------------
  723.  
  724. function OnPluginSaveState ()
  725. mapper.save_state ()
  726. SetVariable ("config", "config = " .. serialize.save_simple (config))
  727. end -- OnPluginSaveState
  728.  
  729. function map_resume (name, line, wildcards)
  730.  
  731. local wanted = mapper.last_hyperlink_uid or mapper.last_speedwalk_uid
  732.  
  733. if not wanted then
  734. mapper.print "No outstanding speedwalks or hyperlinks."
  735. return
  736. end -- if nothing to do
  737.  
  738. -- find desired room
  739. mapper.find (
  740. function (uid)
  741. return uid == wanted, uid == wanted
  742. end, -- function
  743. show_vnums, -- show vnum?
  744. 1, -- how many to expect
  745. true -- just walk there
  746. )
  747.  
  748. end -- map_resume
  749.  
  750. function map_goto (name, line, wildcards)
  751.  
  752. local wanted = wildcards [1]
  753.  
  754. -- check valid string
  755. if string.match (wanted, "%X") then
  756. mapper.maperror ("Room number must be hex string (0-9, A-F), you entered: " .. wanted)
  757. return
  758. end -- if
  759.  
  760. -- internally rooms are upper-case hex
  761. wanted = wanted:upper ()
  762.  
  763. -- see if already there
  764. if current_room and string.match (current_room, "^" .. wanted) then
  765. mapper.mapprint ("You are already in that room.")
  766. return
  767. end -- if
  768.  
  769. -- find desired room
  770. mapper.find (
  771. function (uid)
  772. local found = string.match (uid, "^" .. wanted)
  773. return found, found
  774. end, -- function
  775. show_vnums, -- show vnum?
  776. 1, -- how many to expect
  777. true -- just walk there
  778. )
  779.  
  780. end -- map_goto
  781.  
  782. function map_where (name, line, wildcards)
  783.  
  784. if not mapper.check_we_can_find () then
  785. return
  786. end -- if
  787.  
  788. local wanted = wildcards [1]
  789.  
  790. if current_room and wanted == current_room then
  791. mapper.mapprint ("You are already in that room.")
  792. return
  793. end -- if
  794.  
  795. local paths = mapper.find_paths (current_room,
  796. function (uid)
  797. return uid == wanted, -- wanted room?
  798. uid == wanted -- stop searching?
  799. end)
  800.  
  801. local uid, item = next (paths, nil) -- extract first (only) path
  802.  
  803. -- nothing? room not found
  804. if not item then
  805. mapper.mapprint (string.format ("Room %s not found", wanted))
  806. return
  807. end -- if
  808.  
  809. -- turn into speedwalk
  810. local path = mapper.build_speedwalk (item.path)
  811.  
  812. -- display it
  813. mapper.mapprint (string.format ("Path to %s is: %s", wanted, path))
  814.  
  815. end -- map_where
  816.  
  817. function OnHelp ()
  818. mapper.mapprint (string.format ("[MUSHclient mapper, version %0.1f]", mapper.VERSION))
  819. mapper.mapprint (world.GetPluginInfo (world.GetPluginID (), 3))
  820. end
  821.  
  822.  
  823.  
  824. room_not_in_database = {}
  825. room_in_database = {}
  826.  
  827. function dbcheck (code)
  828.  
  829. if code ~= sqlite3.OK and -- no error
  830. code ~= sqlite3.ROW and -- completed OK with another row of data
  831. code ~= sqlite3.DONE then -- completed OK, no more rows
  832. local err = db:errmsg () -- the rollback will change the error message
  833. db:exec ("ROLLBACK") -- rollback any transaction to unlock the database
  834. error (err, 2) -- show error in caller's context
  835. end -- if
  836.  
  837. end -- dbcheck
  838.  
  839. function fixsql (s)
  840.  
  841. if s then
  842. return "'" .. (string.gsub (s, "'", "''")) .. "'" -- replace single quotes with two lots of single quotes
  843. else
  844. return "NULL"
  845. end -- if
  846. end -- fixsql
  847.  
  848. function fixbool (b)
  849. if b then
  850. return 1
  851. else
  852. return 0
  853. end -- if
  854. end -- fixbool
  855.  
  856. function load_room_from_database (uid)
  857.  
  858. local room
  859.  
  860. assert (uid, "No UID supplied to load_room_from_database")
  861.  
  862. -- if not in database, don't look again
  863. if room_not_in_database [uid] then
  864. return nil
  865. end -- no point looking
  866.  
  867. for row in db:nrows(string.format ("SELECT * FROM rooms WHERE uid = %s", fixsql (uid))) do
  868. room = {
  869. name = row.name,
  870. area = row.area,
  871. description = row.description,
  872. shop = row.shop,
  873. train = row.train,
  874. notes = row.notes,
  875. exits = {} }
  876.  
  877. for exitrow in db:nrows(string.format ("SELECT * FROM exits WHERE fromuid = %s", fixsql (uid))) do
  878. room.exits [exitrow.dir] = tostring (exitrow.touid)
  879. end -- for each exit
  880.  
  881. end -- finding room
  882.  
  883. if room then
  884. rooms [uid] = room
  885. return room
  886. end -- if found
  887.  
  888. room_not_in_database [uid] = true
  889. return nil
  890.  
  891. end -- load_room_from_database
  892.  
  893.  
  894. function save_room_to_database (uid, title, description)
  895.  
  896. assert (uid, "No UID supplied to save_room_to_database")
  897.  
  898. dbcheck (db:execute (string.format (
  899. "INSERT INTO rooms (uid, name, description, date_added) VALUES (%s, %s, %s, DATETIME('NOW'));",
  900. fixsql (uid),
  901. fixsql (title),
  902. fixsql (description)
  903. )))
  904.  
  905. dbcheck (db:execute (string.format ([[
  906. INSERT INTO rooms_lookup (uid, name, description) VALUES (%s, %s, %s);
  907. ]], fixsql (uid),
  908. fixsql (title),
  909. fixsql (description)
  910. )))
  911.  
  912. room_not_in_database [uid] = false
  913.  
  914. if show_database_mods then
  915. mapper.mapprint ("Added room", uid, "to database. Name:", title)
  916. end -- if
  917.  
  918. end -- function save_room_to_database
  919.  
  920. function save_exits_to_database (uid, exits)
  921.  
  922. for dir in string.gmatch (exits, "%a+") do
  923.  
  924. -- fix up in and out
  925. dir = ({ ['i'] = "in", o = "out", }) [dir] or dir
  926.  
  927. dbcheck (db:execute (string.format ([[
  928. INSERT INTO exits (dir, fromuid, touid, date_added)
  929. VALUES (%s, %s, %s, DATETIME('NOW'));
  930. ]], fixsql (dir), -- direction (eg. "n")
  931. fixsql (uid), -- from current room
  932. fixsql (-666) -- destination room (not known)
  933. )))
  934. if show_database_mods then
  935. -- mapper.mapprint ("Added unknown exit", dir, "from room", uid, "to database.")
  936. end -- if
  937.  
  938. end -- for each exit
  939.  
  940. end -- function save_exits_to_database
  941.  
  942.  
  943. function create_tables ()
  944. -- create rooms table
  945. dbcheck (db:execute[[
  946.  
  947. PRAGMA foreign_keys = ON;
  948. PRAGMA journal_mode = WAL;
  949.  
  950. CREATE TABLE IF NOT EXISTS rooms (
  951. roomid INTEGER PRIMARY KEY AUTOINCREMENT,
  952. uid TEXT NOT NULL, -- vnum or how the MUD identifies the room
  953. name TEXT, -- name of room
  954. description TEXT, -- description
  955. terrain TEXT, -- which building it is in
  956. shop INTEGER, -- 1 = shop here
  957. train INTEGER, -- 1 = trainer here
  958. notes TEXT, -- player notes
  959. date_added DATE, -- date added to database
  960. UNIQUE (uid)
  961. );
  962. CREATE INDEX IF NOT EXISTS shop_index ON rooms (shop);
  963. CREATE INDEX IF NOT EXISTS train_index ON rooms (train);
  964.  
  965. CREATE TABLE IF NOT EXISTS exits (
  966. exitid INTEGER PRIMARY KEY AUTOINCREMENT,
  967. dir TEXT NOT NULL, -- direction, eg. "n", "s"
  968. fromuid TEXT NOT NULL, -- exit from which room (in rooms table)
  969. touid TEXT NOT NULL, -- exit to which room (in rooms table)
  970. date_added DATE, -- date added to database
  971. FOREIGN KEY(fromuid) REFERENCES rooms(uid)
  972. );
  973. CREATE INDEX IF NOT EXISTS fromuid_index ON exits (fromuid);
  974. CREATE INDEX IF NOT EXISTS touid_index ON exits (touid);
  975.  
  976. ]])
  977.  
  978. -- check if rooms_lookup table exists
  979. local table_exists
  980. for a in db:nrows "SELECT * FROM sqlite_master WHERE name = 'rooms_lookup' AND type = 'table'" do
  981. table_exists = true
  982. end -- for
  983.  
  984. if not table_exists then
  985. dbcheck (db:execute "CREATE VIRTUAL TABLE rooms_lookup USING FTS3(uid, name, description);")
  986. -- in case we only deleted the rooms_lookup table to save space in the download
  987. dbcheck (db:execute "INSERT INTO rooms_lookup (uid, name, description) SELECT uid, name, description FROM rooms;")
  988. end -- if
  989.  
  990.  
  991. end -- function create_tables
  992.  
  993. function room_edit_bookmark (room, uid)
  994.  
  995. local notes = room.notes or ""
  996.  
  997. if notes ~= "" then
  998. newnotes = utils.inputbox ("Modify room comment (clear it to delete from database)", room.name, notes)
  999. else
  1000. newnotes = utils.inputbox ("Enter room comment (creates a bookmark for this room)", room.name, notes)
  1001. end -- if
  1002.  
  1003. if not newnotes then
  1004. return
  1005. end -- if cancelled
  1006.  
  1007. if newnotes == "" then
  1008. if notes == "" then
  1009. mapper.mapprint ("No comment entered, bookmark not saved.")
  1010. return
  1011. else
  1012. dbcheck (db:execute (string.format (
  1013. "UPDATE rooms SET notes = NULL WHERE uid = %s;",
  1014. fixsql (uid)
  1015. )))
  1016. mapper.mapprint ("Bookmark for room", uid, "deleted. Was previously:", notes)
  1017. rooms [uid].notes = nil
  1018. return
  1019. end -- if
  1020. end -- if
  1021.  
  1022. if notes == newnotes then
  1023. return -- no change made
  1024. end -- if
  1025.  
  1026. dbcheck (db:execute (string.format (
  1027. "UPDATE rooms SET notes = %s WHERE uid = %s;",
  1028. fixsql (newnotes),
  1029. fixsql (uid)
  1030. )))
  1031.  
  1032. if notes ~= "" then
  1033. mapper.mapprint ("Bookmark for room", uid, "changed to:", newnotes)
  1034. else
  1035. mapper.mapprint ("Bookmark added to room", uid, ":", newnotes)
  1036. end -- if
  1037.  
  1038. rooms [uid].notes = newnotes
  1039.  
  1040. end -- room_edit_bookmark
  1041.  
  1042. function room_toggle_shop (room, uid)
  1043.  
  1044. rooms [uid].shop = not rooms [uid].shop
  1045.  
  1046. dbcheck (db:execute (string.format (
  1047. "UPDATE rooms SET shop = %i WHERE uid = %s;",
  1048. fixbool (rooms [uid].shop),
  1049. fixsql (uid)
  1050. )))
  1051.  
  1052. if rooms [uid].shop then
  1053. mapper.mapprint ("Room", uid, "marked as a shop")
  1054. else
  1055. mapper.mapprint ("Room", uid, "not a shop any more")
  1056. end
  1057.  
  1058. mapper.draw (current_room)
  1059.  
  1060. end -- room_toggle_shop
  1061.  
  1062. function room_toggle_train (room, uid)
  1063.  
  1064. rooms [uid].train = not rooms [uid].train
  1065.  
  1066. dbcheck (db:execute (string.format (
  1067. "UPDATE rooms SET train = %i WHERE uid = %s;",
  1068. fixbool (rooms [uid].train),
  1069. fixsql (uid)
  1070. )))
  1071.  
  1072. if rooms [uid].train then
  1073. mapper.mapprint ("Room", uid, "marked as a training room")
  1074. else
  1075. mapper.mapprint ("Room", uid, "not a training room any more")
  1076. end
  1077.  
  1078. mapper.draw (current_room)
  1079.  
  1080. end -- room_toggle_train
  1081.  
  1082. function setup_terrain_colors()
  1083. terrain_color["0"]=tonumber("0x000000")--NOTSET
  1084. terrain_color["1"]=tonumber("0x606060")--Building
  1085. terrain_color["2"]=tonumber("0x805a22")--Town
  1086. terrain_color["3"]=tonumber("0x00ff00")--FIELD
  1087. terrain_color["4"]=tonumber("0x00c000")--LFOREST
  1088. terrain_color["5"]=tonumber("0x008000")--TFOREST
  1089. terrain_color["6"]=tonumber("0x004000")--DFOREST
  1090. terrain_color["7"]=tonumber("0x406080")--SWAMP
  1091. terrain_color["8"]=tonumber("0x60a060")--PLATEAU
  1092. terrain_color["9"]=tonumber("0x00ffff")--SANDY
  1093. terrain_color["10"]=tonumber("0xc0c0c0")--MOUNTAIN
  1094. terrain_color["11"]=tonumber("0x808080")--ROCK
  1095. terrain_color["12"]=tonumber("0x00ffff")--DESERT
  1096. terrain_color["13"]=tonumber("0x805080")--TUNDRA
  1097. terrain_color["14"]=ColourNameToRGB("lightyellow")--BEACH
  1098. terrain_color["15"]=tonumber("0x409040")--HILL
  1099. terrain_color["16"]=tonumber("0xf0f080")--DUNES
  1100. terrain_color["17"]=tonumber("0x20c040")--JUNGLE
  1101. terrain_color["18"]=ColourNameToRGB("darkblue")--OCEAN
  1102. terrain_color["19"]=tonumber("0x00f0f0")--STREAM
  1103. terrain_color["20"]=ColourNameToRGB("blue")--RIVER
  1104. terrain_color["21"]=tonumber("0x021e6c")--UNDERWATER
  1105. terrain_color["22"]=tonumber("0x303030")--UNDERGROUND
  1106. terrain_color["23"]=tonumber("0x000000")--AIR
  1107. terrain_color["24"]=tonumber("0x82f8e6")--ICE
  1108. terrain_color["25"]=ColourNameToRGB("red")--LAVA
  1109. terrain_color["26"]=tonumber("0x806060")--RUINS
  1110. terrain_color["27"]=tonumber("0x404040")--CAVE
  1111. terrain_color["28"]=tonumber("0x907040")--CITY
  1112. terrain_color["29"]=tonumber("0x20a060")--MARSH
  1113. terrain_color["30"]=tonumber("0xf0f0a0")--WASTELAND
  1114. terrain_color["31"]=tonumber("0xffffff")--CLOUD
  1115. terrain_color["32"]=ColourNameToRGB("blue")--WATER
  1116. terrain_color["33"]=tonumber("0x808080")--METAL
  1117. terrain_color["34"]=tonumber("0x006000")--TAIGA
  1118. terrain_color["35"]=tonumber("0x404040")--SEWER
  1119. terrain_color["36"]=ColourNameToRGB("indigo")--SHADOW
  1120. -- end of terrain_color
  1121. end
  1122.  
  1123.  
  1124. function room_add_exit (room, uid)
  1125.  
  1126. local available = {
  1127. n = "North",
  1128. s = "South",
  1129. e = "East",
  1130. w = "West",
  1131. u = "Up",
  1132. d = "Down",
  1133. ne = "Northeast",
  1134. sw = "Southwest",
  1135. nw = "Northwest",
  1136. se = "Southeast",
  1137. ['in'] = "In",
  1138. out = "Out",
  1139. } -- end of available
  1140.  
  1141. -- remove existing exits
  1142. for k in pairs (room.exits) do
  1143. available [k] = nil
  1144. end -- for
  1145.  
  1146. if next (available) == nil then
  1147. utils.msgbox ("All exits already used.", "No free exits!", "ok", "!", 1)
  1148. return
  1149. end -- not known
  1150.  
  1151. local chosen_exit = utils.listbox ("Choose exit to add", "Exits ...", available )
  1152. if not chosen_exit then
  1153. return
  1154. end
  1155.  
  1156. exit_destination = utils.inputbox ("Enter destination room identifier (number) for " .. available [chosen_exit], room.name, "")
  1157.  
  1158. if not exit_destination then
  1159. return
  1160. end -- cancelled
  1161.  
  1162. -- look it up
  1163. local dest_room = rooms [exit_destination]
  1164.  
  1165. -- not cached - see if in database
  1166. if not dest_room then
  1167. dest_room = load_room_from_database (exit_destination)
  1168. rooms [exit_destination] = dest_room -- cache for later
  1169. end -- not in cache
  1170.  
  1171. if not dest_room then
  1172. utils.msgbox ("Room " .. exit_destination .. " does not exist.", "Room does not exist!", "ok", "!", 1)
  1173. return
  1174. end -- if still not there
  1175.  
  1176. dbcheck (db:execute (string.format ([[
  1177. INSERT INTO exits (dir, fromuid, touid, date_added)
  1178. VALUES (%s, %s, %s, DATETIME('NOW'));
  1179. ]], fixsql (chosen_exit), -- direction (eg. "n")
  1180. fixsql (uid), -- from current room
  1181. fixsql (exit_destination) -- destination room
  1182. )))
  1183. if show_database_mods then
  1184. mapper.mapprint ("Added exit", available [chosen_exit], "from room", uid, "to room", exit_destination, "to database.")
  1185. end -- if
  1186.  
  1187. -- update in-memory table
  1188. rooms [uid].exits [chosen_exit] = exit_destination
  1189.  
  1190. mapper.draw (current_room)
  1191.  
  1192. end -- room_add_exit
  1193.  
  1194.  
  1195. function room_delete_exit (room, uid)
  1196.  
  1197. local available = {
  1198. n = "North",
  1199. s = "South",
  1200. e = "East",
  1201. w = "West",
  1202. u = "Up",
  1203. d = "Down",
  1204. ne = "Northeast",
  1205. sw = "Southwest",
  1206. nw = "Northwest",
  1207. se = "Southeast",
  1208. ['in'] = "In",
  1209. out = "Out",
  1210. } -- end of available
  1211.  
  1212. -- remove non-existent exits
  1213. for k in pairs (available) do
  1214. if room.exits [k] then
  1215. available [k] = available [k] .. " --> " .. room.exits [k]
  1216. else
  1217. available [k] = nil
  1218. end -- if not a room exit
  1219. end -- for
  1220.  
  1221. if next (available) == nil then
  1222. utils.msgbox ("There are no exits from this room.", "No exits!", "ok", "!", 1)
  1223. return
  1224. end -- not known
  1225.  
  1226. local chosen_exit = utils.listbox ("Choose exit to delete", "Exits ...", available )
  1227. if not chosen_exit then
  1228. return
  1229. end
  1230.  
  1231. dbcheck (db:execute (string.format ([[
  1232. DELETE FROM exits WHERE dir = %s AND fromuid = %s;
  1233. ]], fixsql (chosen_exit), -- direction (eg. "n")
  1234. fixsql (uid) -- from current room
  1235. )))
  1236. if show_database_mods then
  1237. mapper.mapprint ("Deleted exit", available [chosen_exit], "from room", uid, "from database.")
  1238. end -- if
  1239.  
  1240. -- update in-memory table
  1241. rooms [uid].exits [chosen_exit] = nil
  1242.  
  1243. mapper.draw (current_room)
  1244.  
  1245. end -- room_delete_exit
  1246.  
  1247.  
  1248. function room_change_exit (room, uid)
  1249.  
  1250. local available = {
  1251. n = "North",
  1252. s = "South",
  1253. e = "East",
  1254. w = "West",
  1255. u = "Up",
  1256. d = "Down",
  1257. ne = "Northeast",
  1258. sw = "Southwest",
  1259. nw = "Northwest",
  1260. se = "Southeast",
  1261. ['in'] = "In",
  1262. out = "Out",
  1263. } -- end of available
  1264.  
  1265. -- remove non-existent exits
  1266. for k in pairs (available) do
  1267. if room.exits [k] then
  1268. available [k] = available [k] .. " --> " .. room.exits [k]
  1269. else
  1270. available [k] = nil
  1271. end -- if not a room exit
  1272. end -- for
  1273.  
  1274. if next (available) == nil then
  1275. utils.msgbox ("There are no exits from this room.", "No exits!", "ok", "!", 1)
  1276. return
  1277. end -- not known
  1278.  
  1279. local chosen_exit = utils.listbox ("Choose exit to change destination of:", "Exits ...", available )
  1280. if not chosen_exit then
  1281. return
  1282. end
  1283.  
  1284. exit_destination = utils.inputbox ("Enter destination room identifier (number) for " .. available [chosen_exit], room.name, "")
  1285.  
  1286. if not exit_destination then
  1287. return
  1288. end -- cancelled
  1289.  
  1290. -- look it up
  1291. local dest_room = rooms [exit_destination]
  1292.  
  1293. -- not cached - see if in database
  1294. if not dest_room then
  1295. dest_room = load_room_from_database (exit_destination)
  1296. rooms [exit_destination] = dest_room -- cache for later
  1297. end -- not in cache
  1298.  
  1299. if not dest_room then
  1300. utils.msgbox ("Room " .. exit_destination .. " does not exist.", "Room does not exist!", "ok", "!", 1)
  1301. return
  1302. end -- if still not there
  1303.  
  1304. dbcheck (db:execute (string.format ([[
  1305. UPDATE exits SET touid = %s WHERE dir = %s AND fromuid = %s;
  1306. ]], fixsql (exit_destination),
  1307. fixsql (chosen_exit), -- direction (eg. "n")
  1308. fixsql (uid) -- from current room
  1309. )))
  1310.  
  1311. if show_database_mods then
  1312. mapper.mapprint ("Modified exit", available [chosen_exit], "from room", uid, "to be to room", exit_destination, "in database.")
  1313. end -- if
  1314.  
  1315. -- update in-memory table
  1316. rooms [uid].exits [chosen_exit] = exit_destination
  1317. mapper.draw (current_room)
  1318.  
  1319. end -- room_change_exit
  1320.  
  1321. function room_click (uid, flags)
  1322.  
  1323. -- check we got room at all
  1324. if not uid then
  1325. return nil
  1326. end -- if
  1327.  
  1328. -- look it up
  1329. local room = rooms [uid]
  1330.  
  1331. -- not cached - see if in database
  1332. if not room then
  1333. room = load_room_from_database (uid)
  1334. rooms [uid] = room -- cache for later
  1335. end -- not in cache
  1336.  
  1337. if not room then
  1338. return
  1339. end -- if still not there
  1340.  
  1341. local handlers = {
  1342. { name = "Edit bookmark", func = room_edit_bookmark} ,
  1343. { name = "-", } ,
  1344. { name = "Add Exit", func = room_add_exit} ,
  1345. { name = "Change Exit", func = room_change_exit} ,
  1346. { name = "Delete Exit", func = room_delete_exit} ,
  1347. { name = "-", } ,
  1348. { name = "Toggle Shop", func = room_toggle_shop } ,
  1349. { name = "Toggle Trainer", func = room_toggle_train } ,
  1350. } -- handlers
  1351.  
  1352. local t, tf = {}, {}
  1353. for _, v in pairs (handlers) do
  1354. table.insert (t, v.name)
  1355. tf [v.name] = v.func
  1356. end -- for
  1357.  
  1358. local choice = WindowMenu (mapper.win,
  1359. WindowInfo (mapper.win, 14),
  1360. WindowInfo (mapper.win, 15),
  1361. table.concat (t, "|"))
  1362.  
  1363. local f = tf [choice]
  1364.  
  1365. if f then
  1366. f (room, uid)
  1367. end -- if handler found
  1368.  
  1369. end -- room_click
  1370.  
  1371.  
  1372. function map_find (name, line, wildcards)
  1373.  
  1374. local rooms = {}
  1375. local count = 0
  1376. local snippets = {}
  1377. local reset = ANSI (0)
  1378. local bold = ANSI (1)
  1379. local unbold = ANSI (22)
  1380.  
  1381. function show_snippet (uid)
  1382. AnsiNote (reset .. snippets [uid])
  1383. end -- show_snippet
  1384.  
  1385.  
  1386. -- find matching rooms using FTS3
  1387. for row in db:nrows(string.format (
  1388. [[
  1389. SELECT uid, name, snippet(rooms_lookup, '%s', '%s', ' ... ', -1, -10) AS snippet
  1390. FROM rooms_lookup
  1391. WHERE rooms_lookup MATCH %s]],
  1392. bold, unbold,
  1393. fixsql (wildcards [1]))) do
  1394. rooms [row.uid] = true
  1395. snippets [row.uid] = row.snippet
  1396. count = count + 1
  1397. end -- finding room
  1398.  
  1399. -- see if nearby
  1400. mapper.find (
  1401. function (uid)
  1402. local room = rooms [uid]
  1403. if room then
  1404. rooms [uid] = nil
  1405. end -- if
  1406. return room, next (rooms) == nil
  1407. end, -- function
  1408. show_vnums, -- show vnum?
  1409. count, -- how many to expect
  1410. false, -- don't auto-walk
  1411. show_snippet -- show find snippet
  1412. )
  1413.  
  1414. end -- map_find
  1415.  
  1416. function map_bookmarks (name, line, wildcards)
  1417.  
  1418. local rooms = {}
  1419. local count = 0
  1420.  
  1421. -- build table of special places (with info in them)
  1422. for row in db:nrows(string.format ("SELECT uid, notes FROM rooms WHERE notes IS NOT NULL")) do
  1423. rooms [row.uid] = capitalize (row.notes)
  1424. count = count + 1
  1425. end -- finding room
  1426.  
  1427. -- find such places
  1428. mapper.find (
  1429. function (uid)
  1430. local room = rooms [uid]
  1431. if room then
  1432. rooms [uid] = nil
  1433. end -- if
  1434. return room, next (rooms) == nil -- room will be type of info (eg. shop)
  1435. end, -- function
  1436. show_vnums, -- show vnum?
  1437. count, -- how many to expect
  1438. false -- don't auto-walk
  1439. )
  1440.  
  1441. end -- map_bookmarks
  1442.  
  1443. function map_find_special (which)
  1444.  
  1445. local rooms = {}
  1446. local count = 0
  1447.  
  1448. -- build table of special places (with info in them)
  1449. for row in db:nrows(string.format ("SELECT uid, name FROM rooms WHERE %s = 1", which)) do
  1450. rooms [row.uid] = true
  1451. count = count + 1
  1452. end -- finding room
  1453.  
  1454. -- find such places
  1455. mapper.find (
  1456. function (uid)
  1457. local room = rooms [uid]
  1458. if room then
  1459. rooms [uid] = nil
  1460. end -- if
  1461. return room, next (rooms) == nil -- room will be type of info (eg. shop)
  1462. end, -- function
  1463. show_vnums, -- show vnum?
  1464. count, -- how many to expect
  1465. false -- don't auto-walk
  1466. )
  1467.  
  1468. end -- map_find_special
  1469.  
  1470. function map_shops (name, line, wildcards)
  1471. map_find_special ("shop")
  1472. end -- map_shops
  1473.  
  1474. function map_trainers (name, line, wildcards)
  1475. map_find_special ("train")
  1476. end -- map_trainers
  1477.  
  1478. function manual_backup()
  1479. backup_databases(true)
  1480. end
  1481.  
  1482. function backup_databases(manual)
  1483. wait.make(function()
  1484.  
  1485. performing_maintenance = true
  1486. local success = false
  1487. maybe_Note("PERFORMING "..((manual and "MANUAL") or "AUTOMATIC").." DATABASE BACKUP. DON'T TOUCH ANYTHING!", manual)
  1488. if not checkDatabaseIntegrity(true) then
  1489. maybe_Note("ABORTING CURRENT BACKUP", manual)
  1490. if not compact_mode then Note("") end
  1491. Repaint()
  1492. db = assert (sqlite3.open(worldPath..".db")) -- try to re-open the database anyway
  1493. performing_maintenance = false
  1494. satisfy_broadcast_queue()
  1495. return
  1496. end
  1497. maybe_Note("BACKING UP DATABASE", manual)
  1498. Repaint()
  1499.  
  1500. backupPath = GetInfo(66).."db_backups\\"..sanitize_filename(WorldName())
  1501. firstBackup = backupPath..".db.Backup"
  1502. local ffi
  1503. if type(jit) == 'table' then
  1504. ffi = require("ffi")
  1505. ffi.cdef[[
  1506. bool CreateDirectoryA(const char *lpPathName, void *lpSecurityAttributes);
  1507. bool CopyFileA(const char* lpExistingFileName, const char * lpNewFileName, bool bFailIfExists);
  1508. unsigned long GetLastError(void);
  1509. ]]
  1510.  
  1511. succ = ffi.C.CreateDirectoryA(GetInfo(66).."db_backups\\", nil)
  1512. err_no = ffi.C.GetLastError()
  1513. else
  1514. succ, err_no = utils.shellexecute("cmd", "/C mkdir db_backups", GetInfo(66), "open", 0)
  1515. end
  1516. if succ == false and err_no ~= 183 and err_no ~= 127 then
  1517. -- error
  1518. ColourNote("yellow","red", "ERROR ("..err_no..") trying to CreateDirectory: "..GetInfo(66).."db_backups\\\n")
  1519. else
  1520. -- successfully created the backup directory
  1521.  
  1522. -- record when the backup occurs
  1523. dbCheckExecute(string.format("INSERT OR REPLACE INTO storage (name, data) VALUES (%s,%s);", fixsql("backup_date"), fixsql(os.date("%b %d, %Y - %X"))))
  1524.  
  1525. if db:isopen() then
  1526. db:close() -- always close the database before copying
  1527. end
  1528.  
  1529. -- make new backup
  1530. if use_compression == 1 then
  1531.  
  1532. local tmp = GetInfo(66).."aard_package_temp_file.txt" -- temp file for recording output
  1533. -- It's not so simple to catch errors from this, so record the output and look at it later.
  1534. -- Use pushd/popd because cd can't @!#($$# access UNC paths.
  1535. local execute_string = "pushd "..quote(GetInfo(66)).." & zip -j -v -T -lf "..quote(tmp).." "..quote(firstBackup..".zip").." "..quote(worldPath..".db").." & popd"
  1536.  
  1537. function file_exists(name)
  1538. local f=io.open(name,"r")
  1539. if f~=nil then io.close(f) return true else return false end
  1540. end
  1541. function file_is_writable(name)
  1542. local f=io.open(name,"w")
  1543. if f~=nil then io.close(f) return true else return false end
  1544. end
  1545.  
  1546. if file_exists(tmp) and not file_is_writable(tmp) then
  1547. ColourNote("yellow","red", "ERROR executing system command: "..execute_string.."\n")
  1548. ColourNote("yellow", "red", "Log file "..quote(tmp).." is not writeable. Do you have write permission?") -- flaming output
  1549. -- failure
  1550. else
  1551. utils.shellexecute("cmd", "/C "..execute_string, "", "open", 0)
  1552.  
  1553. local zip_done = false
  1554. local zip_error = false
  1555. local zipstarttime = utils.timer()
  1556. local zip_lines
  1557. while not zip_done do
  1558. zip_lines = {}
  1559. if file_exists(tmp) then
  1560. for line in io.lines(tmp) do
  1561. table.insert(zip_lines, line)
  1562. end
  1563. os.remove(tmp) -- remove temp file
  1564. end
  1565.  
  1566. for _,line in ipairs(zip_lines) do
  1567. if line:find("zip warning") or line:find("zip error") or line:find("zip I/O error") then
  1568. zip_done = true
  1569. zip_error = true
  1570. end
  1571. if line:find("zip OK") then
  1572. zip_done = true
  1573. end
  1574. end
  1575.  
  1576. if zip_done then break end
  1577. if utils.timer() - zipstarttime > 30 then
  1578. -- we have to give up EVENTUALLY
  1579. break
  1580. end
  1581. wait.time(0.1)
  1582. end
  1583.  
  1584. if zip_error then
  1585. -- something went wrong with the compression
  1586. -- we expect to see some lines with the last line showing a passing test
  1587. ColourNote("yellow","red", "ERROR executing system command: "..execute_string.."\n")
  1588. for _,v in ipairs(zip_lines) do
  1589. ColourNote("yellow", "red", v) -- flaming output
  1590. end
  1591. -- failure
  1592. else
  1593. for _,v in ipairs(zip_lines) do
  1594. maybe_Note(v, manual) -- less intense output
  1595. end
  1596. success = true
  1597. end
  1598. end
  1599. else
  1600. -- no compression, just copy
  1601. if type(jit) == 'table' then
  1602. succ = ffi.C.CopyFileA(worldPath..".db", firstBackup, false)
  1603. err_no = ffi.C.GetLastError()
  1604. else
  1605. -- succ, err_no = utils.shellexecute("cmd", "/C copy "..worldPath..".db "..firstBackup, "", "open", 0);
  1606. local inp, outp, errmsg
  1607. succ = false
  1608. inp, errmsg, err_no = io.open(worldPath..".db", "rb")
  1609. if err_no == nil then
  1610. outp, errmsg, err_no = io.open(firstBackup, "wb")
  1611. if err_no == nil then
  1612. local data = inp:read("*all")
  1613. outp:write(data)
  1614. outp:close()
  1615. inp:close()
  1616. succ = true
  1617. end
  1618. end
  1619. if succ == false then
  1620. ColourNote("yellow","red", "ERROR: "..errmsg)
  1621. end
  1622. end
  1623. if succ == false then
  1624. ColourNote("yellow","red", "ERROR ("..err_no..") trying to copy database from '"..worldPath..".db' to '"..firstBackup.."'")
  1625. else
  1626. success = true
  1627. end
  1628. end
  1629. end
  1630.  
  1631. if success then
  1632. rotate_backups(manual) -- rotate backup folders (obviously)
  1633. maybe_Note("FINISHED DATABASE BACKUP. YOU MAY NOW GO BACK TO MUDDING.", manual)
  1634. else
  1635. Note("ABORTING BACKUP.")
  1636. CorruptionAlert()
  1637. end
  1638. if not compact_mode then Note("") end
  1639. db = assert (sqlite3.open(worldPath..".db")) -- re-open database
  1640. Repaint()
  1641. performing_maintenance = false
  1642. satisfy_broadcast_queue()
  1643. end)
  1644. end
  1645.  
  1646.  
  1647. function Door_Closed (name, line, wildcards)
  1648.  
  1649. local dirs = {
  1650. n = "north",
  1651. s = "south",
  1652. e = "east",
  1653. w = "west",
  1654. u = "up",
  1655. d = "down",
  1656. ne = "northeast",
  1657. sw = "southwest",
  1658. nw = "northwest",
  1659. se = "southeast",
  1660. ['in'] = "in",
  1661. out = "out",
  1662. } -- end of available
  1663.  
  1664. if last_direction_moved then
  1665. Send ("open " .. dirs [last_direction_moved])
  1666. Send (dirs [last_direction_moved])
  1667. end -- if
  1668.  
  1669. end -- Door_Closed
  1670.  
  1671. ]]>
  1672. </script>
  1673.  
  1674.  
  1675. </muclient>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement