HTML UI Interfaces

# Version 1.0

THEY DON'T LAG LIKE NANOUI
Only crew monitoring computer exists
Doesn't display coordinate data that I've seen
Takes a few seconds to populate with information as well
None of the improvements/bugfixes have been applied yet
This commit is contained in:
clusterfack
2015-07-07 17:45:35 -05:00
parent 436e36750b
commit 9417d5149b
13 changed files with 999 additions and 29 deletions

View File

@@ -0,0 +1,105 @@
body
{
padding-left: 490px;
cursor: default;
}
#ntbgcenter
{
background-position: 550px 0px !important;
}
#minimap
{
position: fixed;
top: 8px;
left: 8px;
border: 2px inset #888;
}
#textbased
{
width: 100%;
}
#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;
}
a { display: none; }
.health
{
width: 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; }
.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;
}

View File

@@ -0,0 +1,567 @@
/obj/machinery/computer/crew
name = "Crew monitoring computer"
desc = "Used to monitor active health sensors built into most of the crew's uniforms."
icon_state = "crew"
use_power = 1
idle_power_usage = 250
active_power_usage = 500
circuit = "/obj/item/weapon/circuitboard/crew"
var/list/tracked = list( )
var/track_special_role
light_color = LIGHT_COLOR_BLUE
light_range_on = 2
/obj/machinery/computer/crew/New()
tracked = list()
..()
/obj/machinery/computer/crew/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/computer/crew/attack_hand(mob/user)
. = ..()
if(.)
return
if(stat & (BROKEN|NOPOWER))
return
crewmonitor.show(user)
/obj/machinery/computer/crew/update_icon()
if(stat & BROKEN)
icon_state = "crewb"
else
if(stat & NOPOWER)
src.icon_state = "c_unpowered"
stat |= NOPOWER
else
icon_state = initial(icon_state)
stat &= ~NOPOWER
var/global/datum/crewmonitor/crewmonitor = new
/datum/crewmonitor
var/list/jobs
var/list/interfaces
var/list/data
var/const/MAX_ICON_DIMENSION = 1024
var/const/ICON_SIZE = 4
var/initialized = FALSE
/datum/crewmonitor/New()
. = ..()
var/list/jobs = new/list()
jobs["Captain"] = 00
jobs["Head of Personnel"] = 50
jobs["Head of Security"] = 10
jobs["Warden"] = 11
jobs["Security Officer"] = 12
jobs["Detective"] = 13
jobs["Chief Medical Officer"] = 20
jobs["Chemist"] = 21
jobs["Geneticist"] = 22
jobs["Virologist"] = 23
jobs["Medical Doctor"] = 24
jobs["Research Director"] = 30
jobs["Scientist"] = 31
jobs["Roboticist"] = 32
jobs["Chief Engineer"] = 40
jobs["Station Engineer"] = 41
jobs["Atmospheric Technician"] = 42
jobs["Quartermaster"] = 51
jobs["Shaft Miner"] = 52
jobs["Cargo Technician"] = 53
jobs["Bartender"] = 61
jobs["Cook"] = 62
jobs["Botanist"] = 63
jobs["Librarian"] = 64
jobs["Chaplain"] = 65
jobs["Clown"] = 66
jobs["Mime"] = 67
jobs["Janitor"] = 68
jobs["Lawyer"] = 69
jobs["Admiral"] = 200
jobs["Centcom Commander"] = 210
jobs["Custodian"] = 211
jobs["Medical Officer"] = 212
jobs["Research Officer"] = 213
jobs["Emergency Response Team Commander"] = 220
jobs["Security Response Officer"] = 221
jobs["Engineer Response Officer"] = 222
jobs["Medical Response Officer"] = 223
jobs["Assistant"] = 999 //Unknowns/custom jobs should appear after civilians, and before assistants
src.jobs = jobs
src.interfaces = list()
src.data = list()
/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 (!z) z = mob.z
if (z > 0 && src.interfaces)
var/datum/html_interface/hi
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>")
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>")
src.update(z, TRUE)
else
hi = src.interfaces["[z]"]
hi = src.interfaces["[z]"]
hi.show(mob)
src.updateFor(mob, hi, z)
/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)
for (var/list/L in data)
hi.callJavaScript("add", L, hclient_or_mob)
/datum/crewmonitor/proc/update(z, ignore_unused = FALSE)
if (src.interfaces["[z]"])
var/datum/html_interface/hi = src.interfaces["[z]"]
if (ignore_unused || hi.isUsed())
var/list/results = list()
var/obj/item/clothing/under/U
var/obj/item/weapon/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
for(var/mob/living/carbon/human/H in mob_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
// Are the suit sensors on?
if (U.has_sensor && U.sensor_mode)
pos = H.z == 0 || U.sensor_mode == 3 ? get_turf(H) : null
// 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
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 >= 1) life_status = (!H.stat ? "true" : "false")
else life_status = null
if (U.sensor_mode >= 2)
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 >= 3)
if (!pos) pos = get_turf(H)
var/area/player_area = get_area(H)
area = format_text(player_area.name)
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())
src.data = results
src.updateFor(null, hi, z) // updates for everyone
/mob/living/carbon/human/proc/can_track()
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
var/turf/T = get_turf(src)
if(!T)
return 0
if(T.z == CENTCOMM_Z) //dont detect mobs on centcomm
return 0
if(T.z >= map.zLevels.len)
return 0
. = 1
/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
return (hclient.client.mob && hclient.client.mob.stat == 0 && hclient.client.mob.z == text2num(z) && ( isAI(hclient.client.mob) || (locate(/obj/machinery/computer/crew, range(1, hclient.client.mob))) ) )
/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 range(10, tile)
if (!C) C = locate(/obj/machinery/camera) in range(15, tile)
if (C)
var/turf/current_loc = AI.eyeobj.loc
spawn(min(30, get_dist(get_turf(C), AI.eyeobj) / 4))
if (AI && AI.eyeobj && current_loc == AI.eyeobj.loc)
AI.switchCamera(C)
/mob/living/carbon/human/Move()
if(src.w_uniform)
var/old_z = src.z
. = ..()
if (old_z != src.z) crewmonitor.queueUpdate(old_z)
crewmonitor.queueUpdate(src.z)
else
return ..()
/datum/crewmonitor/proc/queueUpdate(z)
var/datum/controller/process/html/html = processScheduler.getProcess("html")
html.queue(crewmonitor, "update", z)
/datum/crewmonitor/proc/generateMiniMaps()
spawn
for (var/z = 1 to world.maxz) src.generateMiniMap(z)
testing("MINIMAP: All minimaps have been generated.")
for (var/client/C in clients)
src.sendResources(C)
src.initialized = TRUE
/datum/crewmonitor/proc/sendResources(client/C)
C << browse_rsc('crew.js', "crewmonitor.js")
C << browse_rsc('crew.css', "crewmonitor.css")
for (var/z = 1 to world.maxz) C << browse_rsc(file("[getMinimapFile(z)].png"), "minimap_[z].png")
/datum/crewmonitor/proc/getMinimapFile(z)
return "data/minimaps/map_[z]"
// Activate this to debug tile mismatches in the minimap.
// This will store the full information on each tile and compare it the next time you run the minimap.
// It can be used to find out what's changed since the last iteration.
// Only activate this when you need it - this should never be active on a live server!
// #define MINIMAP_DEBUG
/datum/crewmonitor/proc/generateMiniMap(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy)
var/result_path = "[src.getMinimapFile(z)].png"
var/hash_path = "[src.getMinimapFile(z)].md5"
var/list/tiles = block(locate(x1, y1, z), locate(x2, y2, z))
var/hash = ""
var/temp
var/obj/obj
#ifdef MINIMAP_DEBUG
var/tiledata_path = "data/minimaps/debug_tiledata_[z].sav"
var/savefile/F = new/savefile(tiledata_path)
#endif
// Note for future developer: If you have tiles on the map with random or dynamic icons this hash check will fail
// every time. You'll have to modify this code to generate a unique hash for your object.
// Don't forget to modify the minimap generation code to use a default icon (or skip generation altogether).
for (var/turf/tile in tiles)
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/unsimulated/mineral) || (tile.loc.name == "Space" && istype(tile, /turf/unsimulated/floor/asteroid)))
temp = "/area/asteroid"
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/unsimulated/floor/asteroid))
temp = "/area/mine/explored"
else if (tile.loc.type == /area/start || (tile.type == /turf/space && !(locate(/obj/structure/lattice) in tile)) || istype(tile, /turf/space/transit))
temp = "/turf/space"
if (locate(/obj/structure/catwalk) in tile)
else
else if (tile.type == /turf/space)
if (locate(/obj/structure/catwalk) in tile)
temp = "/obj/structure/lattice/catwalk"
else
temp = "/obj/structure/lattice"
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/shuttle/window) in tile))
temp = "/obj/structure/window/shuttle"
else
temp = "[tile.icon][tile.icon_state][tile.dir]"
obj = locate(/obj/structure/transit_tube) in tile
if (obj) temp = "[temp]/obj/structure/transit_tube[obj.icon_state][obj.dir]"
#ifdef MINIMAP_DEBUG
if (F["/[tile.y]/[tile.x]"] && F["/[tile.y]/[tile.x]"] != temp)
CRASH("Mismatch: [tile.type] at [tile.x],[tile.y],[tile.z] ([tile.icon], [tile.icon_state], [tile.dir])")
else
F["/[tile.y]/[tile.x]"] << temp
#endif
hash = md5("[hash][temp]")
if (fexists(result_path))
if (!fexists(hash_path) || trim(file2text(hash_path)) != hash)
fdel(result_path)
fdel(hash_path)
if (!fexists(result_path))
ASSERT(x1 > 0)
ASSERT(y1 > 0)
ASSERT(x2 <= world.maxx)
ASSERT(y2 <= world.maxy)
var/icon/map_icon = new/icon('html/mapbase1024.png')
// map_icon is fine and contains only 1 direction at this point.
ASSERT(map_icon.Width() == MAX_ICON_DIMENSION && map_icon.Height() == MAX_ICON_DIMENSION)
testing("MINIMAP: Generating minimap for z-level [z].")
var/i = 0
var/icon/turf_icon
var/icon/obj_icon
var/old_icon
var/old_icon_state
var/old_dir
var/new_icon
var/new_icon_state
var/new_dir
for (var/turf/tile in tiles)
if (tile.loc.type != /area/start && (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile) || (locate(/obj/structure/transit_tube) in tile)) && !istype(tile, /turf/space/transit))
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/unsimulated/mineral) || (tile.loc.name == "Space" && istype(tile, /turf/unsimulated/floor/asteroid)))
new_icon = 'icons/turf/walls.dmi'
new_icon_state = "rock"
new_dir = 2
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/unsimulated/floor/asteroid))
new_icon = 'icons/turf/floors.dmi'
new_icon_state = "asteroid"
new_dir = 2
else if (tile.type == /turf/space)
obj = locate(/obj/structure/lattice) in tile
if (!obj) obj = locate(/obj/structure/transit_tube) in tile
ASSERT(obj != null)
if (obj)
new_icon = obj.icon
new_dir = obj.dir
new_icon_state = obj.icon_state
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/shuttle/window) in tile))
new_icon = 'icons/obj/structures.dmi'
new_dir = 2
new_icon_state = "swindow"
else
new_icon = tile.icon
new_icon_state = tile.icon_state
new_dir = tile.dir
if (new_icon != old_icon || new_icon_state != old_icon_state || new_dir != old_dir)
old_icon = new_icon
old_icon_state = new_icon_state
old_dir = new_dir
turf_icon = new/icon(new_icon, new_icon_state, new_dir, 1, 0)
turf_icon.Scale(ICON_SIZE, ICON_SIZE)
if (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile))
obj = locate(/obj/structure/transit_tube) in tile
if (obj)
obj_icon = new/icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
obj_icon.Scale(ICON_SIZE, ICON_SIZE)
turf_icon.Blend(obj_icon, ICON_OVERLAY)
map_icon.Blend(turf_icon, ICON_OVERLAY, ((tile.x - 1) * ICON_SIZE), ((tile.y - 1) * ICON_SIZE))
if ((++i) % 512 == 0) sleep(1) // deliberate delay to avoid lag spikes
if ((i % 1024) == 0) testing("MINIMAP: Generated [i] of [tiles.len] tiles.")
else
sleep(-1) // avoid sleeping if possible: prioritize pending procs
testing("MINIMAP: Generated [tiles.len] of [tiles.len] tiles.")
// BYOND BUG: map_icon now contains 4 directions? Create a new icon with only a single state.
var/icon/result_icon = new/icon()
result_icon.Insert(map_icon, "", SOUTH, 1, 0)
fcopy(result_icon, result_path)
text2file(hash, hash_path)
#ifdef MINIMAP_DEBUG
#undef MINIMAP_DEBUG
#endif
/*
/obj/machinery/computer/crew/interact(mob/user)
ui_interact(user)
/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
user.set_machine(src)
src.scan()
var/data[0]
var/list/crewmembers = list()
for(var/mob/living/carbon/brain/B in mob_list)
var/turf/pos = get_turf(B)
if(!pos) continue
var/obj/item/device/mmi/M = B.loc
if(istype(M) && M.brainmob == B)
if(isrobot(M.loc))
continue
var/list/crewmemberData = list()
crewmemberData["sensor_type"] = 3
crewmemberData["dead"] = 0
crewmemberData["oxy"] = 0
crewmemberData["tox"] = 0
crewmemberData["fire"] = 0
crewmemberData["brute"] = 0
crewmemberData["name"] = M.name
crewmemberData["rank"] = "Unknown"
crewmemberData["area"] = get_area(M)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmemberData["z"] = pos.z
crewmemberData["xoffset"] = pos.x-WORLD_X_OFFSET[pos.z]
crewmemberData["yoffset"] = pos.y-WORLD_Y_OFFSET[pos.z]
crewmembers += list(crewmemberData)
for(var/obj/item/clothing/under/C in src.tracked)
var/turf/pos = get_turf(C)
if((C) && (C.has_sensor) && (pos) && (pos.z != CENTCOMM_Z) && C.sensor_mode)
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
var/list/crewmemberData = list()
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["dead"] = H.stat > 1
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
crewmemberData["name"] = "Unknown"
crewmemberData["rank"] = "Unknown"
if(H.wear_id && istype(H.wear_id, /obj/item/weapon/card/id) )
var/obj/item/weapon/card/id/I = H.wear_id
crewmemberData["name"] = I.name
crewmemberData["rank"] = I.rank
else if(H.wear_id && istype(H.wear_id, /obj/item/device/pda) )
var/obj/item/device/pda/P = H.wear_id
crewmemberData["name"] = (P.id ? P.id.name : "Unknown")
crewmemberData["rank"] = (P.id ? P.id.rank : "Unknown")
crewmemberData["area"] = get_area(H)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmemberData["z"] = pos.z
crewmemberData["xoffset"] = pos.x-WORLD_X_OFFSET[pos.z]
crewmemberData["yoffset"] = pos.y-WORLD_Y_OFFSET[pos.z]
crewmembers += list(crewmemberData)
// Works around list += list2 merging lists; it's not pretty but it works
//crewmembers += "temporary item"
//crewmembers[crewmembers.len] = crewmemberData
crewmembers = sortList(crewmembers)
data["crewmembers"] = crewmembers
//ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui) // no ui has been passed, so we'll search for one
ui = nanomanager.get_open_ui(user, src, ui_key)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
// we want to show the map by default
ui.set_show_map(1)
ui.set_initial_data(data)
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
else
// The UI is already open so push the new data to it
ui.push_data(data)
return
/obj/machinery/computer/crew/proc/is_scannable(const/obj/item/clothing/under/C, const/mob/living/carbon/human/H)
if(!istype(H) || H.iscorpse)
return 0
if(isnull(track_special_role))
return C.has_sensor
return (H.mind ? H.mind.special_role == track_special_role : 1)
/obj/machinery/computer/crew/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
if(is_scannable(C, H))
tracked |= C
return 1*/

