From a3efc91ab9f3c4eb4981edebe12ce6f6ebd8c2e8 Mon Sep 17 00:00:00 2001 From: NullQuery Date: Sun, 12 Jul 2015 13:37:18 +0200 Subject: [PATCH] Modifications to crew monitoring computer, procqueue and html_interface. - procqueue: You can now schedule procs to be executed at some point in the future. - Crew monitoring: see issue #10498 - html_interface: fix for Nanotrasen-style windows, refactor Javascript files and move them in their own folder - Includes changelog entry for the crew monitoring changes. --- code/controllers/subsystem/procqueue.dm | 55 ++-- code/game/machinery/computer/crew.css | 37 ++- code/game/machinery/computer/crew.dm | 25 +- code/game/machinery/computer/crew.js | 240 +++++++++++++++--- .../{ => css}/bootstrap.min.css | 0 .../{ => css}/html_interface.css | 0 code/modules/html_interface/html_interface.dm | 25 +- .../html_interface/html_interface.html | 1 + .../html_interface/{ => js}/bootstrap.min.js | 0 .../html_interface/{ => js}/html_interface.js | 0 .../html_interface/{ => js}/jquery.min.js | 0 .../html_interface/nanotrasen/nanotrasen.dm | 2 +- html/changelogs/nullquery-hi-extended.yml | 10 + 13 files changed, 312 insertions(+), 83 deletions(-) rename code/modules/html_interface/{ => css}/bootstrap.min.css (100%) rename code/modules/html_interface/{ => css}/html_interface.css (100%) rename code/modules/html_interface/{ => js}/bootstrap.min.js (100%) rename code/modules/html_interface/{ => js}/html_interface.js (100%) rename code/modules/html_interface/{ => js}/jquery.min.js (100%) create mode 100644 html/changelogs/nullquery-hi-extended.yml diff --git a/code/controllers/subsystem/procqueue.dm b/code/controllers/subsystem/procqueue.dm index daf762927c9..be9323e5638 100644 --- a/code/controllers/subsystem/procqueue.dm +++ b/code/controllers/subsystem/procqueue.dm @@ -9,38 +9,53 @@ var/datum/subsystem/procqueue/procqueue /datum/subsystem/procqueue/fire() if (queue.len) var/list/L = list() - var/key for (var/datum/procqueue_item/item in queue) - key = "[item.ref]_[item.procname]" + if (!item.runafter || item.runafter-- <= 0) + if (!(item.id in L)) + if (item.args) call(item.ref, item.procname)(arglist(item.args)) + else call(item.ref, item.procname)() - if (item.args) - key += "(" - var/first = 1 - for (var/a in item.args) - if (!first) key += "," - key += "[a]" - first = 0 - key += ")" + L.Add(item.id) - if (!(key in L)) - if (item.args) call(item.ref, item.procname)(arglist(item.args)) - else call(item.ref, item.procname)() - - L.Add(key) - - queue.Cut() + queue.Remove(item) /datum/subsystem/procqueue/proc/queue(ref, procname, ...) + var/list/L = args.Copy() + + L.Insert(1, 0) + + src.schedule(arglist(L)) + +/datum/subsystem/procqueue/proc/schedule(time, ref, procname, ...) var/datum/procqueue_item/item = new/datum/procqueue_item item.ref = ref item.procname = procname - if (args.len > 2) - item.args = args.Copy(3) + if (args.len > 3) + item.args = args.Copy(4) + + if (time > 0) item.runafter = time / 10 + + item.id = "[item.ref]_[item.procname]" + + if (item.args) + item.id += "(" + var/first = 1 + for (var/a in item.args) + if (!first) item.id += "," + item.id += "[a]" + first = 0 + item.id += ")" + + for (var/datum/procqueue_item/candidate in queue) + if (candidate.id == item.id) + return src.queue.Insert(1, item) +/datum/procqueue_item/var/id +/datum/procqueue_item/var/runafter /datum/procqueue_item/var/ref /datum/procqueue_item/var/procname -/datum/procqueue_item/var/list/args \ No newline at end of file +/datum/procqueue_item/var/list/args diff --git a/code/game/machinery/computer/crew.css b/code/game/machinery/computer/crew.css index 49c0c92437a..2ebb2e2dda8 100644 --- a/code/game/machinery/computer/crew.css +++ b/code/game/machinery/computer/crew.css @@ -1,6 +1,6 @@ body { - padding-left: 490px; + padding-left: 53%; cursor: default; } @@ -15,11 +15,19 @@ body top: 8px; left: 8px; border: 2px inset #888; + overflow: hidden; + min-width: 480px; + min-height: 480px; + width: 53%; + height: 100%; + max-width: 480px; + max-height: 480px; } #textbased { width: 100%; + padding-left: 20px; } #textbased table @@ -51,11 +59,10 @@ body clear: both; } -a { display: none; } - .health { width: 16px; + height: 16px; background-color: #FFF; border: 1px solid #434343; position: relative; @@ -69,6 +76,12 @@ a { display: none; } .health-1 { background-color: #e74c3c; } .health-0 { background-color: #ed2814; } +.health > div +{ + margin-left: 20px; + margin-top: -4px; +} + .tt { position: relative; @@ -106,7 +119,6 @@ a { display: none; } .dot { - transition: .2s all; position: absolute; width: 3px; height: 3px; @@ -122,4 +134,21 @@ a { display: none; } height: 8px; margin-top: -2px; margin-left: -3px; +} + +.zoom +{ + position: fixed; + left: 53%; + top: 10px; + display: block; + width: 24px; + height: 24px; + text-align: center; + margin-left: 20px !important; +} + +.zoom.in +{ + margin-left: -3px !important; } \ No newline at end of file diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 53b62bee531..3f2c3d52e75 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -97,12 +97,16 @@ var/global/datum/crewmonitor/crewmonitor = new hi = src.interfaces["[z]"] - hi.updateContent("content", "Switch to mini map Switch to text-based
") + hi.updateContent("content", "
+-
") src.update(z, TRUE) else hi = src.interfaces["[z]"] + // Debugging purposes + mob << browse_rsc(file("code/game/machinery/computer/crew.js"), "crew.js") + mob << browse_rsc(file("code/game/machinery/computer/crew.css"), "crew.css") + hi = src.interfaces["[z]"] hi.show(mob) src.updateFor(mob, hi, z) @@ -110,13 +114,13 @@ var/global/datum/crewmonitor/crewmonitor = new /datum/crewmonitor/proc/updateFor(hclient_or_mob, datum/html_interface/hi, z) // This check will succeed if updateFor is called after showing to the player, but will fail // on regular updates. Since we only really need this once we don't care if it fails. - var/list/parameters = list(ismob(hclient_or_mob) && isAI(hclient_or_mob) ? "true" : "false") - - hi.callJavaScript("clearAll", parameters, hclient_or_mob) + hi.callJavaScript("clearAll", null, hclient_or_mob) for (var/list/L in data) hi.callJavaScript("add", L, hclient_or_mob) + hi.callJavaScript("onAfterUpdate", null, hclient_or_mob) + /datum/crewmonitor/proc/update(z, ignore_unused = FALSE) if (src.interfaces["[z]"]) var/datum/html_interface/hi = src.interfaces["[z]"] @@ -234,17 +238,6 @@ var/global/datum/crewmonitor/crewmonitor = new if (AI && AI.eyeobj && current_loc == AI.eyeobj.loc) AI.switchCamera(C) -/* -/proc/crewscan() - var/list/tracked = list() - for(var/mob/living/carbon/human/H in mob_list) - if(istype(H.w_uniform, /obj/item/clothing/under)) - var/obj/item/clothing/under/U = H.w_uniform - if(U.has_sensor && U.sensor_mode) - tracked.Add(H) - return tracked -*/ - /mob/living/carbon/human/Move() if (src.w_uniform) var/old_z = src.z @@ -257,7 +250,7 @@ var/global/datum/crewmonitor/crewmonitor = new return ..() /datum/crewmonitor/proc/queueUpdate(z) - procqueue.queue(crewmonitor, "update", z) + procqueue.schedule(50, crewmonitor, "update", z) /datum/crewmonitor/proc/generateMiniMaps() spawn diff --git a/code/game/machinery/computer/crew.js b/code/game/machinery/computer/crew.js index 6db71d7d3c4..e29fda21061 100644 --- a/code/game/machinery/computer/crew.js +++ b/code/game/machinery/computer/crew.js @@ -207,34 +207,177 @@ * Crew manifest script */ -var isAI = null; +var minimap_height = 480; var scale_x; var scale_y; +var zoom_factor = null; +var minimap_mousedown = false; +var minimap_mousedown_scrollLeft; +var minimap_mousedown_scrollTop; +var minimap_mousedown_clientX; +var minimap_mousedown_clientY; +var minimap_mousedown_counter = 0; function disableSelection(){ return false; }; $(window).on("onUpdateContent", function() { - $("#textbased").html("

