html_interface removal and crew monitoring console refactor.

This commit is contained in:
AnturK
2018-02-15 21:31:21 +01:00
committed by CitadelStationBot
parent 1cda9ef2b4
commit 35b8e410be
41 changed files with 268 additions and 2416 deletions

View File

@@ -196,7 +196,7 @@
"aL" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/table,
/obj/item/deck,
/obj/item/toy/cards/deck,
/obj/item/folder/blue,
/obj/item/pen,
/turf/open/floor/plasteel/floorgrime,

View File

@@ -54,7 +54,7 @@
if(..())
return
var/mob/living/silicon/ai/AI = usr
GLOB.crewmonitor.show(AI)
GLOB.crewmonitor.show(AI,AI)
/obj/screen/ai/crew_manifest
name = "Crew Manifest"

View File

@@ -57,8 +57,6 @@ GLOBAL_LIST_EMPTY(cinematics)
//Close all open windows if global
if(is_global)
for (var/datum/html_interface/hi in GLOB.html_interfaces)
hi.closeAll()
SStgui.close_all_uis()

View File

@@ -143,10 +143,6 @@
var/datum/atom_hud/data/human/medical/basic/B = GLOB.huds[DATA_HUD_MEDICAL_BASIC]
B.update_suit_sensors(src)
var/turf/T = get_turf(src)
if (T)
GLOB.crewmonitor.queueUpdate(T.z)
//called when a living mob changes health
/mob/living/proc/med_hud_set_health()
var/image/holder = hud_list[HEALTH_HUD]
@@ -158,10 +154,6 @@
/mob/living/carbon/med_hud_set_health()
..()
var/turf/T = get_turf(src)
if(T)
GLOB.crewmonitor.queueUpdate(T.z)
//called when a carbon changes stat, virus or XENO_HOST
/mob/living/proc/med_hud_set_status()
var/image/holder = hud_list[STATUS_HUD]
@@ -216,10 +208,6 @@
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
sec_hud_set_security_status()
var/turf/T = get_turf(src)
if (T)
GLOB.crewmonitor.queueUpdate(T.z)
/mob/living/carbon/human/proc/sec_hud_set_implants()
var/image/holder
for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD))

View File

@@ -456,21 +456,6 @@ Class Procs:
/obj/machinery/proc/on_deconstruction()
return
// Hook for html_interface module to prevent updates to clients who don't have this as their active machine.
/obj/machinery/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
if (hclient.client.mob && (hclient.client.mob.stat == 0 || IsAdminGhost(hclient.client.mob)))
if (isAI(hclient.client.mob) || IsAdminGhost(hclient.client.mob))
return TRUE
else
return hclient.client.mob.machine == src && Adjacent(hclient.client.mob)
else
return FALSE
// Hook for html_interface module to unset the active machine when the window is closed by the player.
/obj/machinery/proc/hiOnHide(datum/html_interface_client/hclient)
if (hclient.client.mob && hclient.client.mob.machine == src)
hclient.client.mob.unset_machine()
/obj/machinery/proc/can_be_overridden()
. = 1

View File

@@ -20,13 +20,14 @@
switchCamera(cameras[camera])
/datum/trackable
var/initialized = FALSE
var/list/names = list()
var/list/namecounts = list()
var/list/humans = list()
var/list/others = list()
/mob/living/silicon/ai/proc/trackable_mobs()
track.initialized = TRUE
track.names.Cut()
track.namecounts.Cut()
track.humans.Cut()
@@ -63,6 +64,9 @@
if(!target_name)
return
if(!track.initialized)
trackable_mobs()
var/mob/target = (isnull(track.humans[target_name]) ? track.others[target_name] : track.humans[target_name])
ai_actual_track(target)

View File

