Merge pull request #10574 from nullstation/hi-extended

Changes to the crew monitoring computer
This commit is contained in:
Jordie
2015-07-23 22:17:50 +10:00
13 changed files with 312 additions and 83 deletions
+35 -20
View File
@@ -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
/datum/procqueue_item/var/list/args
+33 -4
View File
@@ -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;
}
+9 -16
View File
@@ -97,12 +97,16 @@ var/global/datum/crewmonitor/crewmonitor = new
hi = src.interfaces["[z]"]
hi.updateContent("content", "<a href=\"javascript:switchTo(0);\">Switch to mini map</a> <a href=\"javascript:switchTo(1);\">Switch to text-based</a><div id=\"minimap\"></div><div id=\"textbased\"></div>")
hi.updateContent("content", "<div id=\"minimap\"><a href=\"javascript:zoomIn();\" class=\"zoom in\">+</a><a href=\"javascript:zoomOut();\" class=\"zoom\">-</a></div><div id=\"textbased\"></div>")
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
+210 -30
View File
@@ -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("<table><colgroup><col /><col style=\"width: 24px;\" /><col style=\"width: 180px;\" /></colgroup><thead><tr><td><h3>Name</h3></td><td><h3>&nbsp;</h3></td><td><h3>Position</h3></td></tr></thead><tbody id=\"textbased-tbody\"></tbody></table>");
$("#textbased").html("<table><colgroup><col /><col style=\"width: 24px;\" class=\"colhealth\" /><col style=\"width: 180px;\" /></colgroup><thead><tr><td><h3>Name</h3></td><td><h3>&nbsp;</h3></td><td><h3>Position</h3></td></tr></thead><tbody id=\"textbased-tbody\"></tbody></table>");
$("#minimap").append("<img src=\"minimap_" + z + ".png\" id=\"map\" style=\"width: auto; height: 480px;\" />");
$("#minimap").append("<img src=\"minimap_" + z + ".png\" id=\"map\" style=\"width: auto; height: " + minimap_height + "px;\" />");
$("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 = "<div class=\"health health-" + i + " tt\"><div><span>(<font color=\"#3498db\">" + dam1 + "</font>/<font color=\"#2ecc71\">" + dam2 + "</font>/<font color=\"#e67e22\">" + dam3 + "</font>/<font color=\"#e74c3c\">" + dam4 + "</font>)</span></div></div>";
healthHTML = "<div class=\"health health-" + i + (expandHealth() ? "" : " tt") + "\"><div><span>(<font color=\"#3498db\">" + dam1 + "</font>/<font color=\"#2ecc71\">" + dam2 + "</font>/<font color=\"#e67e22\">" + dam3 + "</font>/<font color=\"#e74c3c\">" + dam4 + "</font>)</span></div></div>";
}
else
{
healthHTML = "<div class=\"health health-" + (life_status == "" ? -1 : (life_status == "true" ? 4 : 0)) + " tt\"><div><span>Not Available</span></div></div>";
healthHTML = "<div class=\"health health-" + (life_status == "" ? -1 : (life_status == "true" ? 4 : 0)) + (expandHealth() ? "" : " tt") + "\"><div><span>Not Available</span></div></div>";
}
var trElem = $("<tr></tr>").attr("data-ijob", ijob);
@@ -341,14 +487,21 @@ function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area,
trElem.append(tdElem);
tdElem = $("<td style=\"text-align: center; vertical-align: top; cursor: default;\"></td>");
tdElem = $("<td style=\"vertical-align: top; cursor: default;\"></td>");
tdElem.html(healthHTML);
trElem.append(tdElem);
tdElem = $("<td style=\"cursor: default;\"></td>");
if (area && pos_x && pos_y) { tdElem.append($("<div></div>").text(area).addClass("tt").append($("<div></div>").append($("<span></span>").text("(" + pos_x + ", " + pos_y + ")")))); }
if (area && pos_x && pos_y)
{
tdElem.append($("<div></div>").text(area).addClass("tt").append($("<div></div>").append($("<span></span>").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 = $("<div class=\"dot\" style=\"top: " + ty + "px; left: " + tx + "px; background-color: " + color + "; z-index: " + ijob + ";\"></div>");
var dotElem = $("<div class=\"dot\" style=\"top: " + ty + "px; left: " + tx + "px; background-color: " + color + "; z-index: " + ijob + ";\" data-x=\"" + x + "\" data-y=\"" + y + "\"></div>");
$("#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;
+13 -12
View File
@@ -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>", "[head]</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>", "[head]</head>"), "browser_\ref[src].browser")
winshow(hclient.client, "browser_\ref[src]", TRUE)
while (hclient.client && hclient.active && !hclient.is_loaded) sleep(2)
@@ -8,6 +8,7 @@
<link rel="stylesheet" type="text/css" href="html_interface.css" />
<script type="text/javascript">var hSrc = "[hsrc]";</script>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.mousewheel.min.js"></script>
<script type="text/javascript" src="bootstrap.min.js"></script>
<script type="text/javascript" src="html_interface.js"></script>
</head>
@@ -21,7 +21,7 @@ The client is optional and may be a /mob, /client or /html_interface_client obje
src.head = src.head + "<link rel=\"stylesheet\" type=\"text/css\" href=\"nanotrasen.css\" />"
src.updateLayout("")
/datum/html_interface/updateLayout(layout)
/datum/html_interface/nanotrasen/updateLayout(layout)
// Wrap the layout in our custom HTML
return ..("<div id=\"ntbgcenter\"></div><div id=\"content\">[layout]</div>")
+10
View File
@@ -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."