html_interface removal and crew monitoring console refactor.
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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> </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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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; }
|
||||
@@ -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)
|
||||
|
Before Width: | Height: | Size: 277 KiB |
@@ -1,11 +0,0 @@
|
||||
html
|
||||
{
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
font-family: Arial;
|
||||
overflow-y: scroll;
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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]
|
||||
11
code/modules/html_interface/js/bootstrap.min.js
vendored
@@ -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"); }
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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")
|
||||
|
Before Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 912 B |
|
Before Width: | Height: | Size: 985 B |
|
Before Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 946 B |
@@ -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.
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
|
||||
144
tgui/src/interfaces/crew.ract
Normal 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>
|
||||