@@ -1,154 +0,0 @@
body
{
padding-left: 53%;
cursor: default;
}
#ntbgcenter
{
background-position: 550px 0px !important;
}
#minimap
{
position: fixed;
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
{
min-width: 380px;
width: 100%;
table-layout: fixed;
}
#textbased td
{
vertical-align: top;
padding: 2px;
}
#textbased tbody td
{
transition: .2s all;
}
#textbased tbody tr:hover td, #textbased tbody tr.hover td
{
background-color: #515151;
}
#textarea:after
{
content: "";
clear: both;
}
.health
{
width: 16px;
height: 16px;
background-color: #FFF;
border: 1px solid #434343;
position: relative;
top: 2px;
}
.health-5 { background-color: #17d568; }
.health-4 { background-color: #2ecc71; }
.health-3 { background-color: #e67e22; }
.health-2 { background-color: #ed5100; }
.health-1 { background-color: #e74c3c; }
.health-0 { background-color: #ed2814; }
.health > div
{
margin-left: 20px;
margin-top: -4px;
}
.tt
{
position: relative;
display: inline-block;
height: 16px;
}
.tt > div
{
display: none;
}
.tt:hover > div
{
position: absolute;
bottom: -30px;
left: 50%;
margin-left: -64px;
display: block;
width: 128px;
height: 24px;
border: 1px solid #313131;
background-color: #434343;
padding: 4px;
z-index: 999;
text-align: center;
}
.tt > div > span
{
position: relative;
top: -2px;
}
.dot
{
position: absolute;
width: 3px;
height: 3px;
margin-top: 0px;
margin-left: 0px;
border: 1px solid transparent;
}
.dot.active
{
z-index: 9999 !important;
width: 8px;
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;
}

View File

@@ -1,3 +1,5 @@
#define SENSORS_UPDATE_PERIOD 100 //How often the sensor data updates.
/obj/machinery/computer/crew
name = "crew monitoring console"
desc = "Used to monitor active health sensors built into most of the crew's uniforms."
@@ -16,21 +18,22 @@
/obj/machinery/computer/crew/attack_ai(mob/user)
if(stat & (BROKEN|NOPOWER))
return
GLOB.crewmonitor.show(user)
GLOB.crewmonitor.show(user,src)
/obj/machinery/computer/crew/attack_hand(mob/user)
if(..())
return
if(stat & (BROKEN|NOPOWER))
return
GLOB.crewmonitor.show(user)
GLOB.crewmonitor.show(user,src)
GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
/datum/crewmonitor
var/list/ui_sources = list() //List of user -> ui source
var/list/jobs
var/list/interfaces
var/list/data
var/list/data_by_z = list()
var/list/last_update = list()
/datum/crewmonitor/New()
. = ..()
@@ -77,196 +80,119 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
jobs["Assistant"] = 999 //Unknowns/custom jobs should appear after civilians, and before assistants
src.jobs = jobs
src.interfaces = list()
src.data = list()
register_asset("crewmonitor.js",'crew.js')
register_asset("crewmonitor.css",'crew.css')
/datum/crewmonitor/Destroy()
if (src.interfaces)
for (var/datum/html_interface/hi in interfaces)
qdel(hi)
src.interfaces = null
return ..()
/datum/crewmonitor/proc/show(mob/mob, z)
if (mob.client)
sendResources(mob.client)
if (!z)
z = mob.z
/datum/crewmonitor/ui_interact(mob/user, ui_key = "crew", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "crew", "crew monitor", 800, 600 , master_ui, state)
ui.open()
if (z > 0 && src.interfaces)
var/datum/html_interface/hi
/datum/crewmonitor/proc/show(mob/M, source)
ui_sources[M] = source
ui_interact(M)
if (!src.interfaces["[z]"])
src.interfaces["[z]"] = new/datum/html_interface/nanotrasen(src, "Crew Monitoring", 900, 540, "<link rel=\"stylesheet\" type=\"text/css\" href=\"crewmonitor.css\" /><script type=\"text/javascript\">var z = [z]; var tile_size = [world.icon_size]; var maxx = [world.maxx]; var maxy = [world.maxy];</script><script type=\"text/javascript\" src=\"crewmonitor.js\"></script>")
/datum/crewmonitor/ui_host(mob/user)
return ui_sources[user]
hi = src.interfaces["[z]"]
/datum/crewmonitor/ui_data(mob/user)
var/z = user.z
if(!z)
var/turf/T = get_turf(user)
z = T.z
var/list/zdata = update_data(z)
. = list()
.["sensors"] = zdata
.["link_allowed"] = isAI(user)
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>")
/datum/crewmonitor/proc/update_data(z)
if(data_by_z["[z]"] && last_update["[z]"] && world.time <= last_update["[z]"] + SENSORS_UPDATE_PERIOD)
return data_by_z["[z]"]
src.update(z, TRUE)
else
hi = src.interfaces["[z]"]
src.update(z,TRUE)
var/list/results = list()
var/obj/item/clothing/under/U
var/obj/item/card/id/I
var/turf/pos
var/ijob
var/name
var/assignment
var/oxydam
var/toxdam
var/burndam
var/brutedam
var/area
var/pos_x
var/pos_y
var/life_status
// 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")
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
// Check if their z-level is correct and if they are wearing a uniform.
// Accept H.z==0 as well in case the mob is inside an object.
if ((H.z == 0 || H.z == z) && istype(H.w_uniform, /obj/item/clothing/under))
U = H.w_uniform
hi = src.interfaces["[z]"]
hi.show(mob)
src.updateFor(mob, hi, z)
// Are the suit sensors on?
if ((U.has_sensor > 0) && U.sensor_mode)
pos = H.z == 0 || U.sensor_mode == SENSOR_COORDS ? get_turf(H) : null
/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.
hi.callJavaScript("clearAll", null, hclient_or_mob)
// Special case: If the mob is inside an object confirm the z-level on turf level.
if (H.z == 0 && (!pos || pos.z != z))
continue
for (var/list/L in data)
hi.callJavaScript("add", L, hclient_or_mob)
I = H.wear_id ? H.wear_id.GetID() : null
hi.callJavaScript("onAfterUpdate", null, hclient_or_mob)
if (I)
name = I.registered_name
assignment = I.assignment
ijob = jobs[I.assignment]
else
name = "Unknown"
assignment = ""
ijob = 80
/datum/crewmonitor/proc/update(z, ignore_unused = FALSE)
if (src.interfaces["[z]"])
var/datum/html_interface/hi = src.interfaces["[z]"]
if (U.sensor_mode >= SENSOR_LIVING)
life_status = (!H.stat ? TRUE : FALSE)
else
life_status = null
if (ignore_unused || hi.isUsed())
var/list/results = list()
var/obj/item/clothing/under/U
var/obj/item/card/id/I
var/turf/pos
var/ijob
var/name
var/assignment
var/dam1
var/dam2
var/dam3
var/dam4
var/area
var/pos_x
var/pos_y
var/life_status
if (U.sensor_mode >= SENSOR_VITALS)
oxydam = round(H.getOxyLoss(),1)
toxdam = round(H.getToxLoss(),1)
burndam = round(H.getFireLoss(),1)
brutedam = round(H.getBruteLoss(),1)
else
oxydam = null
toxdam = null
burndam = null
brutedam = null
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
// Check if their z-level is correct and if they are wearing a uniform.
// Accept H.z==0 as well in case the mob is inside an object.
if ((H.z == 0 || H.z == z) && istype(H.w_uniform, /obj/item/clothing/under))
U = H.w_uniform
if (U.sensor_mode >= SENSOR_COORDS)
if (!pos)
pos = get_turf(H)
area = get_area_name(H, TRUE)
pos_x = pos.x
pos_y = pos.y
else
area = null
pos_x = null
pos_y = null
// Are the suit sensors on?
if ((U.has_sensor > 0) && U.sensor_mode)
pos = H.z == 0 || U.sensor_mode == SENSOR_COORDS ? get_turf(H) : null
results[++results.len] = list("name" = name, "assignment" = assignment, "ijob" = ijob, "life_status" = life_status, "oxydam" = oxydam, "toxdam" = toxdam, "burndam" = burndam, "brutedam" = brutedam, "area" = area, "pos_x" = pos_x, "pos_y" = pos_y, "can_track" = H.can_track(null))
data_by_z["[z]"] = results
last_update["[z]"] = world.time
return results
// Special case: If the mob is inside an object confirm the z-level on turf level.
if (H.z == 0 && (!pos || pos.z != z))
continue
/datum/crewmonitor/ui_act(action,params)
var/mob/living/silicon/ai/AI = usr
if(!istype(AI))
return
switch (action)
if ("select_person")
AI.ai_camera_track(params["name"])
I = H.wear_id ? H.wear_id.GetID() : null
if (I)
name = I.registered_name
assignment = I.assignment
ijob = jobs[I.assignment]
else
name = "<i>Unknown</i>"
assignment = ""
ijob = 80
if (U.sensor_mode >= SENSOR_LIVING)
life_status = (!H.stat ? "true" : "false")
else
life_status = null
if (U.sensor_mode >= SENSOR_VITALS)
dam1 = round(H.getOxyLoss(),1)
dam2 = round(H.getToxLoss(),1)
dam3 = round(H.getFireLoss(),1)
dam4 = round(H.getBruteLoss(),1)
else
dam1 = null
dam2 = null
dam3 = null
dam4 = null
if (U.sensor_mode >= SENSOR_COORDS)
if (!pos)
pos = get_turf(H)
area = get_area_name(H, TRUE)
pos_x = pos.x
pos_y = pos.y
else
area = null
pos_x = null
pos_y = null
results[++results.len] = list(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, pos_x, pos_y, H.can_track(null))
src.data = results
src.updateFor(null, hi, z) // updates for everyone
/datum/crewmonitor/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
var/z = ""
for (z in src.interfaces)
if (src.interfaces[z] == hi)
break
if(hclient.client.mob && IsAdminGhost(hclient.client.mob))
return TRUE
if (hclient.client.mob && hclient.client.mob.stat == 0 && hclient.client.mob.z == text2num(z))
if (isAI(hclient.client.mob))
return TRUE
else if (iscyborg(hclient.client.mob))
return (locate(/obj/machinery/computer/crew, range(world.view, hclient.client.mob))) || (locate(/obj/item/device/sensor_device, hclient.client.mob.contents))
else
return (locate(/obj/machinery/computer/crew, range(1, hclient.client.mob))) || (locate(/obj/item/device/sensor_device, hclient.client.mob.contents))
else
return FALSE
/datum/crewmonitor/Topic(href, href_list[], datum/html_interface_client/hclient)
if (istype(hclient))
if (hclient && hclient.client && hclient.client.mob && isAI(hclient.client.mob))
var/mob/living/silicon/ai/AI = hclient.client.mob
switch (href_list["action"])
if ("select_person")
AI.ai_camera_track(href_list["name"])
if ("select_position")
var/x = text2num(href_list["x"])
var/y = text2num(href_list["y"])
var/turf/tile = locate(x, y, AI.z)
var/obj/machinery/camera/C = locate(/obj/machinery/camera) in range(5, tile)
if (!C)
C = locate(/obj/machinery/camera) in urange(10, tile)
if (!C)
C = locate(/obj/machinery/camera) in urange(15, tile)
if (C)
addtimer(CALLBACK(src, .proc/update_ai, AI, C, AI.eyeobj.loc), min(30, get_dist(get_turf(C), AI.eyeobj) / 4))
/datum/crewmonitor/proc/update_ai(mob/living/silicon/ai/AI, obj/machinery/camera/C, turf/current_loc)
if (AI && AI.eyeobj && current_loc == AI.eyeobj.loc)
AI.switchCamera(C)
/mob/living/carbon/human/Move()
var/old_z = src.z
. = ..()
if (src.w_uniform)
if (old_z != src.z)
GLOB.crewmonitor.queueUpdate(old_z)
GLOB.crewmonitor.queueUpdate(src.z)
/datum/crewmonitor/proc/queueUpdate(z)
addtimer(CALLBACK(src, .proc/update, z), 5, TIMER_UNIQUE)
/datum/crewmonitor/proc/sendResources(var/client/client)
send_asset(client, "crewmonitor.js")
send_asset(client, "crewmonitor.css")
SSminimap.send(client)
#undef SENSORS_UPDATE_PERIOD

View File

@@ -1,588 +0,0 @@
/*!
* jQuery scrollintoview() plugin and :scrollable selector filter
*
* Version 1.8 (14 Jul 2011)
* Requires jQuery 1.4 or newer
*/
(function ($) {
var converter = {
vertical: { x: false, y: true },
horizontal: { x: true, y: false },
both: { x: true, y: true },
x: { x: true, y: false },
y: { x: false, y: true }
};
var settings = {
duration: "fast",
direction: "both"
};
var rootrx = /^(?:html)$/i;
// gets border dimensions
var borders = function (domElement, styles) {
styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
var px = document.defaultView && document.defaultView.getComputedStyle ? true : false;
var b = {
top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0),
left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0),
bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0),
right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0)
};
return {
top: b.top,
left: b.left,
bottom: b.bottom,
right: b.right,
vertical: b.top + b.bottom,
horizontal: b.left + b.right
};
};
var dimensions = function ($element) {
var win = $(window);
var isRoot = rootrx.test($element[0].nodeName);
return {
border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]),
scroll: {
top: (isRoot ? win : $element).scrollTop(),
left: (isRoot ? win : $element).scrollLeft()
},
scrollbar: {
right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth,
bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight
},
rect: (function () {
var r = $element[0].getBoundingClientRect();
return {
top: isRoot ? 0 : r.top,
left: isRoot ? 0 : r.left,
bottom: isRoot ? $element[0].clientHeight : r.bottom,
right: isRoot ? $element[0].clientWidth : r.right
};
})()
};
};
$.fn.extend({
scrollintoview: function (options) {
/// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
/// <param name="options" type="Object">Additional options that can configure scrolling:
/// duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
/// direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
/// complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
/// </param>
/// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>
options = $.extend({}, settings, options);
options.direction = converter[typeof (options.direction) === "string" && options.direction.toLowerCase()] || converter.both;
var dirStr = "";
if (options.direction.x === true) dirStr = "horizontal";
if (options.direction.y === true) dirStr = dirStr ? "both" : "vertical";
var el = this.eq(0);
var scroller = el.closest(":scrollable(" + dirStr + ")");
// check if there's anything to scroll in the first place
if (scroller.length > 0)
{
scroller = scroller.eq(0);
var dim = {
e: dimensions(el),
s: dimensions(scroller)
};
var rel = {
top: dim.e.rect.top - (dim.s.rect.top + dim.s.border.top),
bottom: dim.s.rect.bottom - dim.s.border.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom,
left: dim.e.rect.left - (dim.s.rect.left + dim.s.border.left),
right: dim.s.rect.right - dim.s.border.right - dim.s.scrollbar.right - dim.e.rect.right
};
var animOptions = {};
// vertical scroll
if (options.direction.y === true)
{
if (rel.top < 0)
{
animOptions.scrollTop = dim.s.scroll.top + rel.top;
}
else if (rel.top > 0 && rel.bottom < 0)
{
animOptions.scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom);
}
}
// horizontal scroll
if (options.direction.x === true)
{
if (rel.left < 0)
{
animOptions.scrollLeft = dim.s.scroll.left + rel.left;
}
else if (rel.left > 0 && rel.right < 0)
{
animOptions.scrollLeft = dim.s.scroll.left + Math.min(rel.left, -rel.right);
}
}
// scroll if needed
if (!$.isEmptyObject(animOptions))
{
if (rootrx.test(scroller[0].nodeName))
{
scroller = $("html,body");
}
scroller
.animate(animOptions, options.duration)
.eq(0) // we want function to be called just once (ref. "html,body")
.queue(function (next) {
$.isFunction(options.complete) && options.complete.call(scroller[0]);
next();
});
}
else
{
// when there's nothing to scroll, just call the "complete" function
$.isFunction(options.complete) && options.complete.call(scroller[0]);
}
}
// return set back
return this;
}
});
var scrollValue = {
auto: true,
scroll: true,
visible: false,
hidden: false
};
$.extend($.expr[":"], {
scrollable: function (element, index, meta, stack) {
var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;
var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);
var overflow = {
x: scrollValue[styles.overflowX.toLowerCase()] || false,
y: scrollValue[styles.overflowY.toLowerCase()] || false,
isRoot: rootrx.test(element.nodeName)
};
// check if completely unscrollable (exclude HTML element because it's special)
if (!overflow.x && !overflow.y && !overflow.isRoot)
{
return false;
}
var size = {
height: {
scroll: element.scrollHeight,
client: element.clientHeight
},
width: {
scroll: element.scrollWidth,
client: element.clientWidth
},
// check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
scrollableX: function () {
return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;
},
scrollableY: function () {
return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;
}
};
return direction.y && size.scrollableY() || direction.x && size.scrollableX();
}
});
})(jQuery);
/*!
* Crew manifest script
*/
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;\" 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: " + minimap_height + "px;\" />");
$("body")[0].onselectstart = disableSelection;
$("#minimap").on("click", function(e)
{
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;
}
}).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)
{
if (i == 1)
{
$("#minimap").hide();
$("#textbased").show();
}
else
{
$("#textbased").hide();
$("#minimap").show();
}
}
var orig_scrollTop = 0;
function clearAll()
{
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
}
function getColor(ijob)
{
if (ijob == 0) { return "#C06616"; } // captain
else if (ijob >= 10 && ijob < 20) { return "#E74C3C"; } // security
else if (ijob >= 20 && ijob < 30) { return "#3498DB"; } // medical
else if (ijob >= 30 && ijob < 40) { return "#9B59B6"; } // science
else if (ijob >= 40 && ijob < 50) { return "#F1C40F"; } // engineering
else if (ijob >= 50 && ijob < 60) { return "#F39C12"; } // cargo
else if (ijob >= 200 && ijob < 230) { return "#00C100"; } // CentCom
else { return "#C38312"; } // other / unknown
}
function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, pos_x, pos_y, in_range)
{
try { ijob = parseInt(ijob); }
catch (ex) { ijob = 0; }
var ls = "";
if (life_status === null) { ls = (life_status ? "<span class=\"bad\">Deceased</span>" : "<span class=\"good\">Living</span>"); }
var healthHTML = "";
if (dam1 != "" || dam2 != "" || dam3 != "" || dam4 != "")
{
var avg_dam = parseInt(dam1) + parseInt(dam2) + parseInt(dam3) + parseInt(dam4);
var i;
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 + (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)) + (expandHealth() ? "" : " tt") + "\"><div><span>Not Available</span></div></div>";
}
var trElem = $("<tr></tr>").attr("data-ijob", ijob);
var tdElem;
var spanElem;
tdElem = $("<td></td>");
var italics = false;
if (name.length >= 7 && name.substring(0, 3) == "<i>")
{
name = name.substring(3, name.length - 4);
italics = true;
}
spanElem = $("<span></span>").text(name);
if (italics)
{
spanElem.css("font-style", "italic");
}
if (isHead(ijob)) { spanElem.css("font-weight", "bold"); }
var color = getColor(ijob);
if (color) { spanElem.css("color", color); }
tdElem.append(spanElem);
if (assignment) { tdElem.append($("<span></span>").text(" (" + assignment + ")")); }
trElem.append(tdElem);
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 + ")"))));
tdElem.css("cursor", "pointer").on("click", function()
{
window.clipboardData.setData("Text", pos_x + ", " + pos_y);
});
}
else { tdElem.text("Not Available"); }
trElem.append(tdElem);
var item = $("#textbased-tbody > tr").filter(function(){ return parseInt($(this).attr("data-ijob")) >= ijob; }).eq(0);
if (item.length > 0) { trElem.insertBefore(item); }
else { $("#textbased-tbody").append(trElem); }
if (updateMap && pos_x && pos_y && (in_range == "1"))
{
var x = parseInt(pos_x);
var y = maxy - parseInt(pos_y);
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 + ";\" 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" });
}
function click(e)
{
e.preventDefault();
e.stopPropagation();
window.location.href = "byond://?src=" + hSrc + "&action=select_person&name=" + encodeURIComponent(name);
}
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");
enable();
trElem.scrollintoview();
}).on("mouseout", function()
{
trElem.removeClass("hover");
disable();
}).on("click", click);
}
}
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;
}