View File

@@ -0,0 +1,196 @@
var isAI = null;
var scale_x;
var scale_y;
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>");
$("#minimap").append("<img src=\"minimap_" + z + ".png\" id=\"map\" style=\"width: auto; height: 480px;\" />");
$("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);
window.location.href = "byond://?src=" + hSrc + "&action=select_position&x=" + x + "&y=" + y;
});
});
var updateMap = true;
function switchTo(i)
{
if (i == 1)
{
$("#minimap").hide();
$("#textbased").show();
}
else
{
$("#textbased").hide();
$("#minimap").show();
}
}
function clearAll(ai)
{
if (isAI === null) { isAI = (ai == "true"); }
$("#textbased-tbody").empty();
$("#minimap .dot").remove();
}
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 (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; }
}
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>";
}
else
{
healthHTML = "<div class=\"health health-" + (life_status == "" ? -1 : (life_status == "true" ? 4 : 0)) + " 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=\"text-align: center; 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 + ")")))); }
else { tdElem.text("Not Available"); }
trElem.append(tdElem);
$("#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 = (translate(x - 1, scale_x) - 1.5).toFixed(0);
var ty = (translate(y - 1, scale_y) + 3).toFixed(0);
var dotElem = $("<div class=\"dot\" style=\"transition: .2s all; position: absolute; top: " + ty + "px; left: " + tx + "px; background-color: " + color + "; border: 1px solid transparent; width: 3px; height: 3px; z-index: " + ijob + ";\"></div>");
$("#minimap").append(dotElem);
function enable()
{
dotElem.css({ "border-color": color, "z-index": 9999, "width": "8px", "height": "8px", "margin-top": "-2px", "margin-left": "-3px" });
}
function disable()
{
dotElem.css({ "border-color": "transparent", "z-index": ijob, "width": "3px", "height": "3px", "margin-top": "0px", "margin-left": "0px", "filter": "" });
}
function click(e)
{
e.preventDefault();
e.stopPropagation();
window.location.href = "byond://?src=" + hSrc + "&action=select_person&name=" + encodeURIComponent(name);
}
trElem.on("mouseover", enable).on("mouseout", disable).on("click", click);
dotElem.on("mouseover", function()
{
trElem.addClass("hover");
enable();
}).on("mouseout", function()
{
trElem.removeClass("hover");
disable();
}).on("click", click);
}
}
function translate(n, scale)
{
return (n * tile_size) * scale;
}

