diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index dccf6886bbd..1683aceca3f 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -75,6 +75,8 @@ datum/mind
if(new_character.mind) //disassociate any mind currently in our new body's mind variable
new_character.mind.current = null
+ nanomanager.user_transferred(current, new_character)
+
current = new_character //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index d1f3719b5d4..cea60406f20 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -236,6 +236,7 @@ var/next_external_rsc = 0
'nano/css/shared.css',
'nano/css/icons.css',
'nano/templates/chem_dispenser.tmpl',
+ 'nano/templates/apc.tmpl',
'nano/templates/cryo.tmpl',
'nano/images/uiBackground.png',
'nano/images/uiIcons16.png',
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index 7a09e7ffd3b..c1be3cca799 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -112,5 +112,26 @@
for (var/datum/nanoui/ui in user.open_uis)
ui.close();
+ /**
+ * This is called when a player transfers from one mob to another
+ * Transfers all open UIs to the new mob
+ *
+ * @param oldMob /mob The user's old mob
+ * @param newMob /mob The user's new mob
+ *
+ * @return nothing
+ */
+/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
+ if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
+ newMob.open_uis = list()
+
+ for (var/datum/nanoui/ui in oldMob.open_uis)
+ ui.user = newMob
+ newMob.open_uis.Add(ui)
+
+ oldMob.open_uis.Cut()
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index e1ac8556f2b..901f68ec35f 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -349,6 +349,7 @@ nanoui is used to open and update nano browser uis
window_size = "size=[width]x[height];"
update_status(0)
user << browse(get_html(), "window=[window_id];[window_size][window_options]")
+ winset(user, "mapwindow.map", "focus=true") // Return keyboard focus to map.
on_close_winset()
//onclose(user, window_id)
nanomanager.ui_opened(src)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index af8d5769804..df608c245bd 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -485,134 +485,87 @@
if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
wires.Interact(user)
- user.set_machine(src)
- var/t = "" //"Area Power Controller ([area.name])"
-
- //This goes after the wire stuff. They should be able to fix a physical problem when a wire is cut
- if ( (get_dist(src, user) > 1 ))
- if (!issilicon(user))
- user.unset_machine()
- user << browse(null, "window=apc")
- return
- else if (issilicon(user) && src.aidisabled && !src.malfhack)
- user << "AI control for this APC interface has been disabled."
- user.unset_machine()
- user << browse(null, "window=apc")
- return
- else if (src.malfai && isAI(user))
- var/mob/living/silicon/ai/AI = user
- if ((src.malfai != AI && src.malfai != AI.parent) && !islinked(AI, malfai))
- user << "AI control for this APC interface has been disabled."
- user.unset_machine()
- user << browse(null, "window=apc")
- return
+ return ui_interact(user)
- if(locked && (!istype(user, /mob/living/silicon)))
- t += "
Swipe ID card to unlock interface
"
- t += "Status
"
- t += "Main Breaker: [operating ? "On" : "Off"]
"
- t += "External Power: [ main_status ? (main_status ==2 ? "Good" : "Low") : "None"]
"
- t += "Power Cell: [cell ? "[round(cell.percent())]%" : "Not connected."]"
- if(cell)
- t += "
Charge Mode: [chargemode ? "Auto" : "Off"]"
- t += " ([charging ? ( charging == 1 ? "Charging" : "Fully charged" ) : "Not charging"])"
+/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main")
+ if(!user)
+ return
- t += "Power Channels
"
-
- var/list/L = list ("Off","Off (Auto)", "On", "On (Auto)")
-
- t += "Equipment: [add_lspace(lastused_equip, 6)] W : [L[equipment+1]]
"
- t += "Lighting: [add_lspace(lastused_light, 6)] W : [L[lighting+1]]
"
- t += "Environmental:[add_lspace(lastused_environ, 6)] W : [L[environ+1]]
"
-
- t += "
Total Load: [lastused_light + lastused_equip + lastused_environ] W"
- t += "
Cover Lock: [coverlocked ? "Engaged" : "Disengaged"]"
-
- else
- if (!istype(user, /mob/living/silicon))
- t += "Swipe ID card to lock interface
"
- t += "Status
"
- t += "Main Breaker: [operating ? "On Off" : "On Off" ]
"
- t += "External power : [ main_status ? (main_status ==2 ? "Good" : "Low") : "None"]
"
- if(cell)
- t += "Power cell: [round(cell.percent())]%"
- t += "
Charge mode: [chargemode ? "Off Auto" : "Off Auto"]"
- t += " ([charging ? ( charging == 1 ? "Charging" : "Fully charged" ) : "Not charging"])"
+ var/malfStatus
+ if (ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai))
+ if (src.malfai == (user:parent ? user:parent : user))
+ if (src.occupant == user)
+ malfStatus = 3 // 3 = User is shunted in this APC
+ else if (istype(user.loc, /obj/machinery/power/apc))
+ malfStatus = 4 // 4 = User is shunted in another APC
+ else
+ malfStatus = 2 // 2 = APC hacked by user, and user is in its core.
else
- t += "Power cell: Not connected."
+ malfStatus = 1 // 1 = APC not hacked.
+ else
+ malfStatus = 0 // 0 = User is not a Malf AI
- t += "
Power channels
"
+ var/list/data = list(
+ "locked" = locked,
+ "isOperating" = operating,
+ "externalPower" = main_status,
+ "powerCellStatus" = cell ? cell.percent() : null,
+ "chargeMode" = chargemode,
+ "chargingStatus" = charging,
+ "totalLoad" = lastused_equip + lastused_light + lastused_environ,
+ "coverLocked" = coverlocked,
+ "siliconUser" = istype(user, /mob/living/silicon),
+ "malfStatus" = malfStatus,
- t += "Equipment: [add_lspace(lastused_equip, 6)] W : "
- var/key = "eqp"
- switch(equipment)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
- t +="
"
+ "powerChannels" = list(
+ list(
+ "title" = "Equipment",
+ "powerLoad" = lastused_equip,
+ "status" = equipment,
+ "topicParams" = list(
+ "auto" = list("eqp" = 3),
+ "on" = list("eqp" = 2),
+ "off" = list("eqp" = 1)
+ )
+ ),
+ list(
+ "title" = "Lighting",
+ "powerLoad" = lastused_light,
+ "status" = lighting,
+ "topicParams" = list(
+ "auto" = list("lgt" = 3),
+ "on" = list("lgt" = 2),
+ "off" = list("lgt" = 1)
+ )
+ ),
+ list(
+ "title" = "Environment",
+ "powerLoad" = lastused_environ,
+ "status" = environ,
+ "topicParams" = list(
+ "auto" = list("env" = 3),
+ "on" = list("env" = 2),
+ "off" = list("env" = 1)
+ )
+ )
+ )
+ )
- t += "Lighting: [add_lspace(lastused_light, 6)] W : "
- key = "lgt"
- switch(lighting)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
- t +="
"
-
-
- t += "Environmental:[add_lspace(lastused_environ, 6)] W : "
- key = "env"
- switch(environ)
- if(0)
- t += "Off On Auto"
- if(1)
- t += "Off On Auto (Off)"
- if(2)
- t += "Off On Auto"
- if(3)
- t += "Off On Auto (On)"
-
-
-
- t += "
Total Load: [lastused_light + lastused_equip + lastused_environ] W
"
- t += "
Cover Lock: [coverlocked ? "Engaged" : "Disengaged"]"
-
-
- if (istype(user, /mob/living/silicon))
- t += "
Overload lighting circuit
"
- if (ticker && ticker.mode)
-// world << "there's a ticker"
- if(user.mind in ticker.mode.malf_ai)
-// world << "ticker says its malf"
- if (!src.malfai)
- t += "
Override Programming
"
- else
- t += "
APC Hacked
"
- if(!src.occupant)
- t += "Shunt Core Processes
"
- else
- t += "Core Processes Uploaded
"
-
- //t += "
Close"
-
- //user << browse(t, "window=apc")
- //onclose(user, "apc")
- var/datum/browser/popup = new(user, "apc", "[area.name] APC")
- popup.set_content(t)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.open()
- return
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+ if (!ui)
+ // the ui does not exist, so we'll create a new one
+ ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 500, data["siliconUser"] ? 465 : 390)
+ // When the UI is first opened this is the data it will use
+ ui.set_initial_data(data)
+ ui.open()
+ // Auto update every Master Controller tick
+ ui.set_auto_update(1)
+ else
+ // The UI is already open so push the new data to it
+ ui.push_data(data)
+ return
+ //user.set_machine(src)
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
@@ -691,11 +644,11 @@
/obj/machinery/power/apc/Topic(href, href_list)
if(..())
- return
+ return 0
if(!isrobot(usr))
if(!can_use(usr, 1))
- return
+ return 0
usr.set_machine(src)
@@ -735,11 +688,11 @@
else if( href_list["close"] )
usr << browse(null, "window=apc")
usr.unset_machine()
- return
+ return 0
else if (href_list["close2"])
usr << browse(null, "window=apcwires")
usr.unset_machine()
- return
+ return 0
else if (href_list["overload"])
if( istype(usr, /mob/living/silicon) && !src.aidisabled )
@@ -747,10 +700,10 @@
else if (href_list["malfhack"])
var/mob/living/silicon/ai/malfai = usr
- if( istype(malfai, /mob/living/silicon/ai) && !src.aidisabled )
+ if( istype(malfai, /mob/living/silicon/ai) && !src.aidisabled && (ticker && ticker.mode && (malfai.mind in ticker.mode.malf_ai)) )
if (malfai.malfhacking)
malfai << "You are already hacking an APC."
- return
+ return 1
malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
malfai.malfhack = src
malfai.malfhacking = 1
@@ -759,6 +712,7 @@
if (!src.aidisabled)
malfai.malfhack = null
malfai.malfhacking = 0
+ locked = 1
if (ticker.mode.config_tag == "malfunction")
if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
ticker.mode:apcs++
@@ -775,9 +729,17 @@
else if (href_list["deoccupyapc"])
malfvacate()
+ else if (href_list["toggleaccess"])
+ if (istype(usr, /mob/living/silicon/ai) && !src.aidisabled)
+ if(emagged || (stat & (BROKEN|MAINT)))
+ usr << "The APC does not respond to the command."
+ else
+ locked = !locked
+ update_icon()
+
src.updateDialog()
- return
+ return 1
/obj/machinery/power/apc/proc/toggle_breaker()
operating = !operating
diff --git a/html/changelog.html b/html/changelog.html
index 98f40394f4e..0f13704d693 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -61,6 +61,15 @@ should be listed in the changelog upon commit tho. Thanks. -->
+
+
9 November 2013
+
Yota updated:
+
+ - Along with a NanoUI upgrade, the human interface lock of APCs can now be toggled by the AI.
+ - NanoUI dialogs will no longer steal keyboard focus when opened.
+
+
+
6 November 2013
Cheridan updated:
diff --git a/nano/css/shared.css b/nano/css/shared.css
index 7400e2e25e6..6761674cd44 100644
--- a/nano/css/shared.css
+++ b/nano/css/shared.css
@@ -7,6 +7,7 @@ body
line-height: 170%;
font-family: Verdana, Geneva, sans-serif;
background: #272727 url(uiBackground.png) 50% 0 repeat-x;
+ overflow-x: hidden;
}
hr
@@ -191,7 +192,7 @@ h4
.good
{
- color: #4f7529;
+ color: #79B33F; /*#4f7529;*/
font-weight: bold;
}
@@ -220,7 +221,7 @@ h4
.notice
{
position: relative;
- background: url(uiNoticeBackground.jpg) 50% 50% no-repeat;
+ background: url(uiNoticeBackground.jpg) 50% 50% repeat;
color: #15345A;
font-size: 12px;
font-style: italic;
@@ -251,6 +252,7 @@ div.notice
.item
{
width: 100%;
+ min-height: 22px;
clear: both;
}
@@ -261,6 +263,10 @@ div.notice
color: #e9c183;
}
+.itemContentFull
+{
+ float: left;
+}
.itemContent
{
float: left;
@@ -269,7 +275,7 @@ div.notice
.itemContentSmall
{
float: left;
- width: 33%;
+ width: 30%;
}
.statusDisplay
diff --git a/nano/images/uiBackground.png b/nano/images/uiBackground.png
index 32aa9dd7f63..8bf75150fa8 100644
Binary files a/nano/images/uiBackground.png and b/nano/images/uiBackground.png differ
diff --git a/nano/images/uiBackground.xcf b/nano/images/uiBackground.xcf
index d20db24ff89..56454dfad0f 100644
Binary files a/nano/images/uiBackground.xcf and b/nano/images/uiBackground.xcf differ
diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl
index 446ba31a145..b57829f397f 100644
--- a/nano/templates/apc.tmpl
+++ b/nano/templates/apc.tmpl
@@ -1,26 +1,38 @@
- {^{if locked}}
- Swipe ID card to unlock interface
+ {^{if siliconUser}}
+
+ Interface Lock:
+
+
+ {^{:~link('Engaged', 'locked', {'toggleaccess' : 1}, locked ? 'selected' : null)}}{^{:~link('Disengaged', 'unlocked', {'toggleaccess' : 1}, malfStatus >= 2 ? 'linkOff' : (locked ? null : 'selected'))}}
+
+
{{else}}
- Swipe ID card to lock interface
+ {^{if locked}}
+ Swipe an ID card to unlock this interface.
+ {{else}}
+ Swipe an ID card to lock this interface.
+ {{/if}}
{{/if}}
-
Status
+
+
+
Power Status
Main Breaker:
- {^{if locked}}
+ {^{if locked && !siliconUser}}
{^{if isOperating}}
On
{{else}}
Off
{{/if}}
{{else}}
- {^{:~link('On', {'breaker' : 1}, isOperating ? 'selected' : null)}}{^{:~link('Off', {'breaker' : 1}, isOperating ? null : 'selected')}}
+ {^{:~link('On', 'power', {'breaker' : 1}, isOperating ? 'selected' : null)}}{^{:~link('Off', 'close', {'breaker' : 1}, isOperating ? null : 'selected')}}
{{/if}}
@@ -44,13 +56,16 @@
Power Cell:
-
- {^{if powerCellStatus == null}}
- Not connected.
- {{else}}
- {^{:powerCellStatus}}%
- {{/if}}
-
+ {^{if powerCellStatus == null}}
+
+ Power cell removed.
+
+ {{else}}
+
+ {^{:~round(powerCellStatus*10)/10}}%
+
+ {^{:~displayBar(powerCellStatus, 0, 100, powerCellStatus >= 50 ? 'good' : powerCellStatus >= 25 ? 'average' : 'bad')}}
+ {{/if}}
{^{if powerCellStatus != null}}
@@ -59,83 +74,106 @@
Charge Mode:
- {^{if locked}}
+ {^{if locked && !siliconUser}}
{^{if chargeMode}}
Auto
{{else}}
Off
{{/if}}
{{else}}
- {^{:~link('Auto', {'cmode' : 1}, chargeMode ? 'selected' : null)}}{^{:~link('Off', {'cmode' : 1}, chargeMode ? null : 'selected')}}
+ {^{:~link('Auto', 'refresh', {'cmode' : 1}, chargeMode ? 'selected' : null)}}{^{:~link('Off', 'close', {'cmode' : 1}, chargeMode ? null : 'selected')}}
{{/if}}
{^{if chargingStatus > 1}}
- (Fully Charged)
+ [Fully Charged]
{{else chargingStatus == 1}}
- (Charging)
+ [Charging]
{{else}}
- (Not Charging)
+ [Not Charging]
{{/if}}
{{/if}}
+
Power Channels
{^{for powerChannels}}
- {^{:title}}
+ {^{:title}}:
-
+
{^{:powerLoad}} W
-
- {^{if !~root.locked}}
- {^{:~link('Auto', topicParams.auto, (status == 1 || status == 3) ? 'selected' : null)}}
- {^{:~link('On', topicParams.on, (status == 2) ? 'selected' : null)}}
- {^{:~link('Off', topicParams.off, (status == 0) ? 'selected' : null)}}
- {{/if}}
+
+
{^{if status <= 1}}
Off
{{else status >= 2}}
On
{{/if}}
- {^{if ~root.locked}}
- {^{if status == 1 || status == 3}}
- (Auto)
- {{else}}
- (Manual)
- {{/if}}
- {{/if}}
+ {^{if status == 1 || status == 3}}
+ [Auto]
+ {{else}}
+ [Manual]
+ {{/if}}
+ {^{if !~root.locked || ~root.siliconUser}}
+
+ {^{:~link('Auto', 'refresh', topicParams.auto, (status == 1 || status == 3) ? 'selected' : null)}}
+ {^{:~link('On', 'power', topicParams.on, (status == 2) ? 'selected' : null)}}
+ {^{:~link('Off', 'close', topicParams.off, (status == 0) ? 'selected' : null)}}
+
+ {{/if}}
{{/for}}
-
-
-
+
Total Load:
-
- {{:totalLoad}} W
+
+ {^{:totalLoad}} W
+
+
Cover Lock:
- {^{if locked}}
+ {^{if locked && !siliconUser}}
{^{if coverLocked}}
Engaged
{{else}}
Disengaged
{{/if}}
{{else}}
- {^{:~link('Engaged', {'lock' : 1}, coverLocked ? 'selected' : null)}}{^{:~link('Disengaged', {'lock' : 1}, coverLocked ? null : 'selected')}}
+ {^{:~link('Engaged', 'locked', {'lock' : 1}, coverLocked ? 'selected' : null)}}{^{:~link('Disengaged', 'unlocked', {'lock' : 1}, coverLocked ? null : 'selected')}}
{{/if}}
-
\ No newline at end of file
+
+
+
+{^{if siliconUser}}
+
System Overrides
+
+
+ {^{:~link('Overload Lighting Circuit', 'lightbulb', {'overload' : 1})}}
+ {^{if malfStatus == 1}}
+ {^{:~link('Override Programming', 'script', {'malfhack' : 1})}}
+ {{else malfStatus == 2}}
+ {^{:~link('Shunt Core Processes', 'arrowreturn-1-s', {'occupyapc' : 1})}}
+ {{else malfStatus == 3}}
+ {^{:~link('Return to Main Core', 'arrowreturn-1-w', {'deoccupyapc' : 1})}}
+ {{else malfStatus == 4}}
+ {^{:~link('Shunt Core Processes', 'arrowreturn-1-s', {'occupyapc' : 1}, 'linkOff')}}
+ {{/if}}
+
+{{/if}}
+
+
+
\ No newline at end of file