View File

@@ -7,4 +7,4 @@
slot_flags = SLOT_BELT
/obj/item/device/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user) //Proc already exists, just had to call it
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it

View File

@@ -338,7 +338,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/simple/goonchat
verify = FALSE
assets = list(
"jquery.min.js" = 'code/modules/html_interface/js/jquery.min.js',
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
"errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js',
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
@@ -350,12 +350,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
)
//Registers HTML Interface assets.
/datum/asset/HTML_interface/register()
for(var/path in typesof(/datum/html_interface))
var/datum/html_interface/hi = new path()
hi.registerResources()
//this exists purely to avoid meta by pre-loading all language icons.
/datum/asset/language/register()
for(var/path in typesof(/datum/language))

View File

@@ -49,9 +49,6 @@
var/obj/screen/click_catcher/void
// Used by html_interface module.
var/hi_last_pos
var/ip_intel = "Disabled"
//datum that controls the displaying and hiding of tooltips

View File

@@ -1,279 +0,0 @@
/datum/playingcard
var/name = "playing card"
var/card_icon = "card_back"
var/suit
var/number
/* Deck */
/obj/item/deck
name = "deck of cards"
desc = "A simple deck of playing cards."
icon = 'icons/obj/playing_cards.dmi'
icon_state = "deck"
w_class = WEIGHT_CLASS_SMALL
flags_1 = NOBLUDGEON_1
var/list/cards = list()
/obj/item/deck/Initialize()
. = ..()
var/cardcolor
var/datum/playingcard/card
for (var/suit in list("spades", "clubs", "diamonds", "hearts"))
if (suit == "spades" || suit == "clubs")
cardcolor = "black_"
else
cardcolor = "red_"
for (var/number in list("ace", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"))
card = new()
card.name = "[number] of [suit]"
card.card_icon = "[cardcolor]num"
card.suit = suit
card.number = number
src.cards.Add(card)
for (var/number in list("jack", "queen", "king"))
card = new()
card.name = "[number] of [suit]"
card.card_icon = "[cardcolor]col"
card.suit = suit
card.number = number
src.cards.Add(card)
for (var/i = 0, i < 2, i++)
card = new()
card.name = "joker"
card.card_icon = "joker"
card.suit = "joker"
card.number = ""
src.cards.Add(card)
/obj/item/deck/attackby(obj/O, mob/user)
if (istype(O, /obj/item/hand))
var/obj/item/hand/H = O
for (var/datum/playingcard/P in H.cards)
src.cards.Add(P)
qdel (O)
user.show_message("You place your cards on the bottom of the deck.")
else
return ..()
/obj/item/deck/attack_self(mob/user)
var/list/newcards = list()
var/datum/playingcard/card
while (cards.len)
card = pick(cards)
newcards.Add(card)
src.cards.Remove(card)
src.cards = newcards
user.visible_message("\The [user] shuffles [src].")
/obj/item/deck/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params)
if(flag)
return //It's adjacent, is the user, or is on the user's person
if(isliving(A))
src.dealTo(A, user)
else
return ..()
/obj/item/deck/attack(mob/living/M, mob/living/user, def_zone)
if (istype(M))
src.dealTo(M, user)
else
return ..()
/obj/item/deck/proc/dealTo(mob/living/target, mob/living/source)
if (!cards.len)
source.show_message("There are no cards in the deck.")
return
var/datum/playingcard/card = src.cards[1]
src.cards.Remove(card)
var/obj/item/hand/H = new(get_turf(src))
H.concealed = 1
H.update_conceal()
H.cards.Add(card)
H.update_icon()
source.visible_message("\The [source] deals a card to \the [target].")
H.throw_at(get_step(target, target.dir), 10, 1, source)
/* Hand */
/obj/item/hand
name = "hand of cards"
desc = "Some playing cards."
icon = 'icons/obj/playing_cards.dmi'
icon_state = "empty"
w_class = WEIGHT_CLASS_TINY
var/concealed = 0
var/blank = 0
var/list/cards = list()
var/datum/html_interface/hi
resistance_flags = FLAMMABLE
/obj/item/hand/New(loc)
. = ..()
src.hi = new/datum/html_interface/cards(src, "Your hand", 540, 302)
src.update_conceal()
/obj/item/hand/Destroy()
if (src.hi)
qdel(src.hi)
return ..()
/obj/item/hand/attackby(obj/O, mob/user)
if(cards.len == 1 && istype(O, /obj/item/pen))
var/datum/playingcard/P = cards[1]
if(!blank)
to_chat(user, "You cannot write on that card.")
return
var/cardtext = sanitize(input(user, "What do you wish to write on the card?", "Card Writing") as text|null, 50)
if(!cardtext)
return
P.name = cardtext
blank = 0
else if(istype(O, /obj/item/hand))
var/obj/item/hand/H = O
for(var/datum/playingcard/P in src.cards)
H.cards.Add(P)
H.update_icon()
qdel(src)
else
return ..()
/obj/item/hand/verb/discard(datum/playingcard/card in cards)
set category = "Object"
set name = "Discard"
set desc = "Place a card from your hand in front of you."
if (!card)
return
var/obj/item/hand/H = new(src.loc)
H.concealed = 0
H.update_conceal()
H.cards.Add(card)
src.cards.Remove(card)
H.update_icon()
ASSERT(H)
usr.visible_message("\The [usr] plays \the [card.name].")
H.forceMove(get_step(usr,usr.dir))
src.update_icon()
/obj/item/hand/verb/toggle_conceal()
set category = "Object"
set name = "Toggle conceal"
set desc = "Toggle concealment of your hand"
src.concealed = !src.concealed
src.update_conceal()
usr.visible_message("\The [usr] [concealed ? "conceals" : "reveals"] their hand.")
src.update_icon()
/obj/item/hand/attack_self(mob/user)
src.hi.show(user)
/obj/item/hand/examine()
. = ..()
if((!concealed || src.loc == usr) && cards.len)
usr.show_message("It contains: ", 1)
for (var/datum/playingcard/card in cards)
usr.show_message("The [card.name].", 1)
/obj/item/hand/proc/update_conceal()
if (src.concealed)
src.hi.updateContent("headbar", "You are currently concealing your hand. <a href=\"byond://?src=[REF(hi)]&action=toggle_conceal\">Reveal your hand.</a>")
else
src.hi.updateContent("headbar", "You are currently revealing your hand. <a href=\"byond://?src=[REF(hi)]&action=toggle_conceal\">Conceal your hand.</a>")
/obj/item/hand/update_icon()
if (!cards.len)
qdel (src)
else
if(cards.len > 1)
name = "hand of cards"
desc = "Some playing cards."
else
name = "a playing card"
desc = "A playing card."
cut_overlays()
if (cards.len == 1)
var/datum/playingcard/P = cards[1]
var/mutable_appearance/card_overlay = mutable_appearance(icon, (concealed ? "card_back" : "[P.card_icon]") )
card_overlay.pixel_x = card_overlay.pixel_x + (-5 + rand(10))
card_overlay.pixel_y = card_overlay.pixel_y + (-5 + rand(10))
add_overlay(card_overlay)
else
var/origin = -12
var/offset = round(32 / cards.len)
var/i = 0
var/mutable_appearance/card_overlay
for(var/datum/playingcard/P in cards)
card_overlay = mutable_appearance(icon, (concealed ? "card_back" : P.card_icon))
card_overlay.pixel_x = origin + (offset * i)
add_overlay(card_overlay)
i = i + 1
var/html = ""
for(var/datum/playingcard/card in cards)
html = html + "<a href=\"byond://?src=[REF(src.hi)]&action=play_card&card=[REF(card)]\" class=\"card [card.suit] [card.number]\"></a>"
src.hi.updateContent("hand", html)
/obj/item/hand/Topic(href, href_list[], datum/html_interface_client/hclient)
if (istype(hclient))
switch (href_list["action"])
if ("play_card")
var/datum/playingcard/card = locate(href_list["card"]) in cards
if (card && istype(card))
src.discard(card)
if ("toggle_conceal")
src.toggle_conceal()
// Hook for html_interface module to prevent updates to clients who don't have this in their inventory.
/obj/item/hand/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
return (hclient.client.mob && hclient.client.mob.stat == 0 && (src in hclient.client.mob.contents))

View File

@@ -3,7 +3,11 @@
// which is licensed under CC BY-NC-SA 2.0, the full text of which can be found at the following URL:
// https://creativecommons.org/licenses/by-nc-sa/2.0/legalcode
// Original code by Zuhayr, Polaris Station, ported with modifications
/datum/playingcard
var/name = "playing card"
var/card_icon = "card_back"
var/suit
var/number
/obj/item/toy/cards/deck/cas
name = "\improper CAS deck (white)"

View File

@@ -1,112 +0,0 @@
html, body, div.wrapper > table
{
width: 100%;
height: 100%;
}
body
{
background-color: #EAEAEA;
font-family: verdana,Geneva,sans-serif;
font-size: 12px;
color: #272727;
}
a
{
color: #5353B1;
}
div.wrapper
{
position: absolute; top: 24px; left: 0px; right: 0px; bottom: 0px;
}
div#headbar
{
background-color: #B2B2B2;
border-bottom: 1px solid #C2C2C2;
height: 24px;
padding: 4px 8px;
box-sizing: border-box;
}
div#hand
{
padding: 8px 8px;
padding-bottom: 4px;
background-color: #EAEAEA;
text-align: center;
}
a.card
{
display: inline-block;
margin: 0px 2px;
background-image: url(cards.png);
background-repeat: no-repeat;
width: 94px;
height: 129px;
box-sizing: border-box;
background-position: 0px 0px;
background-origin: border-box;
text-decoration: none;
font-size: 0px;
}
a.card.clubs.ten { background-position: -5px -5px; }
a.card.diamonds.ten { background-position: -109px -5px; }
a.card.hearts.ten { background-position: -213px -5px; }
a.card.spades.ten { background-position: -317px -5px; }
a.card.clubs.two { background-position: -421px -5px; }
a.card.diamonds.two { background-position: -525px -5px; }
a.card.hearts.two { background-position: -629px -5px; }
a.card.spades.two { background-position: -733px -5px; }
a.card.clubs.three { background-position: -5px -144px; }
a.card.diamonds.three { background-position: -109px -144px; }
a.card.hearts.three { background-position: -213px -144px; }
a.card.spades.three { background-position: -317px -144px; }
a.card.clubs.four { background-position: -421px -144px; }
a.card.diamonds.four { background-position: -525px -144px; }
a.card.hearts.four { background-position: -629px -144px; }
a.card.spades.four { background-position: -733px -144px; }
a.card.clubs.five { background-position: -5px -283px; }
a.card.diamonds.five { background-position: -109px -283px; }
a.card.hearts.five { background-position: -213px -283px; }
a.card.spades.five { background-position: -317px -283px; }
a.card.clubs.six { background-position: -421px -283px; }
a.card.diamonds.six { background-position: -525px -283px; }
a.card.hearts.six { background-position: -629px -283px; }
a.card.spades.six { background-position: -733px -283px; }
a.card.clubs.seven { background-position: -5px -422px; }
a.card.diamonds.seven { background-position: -109px -422px; }
a.card.hearts.seven { background-position: -213px -422px; }
a.card.spades.seven { background-position: -317px -422px; }
a.card.clubs.eight { background-position: -421px -422px; }
a.card.diamonds.eight { background-position: -525px -422px; }
a.card.hearts.eight { background-position: -629px -422px; }
a.card.spades.eight { background-position: -733px -422px; }
a.card.clubs.nine { background-position: -5px -561px; }
a.card.diamonds.nine { background-position: -109px -561px; }
a.card.hearts.nine { background-position: -213px -561px; }
a.card.spades.nine { background-position: -317px -561px; }
a.card.clubs.ace { background-position: -421px -561px; }
a.card.diamonds.ace { background-position: -525px -561px; }
a.card.hearts.ace { background-position: -629px -561px; }
a.card.spades.ace { background-position: -733px -561px; }
a.card.clubs.jack { background-position: -5px -700px; }
a.card.diamonds.jack { background-position: -109px -700px; }
a.card.hearts.jack { background-position: -213px -700px; }
a.card.spades.jack { background-position: -317px -700px; }
a.card.clubs.king { background-position: -421px -700px; }
a.card.diamonds.king { background-position: -525px -700px; }
a.card.hearts.king { background-position: -629px -700px; }
a.card.spades.king { background-position: -733px -700px; }
a.card.clubs.queen { background-position: -837px -5px; }
a.card.diamonds.queen { background-position: -837px -144px; }
a.card.hearts.queen { background-position: -837px -283px; }
a.card.spades.queen { background-position: -837px -422px; }
a.card.joker { background-position: -837px -561px; }

View File

@@ -1,13 +0,0 @@
// Used by playing cards; /obj/item/hand
// Subtype exists because of sendResources; these must be sent when the client connects.
/datum/html_interface/cards/New()
. = ..()
src.head = src.head + "<link rel=\"stylesheet\" type=\"text/css\" href=\"cards.css\" />"
src.updateLayout("<div id=\"headbar\"></div><div class=\"wrapper\"><table><tr><td style=\"vertical-align: middle;\"><div id=\"hand\"></div></td></tr></table></div>")
/datum/html_interface/cards/registerResources(var/list/resources = list())
resources["cards.css"] = 'cards.css'
resources["cards.png"] = 'cards.png'
..(resources)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +0,0 @@
html
{
-ms-overflow-style: scrollbar;
}
body
{
font-family: Arial;
overflow-y: scroll;
overflow-x: auto;
}

View File

@@ -1,391 +0,0 @@
/*
Author: NullQuery
Created on: 2014-09-24
** CAUTION - A WORD OF WARNING **
If there is no getter or setter available and you aren't extending my code with a sub-type, DO NOT ACCESS VARIABLES DIRECTLY!
Add a getter/setter instead, even if it does nothing but return or set the variable. Thank you for your patience with me. -NQ
** Public API **
var/datum/html_interface/hi = new/datum/html_interface(ref, title, width = 700, height = 480, head = "")
Creates a new HTML interface object with [ref] as the object and [title] as the initial title of the page. [width] and [height] is the initial width and height
of the window. The text in [head] is added just before the end </head> tag.
hi.setTitle(title)
Changes the title of the page.
hi.getTitle()
Returns the current title of the page.
hi.updateLayout(layout)
Updates the overall layout of the page (the HTML code between the body tags).
This should be used sparingly.
hi.updateContent(id, content, ignore_cache = FALSE)
Updates a portion of the page, i.e., the DOM element with the appropriate ID. The contents of the element are replaced with the provided HTML.
The content is cached on the server-side to minimize network traffic when the client "should have" the same HTML. The client may not have
the same HTML if scripts cause the content to change. In this case set the ignore_cache parameter.
hi.executeJavaScript(jscript, client = null)
Executes Javascript on the browser.
The client is optional and may be a /mob, /client or /html_interface_client object. If not specified the code is executed on all clients.
hi.show(client)
Shows the HTML interface to the provided client. This will create a window, apply the current layout and contents. It will then wait for events.
hi.hide(client)
Hides the HTML interface from the provided client. This will close the browser window.
hi.isUsed()
Returns TRUE if the interface is being used (has an active client) or FALSE if not.
hi.closeAll()
Closes the interface on all clients.
** Additional notes **
When working with byond:// links make sure to reference the HTML interface object and NOT the original object. Topic() will still be called on
your object, but it will pass through the HTML interface first allowing interception at a higher level.
If you want to use custom resources(images/css/js) with an existing interface:
You have to use modules/client/asset_cache to ensure they get sent BEFORE the interface opens
** Sample code **
/mob/var/datum/html_interface/hi
/mob/verb/test()
if (!hi)
hi = new/datum/html_interface(src, "[src.key]")
hi.updateLayout("<div id=\"content\"></div>")
hi.updateContent("content", "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>")
hi.show(src)
*/
GLOBAL_LIST_EMPTY(html_interfaces)
/datum/html_interface
// The atom we should report to.
var/atom/ref
// The current title of the browser window.
var/title
// A list of content elements that have been changed. This is necessary when showing the browser control to new clients.
var/list/content_elements = new/list()
// The HTML layout, typically what's in-between the <body></body> tag. May be overridden by extensions.
var/layout
// An associative list of clients currently viewing this screen. The key is the /client object, the value is the /datum/html_interface_client object.
var/list/clients
// This goes just before the closing HEAD tag. I haven't exposed any getters/setters for it because it's only being used by extensions.
var/head = ""
// The initial width of the browser control, used when the window is first shown to a client.
var/width
// The initial height of the browser control, used when the window is first shown to a client.
var/height
// A type associated list of assets the interface needs.
//Sent to the client when the interface opens on the client for the first time.
var/static/list/asset_list
/datum/html_interface/New(atom/ref, title, width = 700, height = 480, head = "")
GLOB.html_interfaces.Add(src)
. = ..()
src.ref = ref
src.title = title
src.width = width
src.height = height
src.head = head
/datum/html_interface/Destroy()
src.closeAll()
GLOB.html_interfaces.Remove(src)
return ..()
/* * Hooks */
/datum/html_interface/proc/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
//if you need to override this, either call ..() or add your resources to asset_list
/datum/html_interface/proc/registerResources(var/list/resources = list())
resources["jquery.min.js"] = 'js/jquery.min.js'
resources["bootstrap.min.js"] = 'js/bootstrap.min.js'
resources["bootstrap.min.css"] = 'css/bootstrap.min.css'
resources["html_interface.css"] = 'css/html_interface.css'
resources["html_interface.js"] = 'js/html_interface.js'
var/assetlist = list()
for (var/R in resources)
register_asset(R,resources[R])
assetlist += R
if (!asset_list)
asset_list = list()
asset_list[type] = assetlist
/datum/html_interface/proc/createWindow(datum/html_interface_client/hclient)
winclone(hclient.client, "window", "browser_[REF(src)]")
var/list/params = list(
"size" = "[width]x[height]",
"statusbar" = "false",
"on-close" = "byond://?src=[REF(src)]&html_interface_action=onclose"
)
if (hclient.client.hi_last_pos)
params["pos"] = "[hclient.client.hi_last_pos]"
winset(hclient.client, "browser_[REF(src)]", list2params(params))
winset(hclient.client, "browser_[REF(src)].browser", list2params(list("parent" = "browser_[REF(src)]", "type" = "browser", "pos" = "0,0", "size" = "[width]x[height]", "anchor1" = "0,0", "anchor2" = "100,100", "use-title" = "true", "auto-format" = "false")))
/* * Public API */
/datum/html_interface/proc/getTitle()
return src.title
/datum/html_interface/proc/setTitle(title, ignore_cache = FALSE)
src.title = title
var/datum/html_interface_client/hclient
for (var/client in src.clients)
hclient = src._getClient(src.clients[client])
if (hclient && hclient.active)
src._renderTitle(src.clients[client], ignore_cache)
/datum/html_interface/proc/executeJavaScript(jscript, datum/html_interface_client/hclient = null)
if (hclient)
hclient = getClient(hclient)
if (istype(hclient))
if (hclient.is_loaded)
hclient.client << output(list2params(list(jscript)), "browser_[REF(src)].browser:eval")
else
for (var/client in src.clients)
if(src.clients[client])
src.executeJavaScript(jscript, src.clients[client])
/datum/html_interface/proc/callJavaScript(func, list/arguments, datum/html_interface_client/hclient = null)
if (!arguments)
arguments = new/list()
if (hclient)
hclient = getClient(hclient)
if (istype(hclient))
if (hclient.is_loaded)
hclient.client << output(list2params(arguments), "browser_[REF(src)].browser:[func]")
else
for (var/client in src.clients)
if (src.clients[client])
src.callJavaScript(func, arguments, src.clients[client])
/datum/html_interface/proc/updateLayout(layout)
src.layout = layout
var/datum/html_interface_client/hclient
for (var/client in src.clients)
hclient = src._getClient(src.clients[client])
if (hclient && hclient.active)
src._renderLayout(hclient)
/datum/html_interface/proc/updateContent(id, content, ignore_cache = FALSE)
src.content_elements[id] = content
var/datum/html_interface_client/hclient
for (var/client in src.clients)
hclient = src._getClient(src.clients[client])
if (hclient && hclient.active)
spawn (-1) src._renderContent(id, hclient, ignore_cache)
/datum/html_interface/proc/show(datum/html_interface_client/hclient)
hclient = getClient(hclient, TRUE)
if (istype(hclient))
if ((type in asset_list) && islist(asset_list[type]))
send_asset_list(hclient.client, asset_list[type], TRUE)
if (!winexists(hclient.client, "browser_[REF(src)]"))
src.createWindow(hclient)
//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)
/datum/html_interface/proc/hide(datum/html_interface_client/hclient)
hclient = getClient(hclient)
if (istype(hclient))
if (src.clients)
src.clients.Remove(hclient.client)
if (!src.clients.len)
src.clients = null
hclient.client.hi_last_pos = winget(hclient.client, "browser_[REF(src)]" ,"pos")
winshow(hclient.client, "browser_[REF(src)]", FALSE)
winset(hclient.client, "browser_[REF(src)]", "parent=none")
if (hascall(src.ref, "hiOnHide"))
call(src.ref, "hiOnHide")(hclient)
// Convert a /mob to /client, and /client to /datum/html_interface_client
/datum/html_interface/proc/getClient(client, create_if_not_exist = FALSE)
if (istype(client, /datum/html_interface_client))
return src._getClient(client)
else if (ismob(client))
var/mob/mob = client
client = mob.client
if (istype(client, /client))
if (create_if_not_exist && (!src.clients || !(client in src.clients)))
if (!src.clients)
src.clients = new/list()
if (!(client in src.clients))
src.clients[client] = new/datum/html_interface_client(client)
if (src.clients && (client in src.clients))
return src._getClient(src.clients[client])
else
return null
else
return null
/datum/html_interface/proc/enableFor(datum/html_interface_client/hclient)
hclient.active = TRUE
src.show(hclient)
/datum/html_interface/proc/disableFor(datum/html_interface_client/hclient)
hclient.active = FALSE
/datum/html_interface/proc/isUsed()
if (src.clients && src.clients.len > 0)
var/datum/html_interface_client/hclient
for (var/key in clients)
hclient = _getClient(clients[key])
if (hclient)
if (hclient.active)
return TRUE
else
clients.Remove(key)
return FALSE
/datum/html_interface/proc/closeAll()
if (src.clients)
for (var/client in src.clients)
src.hide(src.clients[client])
/* * Danger Zone */
/datum/html_interface/proc/_getClient(datum/html_interface_client/hclient)
if (hclient)
if (hclient.client)
// res = if the client has been active in the past 10 minutes and the client is allowed to view the object (context-sensitive).
var/res = hclient.client.inactivity <= 6000 && (hascall(src.ref, "hiIsValidClient") ? call(src.ref, "hiIsValidClient")(hclient, src) : TRUE)
if (res)
if (!hclient.active) src.enableFor(hclient)
else
if (hclient.active) src.disableFor(hclient)
return hclient
else
return null
else
return null
/datum/html_interface/proc/_renderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE, ignore_loaded = FALSE)
if (hclient && (ignore_loaded || hclient.is_loaded))
// Only render if we have new content.
if (ignore_cache || src.title != hclient.title)
hclient.title = title
src.specificRenderTitle(hclient)
hclient.client << output(list2params(list(title)), "browser_[REF(src)].browser:setTitle")
/datum/html_interface/proc/_renderLayout(datum/html_interface_client/hclient, ignore_loaded = FALSE)
if (hclient && (ignore_loaded || hclient.is_loaded))
var/html = src.layout
// Only render if we have new content.
if (html != hclient.layout)
hclient.layout = html
hclient.client << output(list2params(list(html)), "browser_[REF(src)].browser:updateLayout")
for (var/id in src.content_elements)
src._renderContent(id, hclient, ignore_loaded = ignore_loaded)
/datum/html_interface/proc/_renderContent(id, datum/html_interface_client/hclient, ignore_cache = FALSE, ignore_loaded = FALSE)
if (hclient && (ignore_loaded || hclient.is_loaded))
var/html = src.content_elements[id]
// Only render if we have new content.
if (ignore_cache || !(id in hclient.content_elements) || html != hclient.content_elements[id])
hclient.content_elements[id] = html
hclient.client << output(list2params(list(id, html)), "browser_[REF(src)].browser:updateContent")
/datum/html_interface/Topic(href, href_list[])
var/datum/html_interface_client/hclient = getClient(usr.client)
if (istype(hclient))
if ("html_interface_action" in href_list)
switch (href_list["html_interface_action"])
if ("onload")
hclient.layout = null
hclient.content_elements.len = 0
src._renderTitle(hclient, TRUE, TRUE)
src._renderLayout(hclient, TRUE)
hclient.is_loaded = TRUE
if ("onclose")
src.hide(hclient)
else if (src.ref && hclient.active)
src.ref.Topic(href, href_list, hclient)

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8" />
<title></title>
<link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
<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>
<body>
</body>
</html>