View File

@@ -54,6 +54,10 @@ Hides the HTML interface from the provided client. This will close the browser w
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
@@ -68,12 +72,13 @@ 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. Quisque porttitor, leo nec facilisis aliquam, elit ligula iaculis sapien, non vulputate neque metus id quam. Cras mauris nisl, pharetra malesuada massa nec, volutpat feugiat metus. Duis sed condimentum purus. In ex leo, laoreet ac rhoncus quis, volutpat ac risus. Ut et tempus magna. Vestibulum in nisl vitae metus commodo tempus et dapibus urna. Integer nec vestibulum lacus. Donec quis metus non lacus bibendum lacinia. Aenean tincidunt libero vestibulum metus blandit pharetra. Nunc quis magna volutpat, bibendum nulla in, sagittis risus. Sed id velit sodales, bibendum purus accumsan, eleifend purus.</p><p>Suspendisse potenti. Proin lorem orci, euismod at elit in, molestie dapibus leo. Nulla lacinia vel urna nec vulputate. Praesent non enim metus. Quisque non pharetra justo. Integer efficitur massa orci, vitae placerat libero eleifend sit amet. Fusce in placerat quam. Praesent quis lectus turpis. Aenean mattis lacus sed laoreet sagittis. Aliquam efficitur nisl at tellus ultrices auctor. Quisque hendrerit, mi quis suscipit interdum, justo magna gravida libero, et venenatis sapien ante quis odio.</p><p>Etiam ullamcorper condimentum lacus, eu laoreet ipsum gravida et. Fusce odio libero, iaculis euismod finibus sit amet, condimentum ac ante. Etiam pretium lorem mauris, sit amet varius tortor efficitur eget. Pellentesque at lacinia lectus. Integer tristique nibh hendrerit purus placerat dapibus. Cras elementum est elementum, bibendum orci nec, consequat elit. Fusce porttitor neque quis libero placerat, vel varius arcu aliquet. Aenean vitae rhoncus nunc, non tempus magna. Aliquam lacinia sit amet dolor id maximus. Curabitur eget eleifend nisl. Mauris interdum nibh feugiat lectus lacinia fringilla. Aliquam nec magna vel leo ultricies dignissim. Duis eu luctus odio, finibus dictum nulla.</p>Mauris fringilla a lorem vel euismod. Sed auctor eget lorem sed lacinia. Maecenas vel posuere sapien. In lobortis odio non tincidunt ultricies. Sed consequat molestie orci et pharetra. Suspendisse potenti. Vestibulum vitae ornare risus, nec semper arcu. Duis et interdum lacus.</p><p>Etiam urna nulla, pulvinar at est auctor, varius feugiat orci. Vestibulum efficitur maximus imperdiet. Donec vehicula, leo sit amet condimentum pulvinar, urna felis aliquet velit, bibendum placerat dui libero sed tortor. Vivamus ac diam commodo nisi facilisis lacinia. Aenean a rhoncus risus, venenatis efficitur arcu. Curabitur tincidunt nulla eget augue malesuada imperdiet. Quisque ligula purus, dictum a imperdiet eget, eleifend eu leo. Phasellus massa ipsum, molestie nec pellentesque eu, scelerisque et mi. Vivamus at libero varius, lacinia magna non, imperdiet tortor. Donec scelerisque ipsum sollicitudin justo ornare accumsan. In velit orci, lobortis eget maximus et, scelerisque ut nulla. Cras sit amet finibus sapien. Aenean metus lorem, gravida a rutrum quis, varius eu arcu. Integer ac hendrerit purus. Aliquam cursus ultricies tortor. Fusce scelerisque, arcu id pellentesque accumsan, nulla turpis tempus lectus, tincidunt blandit mi nisi non metus.</p>")
hi.updateContent("content", "<p>Head of Security Announcement: WHY"</p>)
hi.show(src)
*/
/var/list/html_interfaces = new/list()
/datum/html_interface
// The atom we should report to.
var/atom/ref
@@ -100,6 +105,8 @@ mob/verb/test()
var/height
/datum/html_interface/New(atom/ref, title, width = 700, height = 480, head = "")
html_interfaces.Add(src)
. = ..()
src.ref = ref
@@ -109,9 +116,9 @@ mob/verb/test()
src.head = head
/datum/html_interface/Del()
if (src.clients)
for (var/client in src.clients)
src.hide(src.clients[client])
src.closeAll()
html_interfaces.Remove(src)
return ..()
@@ -160,7 +167,19 @@ mob/verb/test()
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) src.executeJavaScript(jscript, src.clients[client])
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
@@ -180,8 +199,8 @@ mob/verb/test()
for (var/client in src.clients)
hclient = src._getClient(src.clients[client])
if (hclient && hclient.active) src._renderContent(id, hclient, ignore_cache)
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)
@@ -200,6 +219,8 @@ mob/verb/test()
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)
@@ -243,24 +264,34 @@ mob/verb/test()
/datum/html_interface/proc/isUsed()
if (src.clients && src.clients.len > 0)
var/datum/html_interface_client/hclient
for (var/key in clients)
hclient = clients[key]
if (hclient.active) return TRUE
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)
if (hascall(src.ref, "hiIsValidClient"))
var/res = call(src.ref, "hiIsValidClient")(hclient)
// 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)
if (res)
if (!hclient.active) src.enableFor(hclient)
else
if (hclient.active) src.disableFor(hclient)
return hclient
else
@@ -268,8 +299,9 @@ mob/verb/test()
else
return null
/datum/html_interface/proc/_renderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
if (hclient && hclient.is_loaded)
/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)
@@ -279,8 +311,9 @@ mob/verb/test()
hclient.client << output(list2params(list(title)), "browser_\ref[src].browser:setTitle")
/datum/html_interface/proc/_renderLayout(datum/html_interface_client/hclient)
if (hclient && hclient.is_loaded)
/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.
@@ -289,10 +322,10 @@ mob/verb/test()
hclient.client << output(list2params(list(html)), "browser_\ref[src].browser:updateLayout")
for (var/id in src.content_elements) src._renderContent(id, hclient)
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)
if (hclient && hclient.is_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.
@@ -311,11 +344,12 @@ mob/verb/test()
if ("onload")
hclient.layout = null
hclient.content_elements.len = 0
src._renderTitle(hclient, TRUE, TRUE)
src._renderLayout(hclient, TRUE)
hclient.is_loaded = TRUE
src._renderTitle(hclient, TRUE)
src._renderLayout(hclient)
if ("onclose")
src.hide(hclient)
else if (src.ref && hclient.active) src.ref.Topic(href, href_list, hclient)
else if (src.ref && hclient.active) src.ref.Topic(href, href_list, hclient)

View File

@@ -40,4 +40,4 @@
return .
/datum/html_interface_client/proc/getExtraVar(key)
if (src.extra_vars) return src.extra_vars[key]
if (src.extra_vars) return src.extra_vars[key]

View File

@@ -11,6 +11,14 @@ body
line-height: 170%; /* NullQuery: 170% of what? */
}
/* Fix for IE8 */
body
{
background-color: #1F1F1F\9 !important;
}
#ntbgcenter
{
position: absolute;