Name

 

Position

"); + $("#textbased").html("

Name

 

Position

"); - $("#minimap").append(""); + $("#minimap").append(""); $("body")[0].onselectstart = disableSelection; - var width = $("#minimap").width(); - - scale_x = width / (maxx * tile_size); - scale_y = width / (maxy * tile_size); // height is assumed to be the same - $("#minimap").on("click", function(e) { - var x = ((((e.clientX - 8) / scale_x) / tile_size) + 1).toFixed(0); - var y = ((maxy - (((e.clientY - 8) / scale_y) / tile_size)) + 1).toFixed(0); + if (!$(e.target).is(".zoom,.dot")) + { + var x = ((((e.clientX + this.scrollLeft - 8) / scale_x) / tile_size) + 1).toFixed(0); + var y = ((maxy - (((e.clientY + this.scrollTop - 8) / scale_y) / tile_size)) + 1).toFixed(0); - window.location.href = "byond://?src=" + hSrc + "&action=select_position&x=" + x + "&y=" + y; + window.location.href = "byond://?src=" + hSrc + "&action=select_position&x=" + x + "&y=" + y; + } + }).on("mousedown", function(e) + { + minimap_mousedown_scrollLeft = this.scrollLeft; + minimap_mousedown_scrollTop = this.scrollTop; + minimap_mousedown_clientX = e.clientX; + minimap_mousedown_clientY = e.clientY; + + var c = ++minimap_mousedown_counter; + setTimeout(function() + { + if (c == minimap_mousedown_counter) + { + minimap_mousedown = true; + $("#minimap").css("cursor", "move"); + } + }, 100); }); + + $(document).on("mousemove", function(e) + { + if (minimap_mousedown) + { + var offsetX = minimap_mousedown_clientX - e.clientX; + var offsetY = minimap_mousedown_clientY - e.clientY; + + var minimap = document.getElementById("minimap"); + minimap.scrollLeft = minimap_mousedown_scrollLeft + offsetX; + minimap.scrollTop = minimap_mousedown_scrollTop + offsetY; + } + }).on("mouseup", function() + { + ++minimap_mousedown_counter; + if (minimap_mousedown) + { + document.body.focus(); + minimap_mousedown = false; + $("#minimap").css("cursor", ""); + } + }); + + $(window).on("resize", onResize); + + scaleMinimap(1.00); }); +function zoomIn() +{ + scaleMinimap(Math.min(6.00, zoom_factor + 1.00)); +} + +function zoomOut() +{ + scaleMinimap(Math.max(1.00, zoom_factor - 1.00)); +} + +function scaleMinimap(factor) +{ + var $minimap = $("#minimap"); + + if (factor != zoom_factor) + { + zoom_factor = factor; + + var old_map_width = $minimap.width(); + var old_map_height = $minimap.height(); + var old_canvas_size = $("#minimap > img").height(); // height is assumed to be the same + var new_canvas_size = minimap_height * factor; // ditto + + var old_scrollLeft = $minimap[0].scrollLeft; + var old_scrollTop = $minimap[0].scrollTop; + + var old_factor = old_canvas_size / minimap_height; + var diff_factor = factor - old_factor; + + var old_centerX = ((old_map_width / 2) * diff_factor) + old_scrollLeft; + var old_centerY = ((old_map_height / 2) * diff_factor) + old_scrollTop; + + $("#minimap > img").css("height", new_canvas_size + "px"); + $minimap.css("max-width", new_canvas_size + "px"); + + var new_map_width = $minimap.width(); + var new_map_height = $minimap.height(); + + var new_centerX = (new_map_width / 2) + old_centerX; + var new_centerY = (new_map_height / 2) + old_centerY; + + var scrollLeft = new_centerX - (new_map_width / 2); + var scrollTop = new_centerY - (new_map_height / 2); + + scale_x = new_canvas_size / (maxx * tile_size); + scale_y = new_canvas_size / (maxy * tile_size); + + onResize(); + + $minimap[0].scrollLeft = scrollLeft; + $minimap[0].scrollTop = scrollTop; + + $(".dot").each(function() + { + var $this = $(this); + var tx = translateX(parseInt($this.attr("data-x"))); + var ty = translateY(parseInt($this.attr("data-y"))); + + // Workaround for IE bug where it doesn't modify the positions. + setTimeout(function(){ $this.css({ "top": ty + "px", "left": tx + "px" });}, 0); + }); + } +} + +function onResize() +{ + if (zoom_factor == 1.00) + { + $(".zoom").css("left", "442px"); + $("#minimap").css("max-height", Math.min($(window).height() - 16, 480) + "px"); + } + else + { + $(".zoom").css("left", ($("#minimap").width() - 34) + "px"); + $("#minimap").css("max-height", Math.min($(window).height() - 16, $("#minimap > img").height()) + "px"); + } + + if (expandHealth()) + { + $(".colhealth").css("width", "150px"); + $(".health").removeClass("tt"); + } + else + { + $(".colhealth").css("width", "24px"); + $(".health").addClass("tt"); + } + + $("body").css("padding-left", Math.min($(window).width() - 400, $("#minimap").width() - 10) + "px"); +} + +function expandHealth() +{ + return $("#textbased").width() > 510; +} + var updateMap = true; function switchTo(i) @@ -251,13 +394,20 @@ function switchTo(i) } } -function clearAll(ai) +var orig_scrollTop = 0; + +function clearAll() { - if (isAI === null) { isAI = (ai == "true"); } + orig_scrollTop = $(window).scrollTop(); $("#textbased-tbody").empty(); $("#minimap .dot").remove(); } +function onAfterUpdate() +{ + $(window).scrollTop(orig_scrollTop); +} + function isHead(ijob) { return (ijob % 10 == 0); // head roles always end in 0 @@ -291,21 +441,17 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, var avg_dam = parseInt(dam1) + parseInt(dam2) + parseInt(dam3) + parseInt(dam4); var i; - if (isAI) { i = -1; } - else - { - if (avg_dam <= 0) { i = 5; } - else if (avg_dam <= 25) { i = 4; } - else if (avg_dam <= 50) { i = 3; } - else if (avg_dam <= 75) { i = 2; } - else { i = 0; } - } + if (avg_dam <= 0) { i = 5; } + else if (avg_dam <= 25) { i = 4; } + else if (avg_dam <= 50) { i = 3; } + else if (avg_dam <= 75) { i = 2; } + else { i = 0; } - healthHTML = "
(" + dam1 + "/" + dam2 + "/" + dam3 + "/" + dam4 + ")
"; + healthHTML = "
(" + dam1 + "/" + dam2 + "/" + dam3 + "/" + dam4 + ")
"; } else { - healthHTML = "
Not Available
"; + healthHTML = "
Not Available
"; } var trElem = $("").attr("data-ijob", ijob); @@ -341,14 +487,21 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, trElem.append(tdElem); - tdElem = $(""); + tdElem = $(""); tdElem.html(healthHTML); trElem.append(tdElem); tdElem = $(""); - if (area && pos_x && pos_y) { tdElem.append($("
").text(area).addClass("tt").append($("
").append($("").text("(" + pos_x + ", " + pos_y + ")")))); } + if (area && pos_x && pos_y) + { + tdElem.append($("
").text(area).addClass("tt").append($("
").append($("").text("(" + pos_x + ", " + pos_y + ")")))); + tdElem.css("cursor", "pointer").on("click", function() + { + window.clipboardData.setData("Text", pos_x + ", " + pos_y); + }); + } else { tdElem.text("Not Available"); } trElem.append(tdElem); @@ -363,20 +516,24 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, var x = parseInt(pos_x); var y = maxy - parseInt(pos_y); - var tx = (translate(x - 1, scale_x) - 1.5).toFixed(0); - var ty = (translate(y - 1, scale_y) + 3).toFixed(0); + var tx = translateX(x); + var ty = translateY(y); - var dotElem = $("
"); + var dotElem = $("
"); $("#minimap").append(dotElem); + var counter = 0; + function enable() { + ++counter; dotElem.addClass("active").css({ "border-color": color }); } function disable() { + ++counter; dotElem.removeClass("active").css({ "border-color": "transparent" }); } @@ -388,7 +545,27 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, window.location.href = "byond://?src=" + hSrc + "&action=select_person&name=" + encodeURIComponent(name); } - trElem.on("mouseover", enable).on("mouseout", disable).on("click", click); + trElem.on("mouseover", function() + { + enable(); + + if (zoom_factor > 1.00) + { + var c = counter; + setTimeout(function() + { + if (c == counter) + { + var minimap = document.getElementById("minimap"); + var half = $(minimap).height() / 2; + var offset = $(dotElem).offset(); + + minimap.scrollLeft = offset.left + minimap.scrollLeft - half; + minimap.scrollTop = offset.top + minimap.scrollTop - half; + } + }, 100); + } + }).on("mouseout", disable).on("click", click); dotElem.on("mouseover", function() { trElem.addClass("hover"); @@ -402,6 +579,9 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, } } +function translateX(n) { return (translate(n - 1.5, scale_x) ).toFixed(0); } +function translateY(n) { return (translate(n + 0.75, scale_y) ).toFixed(0); } + function translate(n, scale) { return (n * tile_size) * scale; diff --git a/code/modules/html_interface/bootstrap.min.css b/code/modules/html_interface/css/bootstrap.min.css similarity index 100% rename from code/modules/html_interface/bootstrap.min.css rename to code/modules/html_interface/css/bootstrap.min.css diff --git a/code/modules/html_interface/html_interface.css b/code/modules/html_interface/css/html_interface.css similarity index 100% rename from code/modules/html_interface/html_interface.css rename to code/modules/html_interface/css/html_interface.css diff --git a/code/modules/html_interface/html_interface.dm b/code/modules/html_interface/html_interface.dm index 2e3359e80c4..ffc04407f66 100644 --- a/code/modules/html_interface/html_interface.dm +++ b/code/modules/html_interface/html_interface.dm @@ -127,11 +127,11 @@ mob/verb/test() /datum/html_interface/proc/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE) /datum/html_interface/proc/sendResources(client/client) - client << browse_rsc('jquery.min.js') - client << browse_rsc('bootstrap.min.js') - client << browse_rsc('bootstrap.min.css') - client << browse_rsc('html_interface.css') - client << browse_rsc('html_interface.js') + client << browse_rsc('js/jquery.min.js', "jquery.min.js") + client << browse_rsc('js/bootstrap.min.js', "bootstrap.min.js") + client << browse_rsc('css/bootstrap.min.css', "bootstrap.min.css") + client << browse_rsc('css/html_interface.css', "html_interface.css") + client << browse_rsc('js/html_interface.js', "html_interface.js") /datum/html_interface/proc/createWindow(datum/html_interface_client/hclient) winclone(hclient.client, "window", "browser_\ref[src]") @@ -212,14 +212,15 @@ mob/verb/test() // causing file not found errors. // src.sendResources(hclient.client) - if (winexists(hclient.client, "browser_\ref[src]")) - src._renderTitle(hclient, TRUE) - src._renderLayout(hclient) - else + if (!winexists(hclient.client, "browser_\ref[src]")) src.createWindow(hclient) - hclient.is_loaded = FALSE - hclient.client << output(replacetextEx(replacetextEx(file2text('html_interface.html'), "\[hsrc\]", "\ref[src]"), "", "[head]"), "browser_\ref[src].browser") - winshow(hclient.client, "browser_\ref[src]", TRUE) + //src._renderTitle(hclient, TRUE) + //src._renderLayout(hclient) + + hclient.is_loaded = FALSE + hclient.client << output(replacetextEx(replacetextEx(file2text('html_interface.html'), "\[hsrc\]", "\ref[src]"), "", "[head]"), "browser_\ref[src].browser") + + winshow(hclient.client, "browser_\ref[src]", TRUE) while (hclient.client && hclient.active && !hclient.is_loaded) sleep(2) diff --git a/code/modules/html_interface/html_interface.html b/code/modules/html_interface/html_interface.html index 1231c21df53..4bf76c6180a 100644 --- a/code/modules/html_interface/html_interface.html +++ b/code/modules/html_interface/html_interface.html @@ -8,6 +8,7 @@ + diff --git a/code/modules/html_interface/bootstrap.min.js b/code/modules/html_interface/js/bootstrap.min.js similarity index 100% rename from code/modules/html_interface/bootstrap.min.js rename to code/modules/html_interface/js/bootstrap.min.js diff --git a/code/modules/html_interface/html_interface.js b/code/modules/html_interface/js/html_interface.js similarity index 100% rename from code/modules/html_interface/html_interface.js rename to code/modules/html_interface/js/html_interface.js diff --git a/code/modules/html_interface/jquery.min.js b/code/modules/html_interface/js/jquery.min.js similarity index 100% rename from code/modules/html_interface/jquery.min.js rename to code/modules/html_interface/js/jquery.min.js diff --git a/code/modules/html_interface/nanotrasen/nanotrasen.dm b/code/modules/html_interface/nanotrasen/nanotrasen.dm index 1196b221785..3c1cfa47ef6 100644 --- a/code/modules/html_interface/nanotrasen/nanotrasen.dm +++ b/code/modules/html_interface/nanotrasen/nanotrasen.dm @@ -21,7 +21,7 @@ The client is optional and may be a /mob, /client or /html_interface_client obje src.head = src.head + "" src.updateLayout("") -/datum/html_interface/updateLayout(layout) +/datum/html_interface/nanotrasen/updateLayout(layout) // Wrap the layout in our custom HTML return ..("
[layout]
") diff --git a/html/changelogs/nullquery-hi-extended.yml b/html/changelogs/nullquery-hi-extended.yml new file mode 100644 index 00000000000..592b15ae7fd --- /dev/null +++ b/html/changelogs/nullquery-hi-extended.yml @@ -0,0 +1,10 @@ +author: NullQuery + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +changes: + - tweak: "Crew monitoring: The minimap now supports scaling. You can zoom in and out using the buttons. Hovering over an entry in the table centers the minimap on that part of the screen." + - tweak: "Crew monitoring: If the window is wide enough the health indicator will expand to show full health data (if available)." + - tweak: "Crew monitoring: Clicking on the area name will now copy the coordinates to your clipboard." + - tweak: "Crew monitoring: The AI can view health information again, but there is a 5 second delay between updates for everyone watching."