View File

@@ -1,46 +0,0 @@
/datum/html_interface_client
// The /client object represented by this model.
var/client/client
// The layout currently visible to the client.
var/layout
// The content elements (mirrored from /datum/html_interface) currently visible to the client.
var/list/content_elements = new/list()
// The current title for this client
var/title
// TRUE if the browser control has loaded and will accept input, FALSE if not.
var/is_loaded = FALSE
// TRUE if this client should receive updates, FALSE if not.
var/active = TRUE
// A list of extra variables, for use by extensions.
var/list/extra_vars
/datum/html_interface_client/New(client/client)
. = ..()
src.client = client
/datum/html_interface_client/proc/putExtraVar(key, value)
if (!src.extra_vars)
src.extra_vars = new/list()
src.extra_vars[key] = value
/datum/html_interface_client/proc/removeExtraVar(key)
if (src.extra_vars)
. = src.extra_vars[key]
src.extra_vars.Remove(key)
if (!src.extra_vars.len)
src.extra_vars = null
return .
/datum/html_interface_client/proc/getExtraVar(key)
if (src.extra_vars)
return src.extra_vars[key]

File diff suppressed because one or more lines are too long

View File

@@ -1,45 +0,0 @@
var is_loading = false;
var load_count = 0;
function onload()
{
if (!is_loading)
{
var count = ++load_count;
is_loading = true;
$("body").html("");
window.location.href = "byond://?src=" + hSrc + "&html_interface_action=onload";
// The request may fail which would prevent the player from refreshing the screen again. Try to detect this retry.
setTimeout(function()
{
if (count == load_count && is_loading && $("body").html() == "")
{
is_loading = false;
onload();
}
}, 500);
}
}
$(document).ready(function()
{
$(document).on("keydown", function(e)
{
if (!e.ctrlKey && e.which == 116)
{
e.preventDefault();
onload();
}
});
onload();
});
function fixText(text) { return text.replace(/ÿ/g, ""); }
function setTitle(new_title) { $("title").html(fixText(new_title)); $(window).trigger("onUpdateTitle"); }
function updateLayout(new_html) { $("body").html(fixText(new_html)); $(window).trigger("onUpdateLayout"); setTimeout(function(){ is_loading = false; }, 200); }
function updateContent(id, new_html) { $("#" + id).html(fixText(new_html)); $(window).trigger("onUpdateContent"); }

View File

@@ -1,321 +0,0 @@
body
{
background-color: #272727;
background-image: url(uiBg.png);
background-repeat: repeat-x;
background-position: center top;
font-family: verdana,Geneva,sans-serif;
font-size: 12px;
color: #FFFFFF;
line-height: 170%; /* NullQuery: 170% of what? */
}
/* Fix for IE8 */
body
{
background-color: #1F1F1F\9 !important;
}
#ntbgcenter
{
position: absolute;
top: 0px;
left: 0px;
right: 0px;
height: 246px;
background-image: url(uiBgcenter.png);
background-position: center;
background-repeat: no-repeat;
z-index: -1;
}
#content
{
padding: 8px;
font-family: Verdana, Geneva, sans-serif;
}
hr
{
background-color: #40628a;
height: 1px;
}
a, a:link, a:visited, a:active, .linkOn, .linkOff
{
color: #ffffff;
text-decoration: none;
background: #40628a;
border: 1px solid #161616;
padding: 1px 4px 1px 4px;
margin: 0 2px 0 0;
cursor:default;
}
a.nobg, a.nobg:link, a.nobg:visited, a.nobg:active
{
color: #ffffff;
text-decoration: none;
background: transparent;
border: none;
padding: 0px;
margin: 0px;
cursor:default;
font-weight:bold;
}
a.nobg:hover
{
color:#40628a;
}
a:hover
{
color: #40628a;
background: #ffffff;
}
a.white, a.white:link, a.white:visited, a.white:active
{
color: #40628a;
text-decoration: none;
background: #ffffff;
border: 1px solid #161616;
padding: 1px 4px 1px 4px;
margin: 0 2px 0 0;
cursor:default;
}
a.white:hover
{
color: #ffffff;
background: #40628a;
}
.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover
{
color: #ffffff;
background: #2f943c;
border-color: #24722e;
}
.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover
{
color: #ffffff;
background: #999999;
border-color: #666666;
}
a.icon, .linkOn.icon, .linkOff.icon
{
position: relative;
padding: 1px 4px 2px 20px;
}
a.icon img, .linkOn.icon img
{
position: absolute;
top: 0;
left: 0;
width: 18px;
height: 18px;
}
ul
{
padding: 4px 0 0 10px;
margin: 0;
list-style-type: none;
}
li
{
padding: 0 0 2px 0;
}
img, a img
{
border-style:none;
}
h1, h2, h3, h4, h5, h6
{
margin: 0;
padding: 16px 0 8px 0;
color: #517087;
}
h1
{
font-size: 15px;
}
h2
{
font-size: 14px;
}
h3
{
font-size: 13px;
}
h4
{
font-size: 12px;
}
.good
{
color: #00ff00;
}
.average
{
color: #d09000;
}
.bad
{
color: #ff0000;
}
.highlight
{
color: #8BA5C4;
}
.dark
{
color: #272727;
}
.notice
{
position: relative;
background: #E9C183;
color: #15345A;
font-size: 10px;
font-style: italic;
padding: 2px 4px 0 4px;
margin: 4px;
}
.notice.icon
{
padding: 2px 4px 0 20px;
}
.notice img
{
position: absolute;
top: 0;
left: 0;
width: 16px;
height: 16px;
}
div.notice
{
clear: both;
}
.statusDisplay
{
background: #000000;
color: #ffffff;
border: 1px solid #40628a;
padding: 4px;
margin: 3px 0;
}
.statusLabel
{
width: 138px;
float: left;
overflow: hidden;
color: #98B0C3;
}
.statusValue
{
float: left;
}
.block
{
padding: 8px;
margin: 10px 4px 4px 4px;
border: 1px solid #40628a;
background-color: #202020;
}
.block h3
{
padding: 0;
}
.progressBar
{
width: 240px;
height: 14px;
border: 1px solid #666666;
float: left;
margin: 0 5px;
overflow: hidden;
}
.progressFill
{
width: 100%;
height: 100%;
background: #40628a;
overflow: hidden;
}
.progressFill.good
{
color: #ffffff;
background: #00ff00;
}
.progressFill.average
{
color: #ffffff;
background: #d09000;
}
.progressFill.bad
{
color: #ffffff;
background: #ff0000;
}
.progressFill.highlight
{
color: #ffffff;
background: #8BA5C4;
}
.clearBoth
{
clear: both;
}
.clearLeft
{
clear: left;
}
.clearRight
{
clear: right;
}
.line
{
width: 100%;
clear: both;
}

View File

@@ -1,178 +0,0 @@
/*
Author: NullQuery
Created on: 2014-09-25
Extension to implement Nanotrasen styled windows.
Additional procs:
hi.setEyeColor(color, client)
Use this to set the color of the 'eye' in the top-left corner of the window.
The client is optional and may be a /mob, /client or /html_interface_client object. It must be specified, since the eye icon is specific to a client.
*/
/datum/html_interface/nanotrasen/New()
. = ..()
// Add appropriate CSS and set the default layout.
src.head = src.head + "<link rel=\"stylesheet\" type=\"text/css\" href=\"hi-nanotrasen.css\" />"
src.updateLayout("")
/datum/html_interface/nanotrasen/updateLayout(layout)
// Wrap the layout in our custom HTML
return ..("<div id=\"ntbgcenter\"></div><div id=\"content\">[layout]</div>")
/datum/html_interface/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
// Update the title in our custom header (in addition to default functionality)
winset(hclient.client, "browser_[REF(src)].uiTitle", list2params(list("text" = "[src.title]")))
/datum/html_interface/nanotrasen/registerResources(var/list/resources = list())
resources["uiBg.png"] = 'uiBg.png'
resources["uiBgcenter.png"] = 'uiBgcenter.png'
resources["hi-nanotrasen.css"] = 'hi-nanotrasen.css'
..(resources)
/datum/html_interface/nanotrasen/createWindow(datum/html_interface_client/hclient)
. = ..() // we want the default window
// Remove the titlebar
winset(hclient.client, "browser_[REF(src)]", list2params(list(
"titlebar" = "false"
)))
// Reposition the browser
winset(hclient.client, "browser_[REF(src)].browser", list2params(list(
"pos" = "0,35",
"size" = "[width]x[height - 35]"
)))
// Add top background image
winset(hclient.client, "browser_[REF(src)].topbg", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "label",
"pos" = "0,0",
"size" = "[width]x35",
"anchor1" = "0,0",
"anchor2" = "100,0",
"image" = "['uiBgtop.png']",
"image-mode" = "tile",
"is-disabled" = "true"
)))
// Add Nanotrasen logo
winset(hclient.client, "browser_[REF(src)].uiTitleFluff", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "label",
"pos" = "[width - 42 - 4 - 24 - 4 - 24 - 4],5",
"size" = "42x24",
"anchor1" = "100,0",
"anchor2" = "100,0",
"image" = "['uiTitleFluff.png']",
"image-mode" = "tile",
"is-disabled" = "true"
)))
// Add Eye picture
winset(hclient.client, "browser_[REF(src)].uiTitleEye", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "label",
"pos" = "8,5",
"size" = "42x24",
"anchor1" = "0,0",
"anchor2" = "0,0",
"image" = "['uiEyeGreen.png']",
"image-mode" = "tile",
"is-disabled" = "true"
)))
// Add title text
winset(hclient.client, "browser_[REF(src)].uiTitle", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "label",
"is-transparent" = "true",
"pos" = "64,0",
"size" = "580x35",
"anchor1" = "0,0",
"anchor2" = "100,0",
"is-disabled" = "true",
"text" = "[src.title]",
"align" = "left",
"font-family" = "verdana,Geneva,sans-serif",
"font-size" = "12", // ~ 16px
"text-color" = "#E9C183"
)))
// Add minimize button
// TODO: Style the button (add image)
winset(hclient.client, "browser_[REF(src)].uiTitleMinimize", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "button",
"is-flat" = "true",
"background-color"="#383838", // should be unnecessary if image is used
"text-color" = "#FFFFFF", // should be unnecessary if image is used
"is-transparent" = "true",
"pos" = "[width - 24 - 4 - 24 - 4],5",
"size" = "24x24",
"anchor1" = "100,0",
"anchor2" = "100,0",
"text" = "-",
"font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
"font-size" = "12", // ~ 16px - should be unnecessary if image is used
// Disable resizing (disables maximizing), minimize window, bind window.on-size to catch 'restore window' button to enable resizing if restored.
"command" = ".winset \"browser_[REF(src)].can-resize=false;browser_[REF(src)].is-minimized=true;browser_[REF(src)].on-size=\".swinset \\\"browser_[REF(src)].can-resize=true;browser_[REF(src)].on-size=\\\"\"\""
)))
// Add close button
// TODO: Style the button (add image)
winset(hclient.client, "browser_[REF(src)].uiTitleClose", list2params(list(
"parent" = "browser_[REF(src)]",
"type" = "button",
"is-flat" = "true",
"background-color"="#383838", // should be unnecessary if image is used
"text-color" = "#FFFFFF", // should be unnecessary if image is used
"command" = "byond://?src=[REF(src)];html_interface_action=onclose",
"is-transparent" = "true",
"pos" = "[width - 24 - 4],5",
"size" = "24x24",
"anchor1" = "100,0",
"anchor2" = "100,0",
"text" = "X",
"font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
"font-size" = "12" // ~ 16px - should be unnecessary if image is used
)))
/datum/html_interface/nanotrasen/enableFor(datum/html_interface_client/hclient)
. = ..()
src.setEyeColor("green", hclient)
/datum/html_interface/nanotrasen/disableFor(datum/html_interface_client/hclient)
hclient.active = FALSE
src.setEyeColor("red", hclient)
/datum/html_interface/nanotrasen/proc/setEyeColor(color, datum/html_interface_client/hclient)
hclient = getClient(hclient)
if (istype(hclient))
var/resource
switch (color)
if ("green")
resource = 'uiEyeGreen.png'
if ("orange")
resource = 'uiEyeOrange.png'
if ("red")
resource = 'uiEyeRed.png'
else
CRASH("Invalid color: [color]")
if (hclient.getExtraVar("eye_color") != color)
hclient.putExtraVar("eye_color", color)
winset(hclient.client, "browser_[REF(src)].uiTitleEye", list2params(list("image" = "[resource]")))
else
WARNING("Invalid object passed to /datum/html_interface/nanotrasen/proc/setEyeColor")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 985 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

View File

@@ -57,7 +57,7 @@
* This allows modules/datums to have the UI attached to them,
* and be a part of another object.
**/
/datum/proc/ui_host()
/datum/proc/ui_host(mob/user)
return src // Default src.
/**

View File

@@ -15,7 +15,7 @@
* return UI_state The state of the UI.
**/
/datum/proc/ui_status(mob/user, datum/ui_state/state)
var/src_object = ui_host()
var/src_object = ui_host(user)
. = UI_CLOSE
if(!state)
return

View File

@@ -72,7 +72,7 @@
var/update_count = 0
for(var/ui_key in open_uis[src_object_key])
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
ui.process(force = 1) // Update the UI.
update_count++ // Count each UI we update.
return update_count
@@ -94,7 +94,7 @@
var/close_count = 0
for(var/ui_key in open_uis[src_object_key])
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
ui.close() // Close the UI.
close_count++ // Count each UI we close.
return close_count
@@ -111,7 +111,7 @@
for(var/src_object_key in open_uis)
for(var/ui_key in open_uis[src_object_key])
for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid.
if(ui && ui.src_object && ui.user && ui.src_object.ui_host(ui.user)) // Check the UI is valid.
ui.close() // Close the UI.
close_count++ // Count each UI we close.
return close_count

View File

@@ -300,7 +300,7 @@
* optional force bool If the UI should be forced to update.
**/
/datum/tgui/process(force = 0)
var/datum/host = src_object.ui_host()
var/datum/host = src_object.ui_host(user)
if(!src_object || !host || !user) // If the object or user died (or something else), abort.
close()
return

View File

@@ -219,11 +219,4 @@ Any-Mode: (hotkey doesn't need to be on)
</font>"}
to_chat(src, hotkey_mode)
to_chat(src, other)
// Needed to circumvent a bug where .winset does not work when used on the window.on-size event in skins.
// Used by /datum/html_interface/nanotrasen (code/modules/html_interface/nanotrasen/nanotrasen.dm)
/client/verb/_swinset(var/x as text)
set name = ".swinset"
set hidden = 1
winset(src, null, x)
to_chat(src, other)

View File

@@ -1551,7 +1551,6 @@
#include "code\modules\food_and_drinks\recipes\tablecraft\recipes_sandwich.dm"
#include "code\modules\food_and_drinks\recipes\tablecraft\recipes_soup.dm"
#include "code\modules\food_and_drinks\recipes\tablecraft\recipes_spaghetti.dm"
#include "code\modules\games\cards.dm"
#include "code\modules\games\cas.dm"
#include "code\modules\goonchat\browserOutput.dm"
#include "code\modules\goonchat\jsErrorHandler.dm"
@@ -1563,10 +1562,6 @@
#include "code\modules\holodeck\items.dm"
#include "code\modules\holodeck\mobs.dm"
#include "code\modules\holodeck\turfs.dm"
#include "code\modules\html_interface\html_interface.dm"
#include "code\modules\html_interface\html_interface_client.dm"
#include "code\modules\html_interface\cards\cards.dm"
#include "code\modules\html_interface\nanotrasen\nanotrasen.dm"
#include "code\modules\hydroponics\biogenerator.dm"
#include "code\modules\hydroponics\gene_modder.dm"
#include "code\modules\hydroponics\grown.dm"

View File

@@ -0,0 +1,144 @@
<script>
component.exports = {
data:{
isHead (ijob) { return ijob % 10 == 0 },
dept_class(ijob){
if (ijob == 0) { return "dept-cap"; } // captain
else if (ijob >= 10 && ijob < 20) { return "dept-sec"; } // security
else if (ijob >= 20 && ijob < 30) { return "dept-med"; } // medical
else if (ijob >= 30 && ijob < 40) { return "dept-sci"; } // science
else if (ijob >= 40 && ijob < 50) { return "dept-eng"; } // engineering
else if (ijob >= 50 && ijob < 60) { return "dept-cargo"; } // cargo
else if (ijob >= 200 && ijob < 230) { return "dept-cent"; } // CentCom
else { return "dept-other"; } // other / unknown
},
health_state(oxy,tox,burn,brute){
var avg_dam = oxy + tox + burn + brute;
if (avg_dam <= 0) { return "health-5"; }
else if (avg_dam <= 25) { return "health-4"; }
else if (avg_dam <= 50) { return "health-3"; }
else if (avg_dam <= 75) { return "health-2"; }
else { return "health-0"; }
}
},
computed:{
sorted_sensors() {
var sensors = this.get('data.sensors')
return sensors.sort(function(a,b) { return a.ijob - b.ijob ;});
}
}
}
</script>
<ui-display>
<ui-section>
<table class='crew'>
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Vitals</th>
<th>Position</th>
{{#if data.link_allowed}}
<th>Tracking</th>
{{/if}}
</tr>
</thead>
<tbody>
{{#each sorted_sensors}}
<tr>
<td>
<span class='{{isHead(ijob) ? "bold " :""}}{{dept_class(ijob)}}'>
{{name}} ({{assignment}})
<span>
</td>
<td>
{{#if oxydam != null}}
<span class='health {{health_state(oxydam,toxdam,burndam,brutedam)}}'></span>
{{else}}
{{#if life_status}}
<span class='health health-5'></span>
{{else}}
<span class='health health-0'></span>
{{/if}}
{{/if}}
</td>
<td>
{{#if oxydam != null}}
<span>
(
<span class='oxy'>{{oxydam}}</span>
/
<span class='toxin'>{{toxdam}}</span>
/
<span class='burn'>{{burndam}}</span>
/
<span class='brute'>{{brutedam}}</span>
)
</span>
{{else}}
{{#if life_status}}
<span>Alive</span>
{{else}}
<span>Dead</span>
{{/if}}
{{/if}}
</td>
<td>
{{#if pos_x != null}}
<span>{{area}}</span>
{{else}}
<span>N/A</span>
{{/if}}
</td>
{{#if data.link_allowed }}
<td>
<ui-button action='select_person' state='{{can_track ? null : "disabled"}}' params='{"name":"{{name}}"}'>Track</ui-button>
</td>
{{/if}}
</tr>
{{/each}}
</tbody>
</table>
</ui-section>
</ui-display>
<style>
.health {
width: 16px;
height: 16px;
background-color: #FFF;
border: 1px solid #434343;
position: relative;
top: 2px;
display: inline-block;
}
.health-5 { background-color: #17d568; }
.health-4 { background-color: #2ecc71; }
.health-3 { background-color: #e67e22; }
.health-2 { background-color: #ed5100; }
.health-1 { background-color: #e74c3c; }
.health-0 { background-color: #ed2814; }
.dept-cap {color : #C06616;}
.dept-sec {color : #E74C3C;}
.dept-med {color : #3498DB;}
.dept-sci {color : #9B59B6;}
.dept-eng {color : #F1C40F;}
.dept-cargo {color : #F39C12;}
.dept-cent {color : #00C100;}
.dept-other {color: #C38312;}
.oxy { color : #3498db; }
.toxin { color : #2ecc71; }
.burn { color : #e67e22; }
.brute { color : #e74c3c; }
table.crew{
border-collapse: collapse;
}
table.crew td {
padding : 0px 10px;
}
</style>