Scopes updates all merged and stuff

A lot of these will probably get edited again
This commit is contained in:
SoundScopes
2015-05-14 21:02:12 +01:00
parent 93e54b408b
commit ff68c9e1f3
61 changed files with 1914 additions and 1034 deletions
@@ -119,6 +119,7 @@
icon = 'icons/misc/beach.dmi'
icon_state = "water"
icon_spawn_state = "water"
footstep_sound = "waterstep"
/turf/unsimulated/jungle/water/New()
..()
+7
View File
@@ -128,6 +128,13 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
for(var/atom/A in loc)
A.fire_act(air_contents, air_contents.temperature, air_contents.volume)
//Recheck for turf as it could change since the last check
if(!istype(my_tile) || !my_tile.zone)
if(my_tile.fire == src)
my_tile.fire = null
RemoveFire()
return 1
//spread
for(var/direction in cardinal)
var/turf/simulated/enemy_tile = get_step(my_tile, direction)
+28 -1
View File
@@ -9,6 +9,12 @@
src:Topic(href, href_list)
return null
/proc/get_area_master(const/O)
var/area/A = get_area(O)
if (isarea(A))
return A.master
/proc/get_area(O)
var/atom/location = O
var/i
@@ -46,6 +52,21 @@
return heard
/proc/isStationLevel(var/level)
return level in config.station_levels
///proc/isNotStationLevel(var/level) //Wait how dumb are you people
// return !isStationLevel(level)
/proc/isPlayerLevel(var/level)
return level in config.player_levels
/proc/isAdminLevel(var/level)
return level in config.admin_levels
///proc/isNotAdminLevel(var/level) //Wait how dumb are you people
// return !isAdminLevel(level)
//Magic constants obtained by using linear regression on right-angled triangles of sides 0<x<1, 0<y<1
@@ -474,4 +495,10 @@ datum/projectile_data
C.images += I
sleep(duration)
for(var/client/C in show_to)
C.images -= I
C.images -= I
/proc/MinutesToTicks(var/minutes as num)
return minutes * 60 * 10
/proc/SecondsToTicks(var/seconds)
return seconds * 10
+36 -14
View File
@@ -36,6 +36,12 @@
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
if(modifiers["shift"] && modifiers["alt"])
AltShiftClickOn(A)
return
if(modifiers["middle"])
MiddleClickOn(A)
return
@@ -86,7 +92,10 @@
than anything else in the game, atoms have separate procs
for AI shift, ctrl, and alt clicking.
*/
/mob/living/silicon/ai/CtrlShiftClickOn(var/atom/A)
A.AICtrlShiftClick(src)
/mob/living/silicon/ai/AltShiftClickOn(var/atom/A)
A.AIAltShiftClick(src)
/mob/living/silicon/ai/ShiftClickOn(var/atom/A)
A.AIShiftClick(src)
/mob/living/silicon/ai/CtrlClickOn(var/atom/A)
@@ -101,14 +110,29 @@
I have no idea why it was in atoms.dm instead of respective files.
*/
/atom/proc/AICtrlShiftClick(var/mob/user) // Examines
if(user.client)
examine()
return
/atom/proc/AIAltShiftClick()
return
/obj/machinery/door/airlock/AIAltShiftClick() // Sets/Unsets Emergency Access Override
if(density)
Topic(src, list("src"= "\ref[src]", "command"="emergency", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
Topic(src, list("src"= "\ref[src]", "command"="emergency", "activate" = "0"), 1)
return
/atom/proc/AIShiftClick()
return
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
if(density)
Topic("aiEnable=7", list("aiEnable"="7"), 1) // 1 meaning no window (consistency!)
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
Topic("aiDisable=7", list("aiDisable"="7"), 1)
Topic(src, list("src"= "\ref[src]", "command"="open", "activate" = "0"), 1)
return
/atom/proc/AICtrlClick()
@@ -116,41 +140,39 @@
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
if(locked)
Topic("aiEnable=4", list("aiEnable"="4"), 1)// 1 meaning no window (consistency!)
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
else
Topic("aiDisable=4", list("aiDisable"="4"), 1)
Topic(src, list("src"= "\ref[src]", "command"="bolts", "activate" = "1"), 1)
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
src.enabled = !src.enabled
src.updateTurrets()
Topic(src, list("src"= "\ref[src]", "command"="enable", "value"="[!enabled]"), 1)
/atom/proc/AIAltClick(var/atom/A)
AltClick(A)
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
if(!secondsElectrified)
if(!electrified_until)
// permanent shock
Topic("aiEnable=6", list("aiEnable"="6"), 1) // 1 meaning no window (consistency!)
Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
Topic("aiDisable=5", list("aiDisable"="5"), 1)
Topic(src, list("src"= "\ref[src]", "command"="electrify_permanently", "activate" = "0"), 1)
return
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
src.lethal = !src.lethal
src.updateTurrets()
Topic(src, list("src"= "\ref[src]", "command"="lethal", "value"="[!lethal]"), 1)
/atom/proc/AIMiddleClick()
return
/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
if(!src.lights)
Topic("aiEnable=10", list("aiEnable"="10"), 1) // 1 meaning no window (consistency!)
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
else
Topic("aiDisable=10", list("aiDisable"="10"), 1)
Topic(src, list("src"= "\ref[src]", "command"="lights", "activate" = "0"), 1)
return
//
+44 -15
View File
@@ -18,6 +18,7 @@
/atom/Click(location,control,params)
if(src)
usr.ClickOn(src, params)
/atom/DblClick(location,control,params)
if(src)
usr.DblClickOn(src,params)
@@ -45,6 +46,12 @@
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
if(modifiers["shift"] && modifiers["alt"])
AltShiftClickOn(A)
return
if(modifiers["middle"])
MiddleClickOn(A)
return
@@ -73,6 +80,7 @@
return M.click_action(A,src)
if(restrained())
changeNext_move(CLICK_CD_HANDCUFFED)
RestrainedClickOn(A)
return
@@ -80,16 +88,11 @@
throw_item(A)
return
if(!istype(A,/obj/item/weapon/gun) && !isturf(A) && !istype(A,/obj/screen))
last_target_click = world.time
var/obj/item/W = get_active_hand()
if(W == A)
next_move = world.time + 6
if(W.flags&USEDELAY)
next_move += 5
W.attack_self(src)
changeNext_move(CLICK_CD_MELEE)
if(hand)
update_inv_l_hand(0)
else
@@ -125,18 +128,16 @@
// Allows you to click on a box's contents, if that box is on the ground, but no deeper than that
sdepth = A.storage_depth_turf()
if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1))
next_move = world.time + 10
if(A.Adjacent(src)) // see adjacent.dm
if(W)
if(W.flags&USEDELAY)
next_move += 5
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
var/resolved = A.attackby(W,src)
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example, params)
var/resolved = A.attackby(W,src,params)
changeNext_move(CLICK_CD_MELEE)
if(!resolved && A && W)
W.afterattack(A,src,1,params) // 1: clicking something Adjacent
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A, 1)
return
else // non-adjacent click
@@ -147,9 +148,12 @@
return
/mob/proc/changeNext_move(num)
next_move = world.time + num
// Default behavior: ignore double clicks, consider them normal clicks instead
/mob/proc/DblClickOn(var/atom/A, var/params)
ClickOn(A,params)
return
/*
@@ -163,6 +167,8 @@
in human click code to allow glove touches only at melee range.
*/
/mob/proc/UnarmedAttack(var/atom/A, var/proximity_flag)
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
return
/*
@@ -190,6 +196,11 @@
else
return
A.attack_tk(src)
return
else
if(TK in mutations)
A.attack_tk(src)
/*
Restrained ClickOn
@@ -263,6 +274,24 @@
/mob/proc/TurfAdjacent(var/turf/T)
return T.AdjacentQuick(src)
/*
Control+Shift/Alt+Shift click
+ Unused except for AI
+*/
/mob/proc/CtrlShiftClickOn(var/atom/A)
A.CtrlShiftClick(src)
return
/atom/proc/CtrlShiftClick(var/mob/user)
return
/mob/proc/AltShiftClickOn(var/atom/A)
A.AltShiftClick(src)
return
/atom/proc/AltShiftClick(var/mob/user)
return
/*
Misc helpers
@@ -273,7 +302,7 @@
return
/mob/living/LaserEyes(atom/A)
next_move = world.time + 6
changeNext_move(CLICK_CD_RANGE)
var/turf/T = get_turf(src)
var/turf/U = get_turf(A)
+20 -5
View File
@@ -16,6 +16,12 @@
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
return
if(modifiers["shift"] && modifiers["alt"])
AltShiftClickOn(A)
return
if(modifiers["middle"])
MiddleClickOn(A)
return
@@ -104,11 +110,6 @@
return
return
//Middle click cycles through selected modules.
/mob/living/silicon/robot/MiddleClickOn(var/atom/A)
cycle_modules()
return
/*
As with AI, these are not used in click code,
because the code for robots is specific, not generic.
@@ -125,3 +126,17 @@
/atom/proc/attack_robot(mob/user as mob)
attack_ai(user)
return
/mob/living/silicon/robot/MiddleClickOn(var/atom/A)
cycle_modules()
/mob/living/silicon/robot/CtrlShiftClickOn(var/atom/A)
A.AICtrlShiftClick(src)
/mob/living/silicon/robot/AltShiftClickOn(var/atom/A)
A.AIAltShiftClick(src)
/mob/living/silicon/robot/ShiftClickOn(var/atom/A)
A.AIShiftClick(src)
/mob/living/silicon/robot/CtrlClickOn(var/atom/A)
A.AICtrlClick(src)
/mob/living/silicon/robot/AltClickOn(var/atom/A)
A.AIAltClick(src)
+5
View File
@@ -152,6 +152,11 @@
var/use_overmap = 0
var/invasive_directives = 0
var/list/station_levels = list(1) // Defines which Z-levels the station exists on.
var/list/admin_levels= list(2) // Defines which Z-levels which are for admin functionality, for example including such areas as Central Command and the Syndicate Shuttle
var/list/contact_levels = list(1, 5) // Defines which Z-levels which, for example, a Code Red announcement may affect
var/list/player_levels = list(1, 3, 4, 5, 6) // Defines all Z-levels a character can typically reach
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
+3 -7
View File
@@ -277,13 +277,9 @@ datum/controller/vote
log_vote(text)
world << "<font color='purple'><b>[text]</b>\nType vote to place your votes.\nYou have [config.vote_period/10] seconds to vote.</font>"
switch(vote_type)
if("crew_transfer")
world << sound('sound/ambience/alarm4.ogg')
if("gamemode")
world << sound('sound/ambience/alarm4.ogg')
if("custom")
world << sound('sound/ambience/alarm4.ogg')
for(var/client/C in clients)
if(C.prefs.asfx_togs & ASFX_VOTE) //Personal mute
C << sound('sound/effects/vote.ogg')
if(mode == "gamemode" && going)
going = 0
world << "<font color='red'><b>Round start has been delayed.</b></font>"
+174
View File
@@ -0,0 +1,174 @@
// Wires for airlocks
/datum/wires/airlock/secure
random = 1
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
wire_count = 12
window_y = 570
var/const/AIRLOCK_WIRE_IDSCAN = 1
var/const/AIRLOCK_WIRE_MAIN_POWER1 = 2
var/const/AIRLOCK_WIRE_MAIN_POWER2 = 4
var/const/AIRLOCK_WIRE_DOOR_BOLTS = 8
var/const/AIRLOCK_WIRE_BACKUP_POWER1 = 16
var/const/AIRLOCK_WIRE_BACKUP_POWER2 = 32
var/const/AIRLOCK_WIRE_OPEN_DOOR = 64
var/const/AIRLOCK_WIRE_AI_CONTROL = 128
var/const/AIRLOCK_WIRE_ELECTRIFY = 256
var/const/AIRLOCK_WIRE_SAFETY = 512
var/const/AIRLOCK_WIRE_SPEED = 1024
var/const/AIRLOCK_WIRE_LIGHT = 2048
/datum/wires/airlock/CanUse(var/mob/living/L)
var/obj/machinery/door/airlock/A = holder
if(!istype(L, /mob/living/silicon))
if(A.isElectrified())
if(A.shock(L, 100))
return 0
if(A.p_open)
return 1
return 0
/datum/wires/airlock/GetInteractWindow()
var/obj/machinery/door/airlock/A = holder
var/haspower = A.arePowerSystemsOn()
. += ..()
. += text("<br>\n[]<br>\n[]<br>\n[]<br>\n[]<br>\n[]<br>\n[]<br>\n[]",
(A.locked ? "The door bolts have fallen!" : "The door bolts look up."),
((A.lights && haspower) ? "The door bolt lights are on." : "The door bolt lights are off!"),
((haspower) ? "The test light is on." : "The test light is off!"),
((A.aiControlDisabled==0 && !A.emagged && haspower) ? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off."),
((A.safe==0 && haspower) ? "The 'Check Wiring' light is on." : "The 'Check Wiring' light is off."),
((A.normalspeed==0 && haspower) ? "The 'Check Timing Mechanism' light is on." : "The 'Check Timing Mechanism' light is off."),
((A.emergency && haspower) ? "The emergency lights are on." : "The emergency lights are off."))
/datum/wires/airlock/UpdateCut(var/index, var/mended)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(AIRLOCK_WIRE_IDSCAN)
A.aiDisabledIdScanner = !mended
if(AIRLOCK_WIRE_MAIN_POWER1, AIRLOCK_WIRE_MAIN_POWER2)
if(!mended)
//Cutting either one disables the main door power, but unless backup power is also cut, the backup power re-powers the door in 10 seconds. While unpowered, the door may be crowbarred open, but bolts-raising will not work. Cutting these wires may electocute the user.
A.loseMainPower()
A.shock(usr, 50)
else
A.regainMainPower()
A.shock(usr, 50)
if(AIRLOCK_WIRE_BACKUP_POWER1, AIRLOCK_WIRE_BACKUP_POWER2)
if(!mended)
//Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user.
A.loseBackupPower()
A.shock(usr, 50)
else
A.regainBackupPower()
A.shock(usr, 50)
if(AIRLOCK_WIRE_DOOR_BOLTS)
if(!mended)
//Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present)
A.lock(1)
A.update_icon()
if(AIRLOCK_WIRE_AI_CONTROL)
if(!mended)
//one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all.
//aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
else
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(AIRLOCK_WIRE_ELECTRIFY)
if(!mended)
//Cutting this wire electrifies the door, so that the next person to touch the door without insulated gloves gets electrocuted.
A.electrify(-1)
else
A.electrify(0)
return // Don't update the dialog.
if (AIRLOCK_WIRE_SAFETY)
A.safe = mended
if(AIRLOCK_WIRE_SPEED)
A.autoclose = mended
if(mended)
if(!A.density)
A.close()
if(AIRLOCK_WIRE_LIGHT)
A.lights = mended
A.update_icon()
/datum/wires/airlock/UpdatePulsed(var/index)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(AIRLOCK_WIRE_IDSCAN)
//Sending a pulse through flashes the red light on the door (if the door has power).
if(A.arePowerSystemsOn() && A.density)
A.do_animate("deny")
if(A.emergency)
A.emergency = 0
A.update_icon()
if(AIRLOCK_WIRE_MAIN_POWER1 || AIRLOCK_WIRE_MAIN_POWER2)
//Sending a pulse through either one causes a breaker to trip, disabling the door for 10 seconds if backup power is connected, or 1 minute if not (or until backup power comes back on, whichever is shorter).
A.loseMainPower()
if(AIRLOCK_WIRE_DOOR_BOLTS)
//one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not),
//raises them if they are down (only if power's on)
if(!A.locked)
A.lock()
else
A.unlock()
if(AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2)
//two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter).
A.loseBackupPower()
if(AIRLOCK_WIRE_AI_CONTROL)
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
spawn(10)
if(A)
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(AIRLOCK_WIRE_ELECTRIFY)
//one wire for electrifying the door. Sending a pulse through this electrifies the door for 30 seconds.
A.electrify(30)
if(AIRLOCK_WIRE_OPEN_DOOR)
//tries to open the door without ID
//will succeed only if the ID wire is cut or the door requires no access and it's not emagged
if(A.emagged) return
if(!A.requiresID() || A.check_access(null))
if(A.density) A.open()
else A.close()
if(AIRLOCK_WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
A.close()
if(AIRLOCK_WIRE_SPEED)
A.normalspeed = !A.normalspeed
if(AIRLOCK_WIRE_LIGHT)
A.lights = !A.lights
A.update_icon()
+297
View File
@@ -0,0 +1,297 @@
// Wire datums. Created by Giacomand.
// Was created to replace a horrible case of copy and pasted code with no care for maintability.
// Goodbye Door wires, Cyborg wires, Vending Machine wires, Autolathe wires
// Protolathe wires, APC wires and Camera wires!
#define MAX_FLAG 65535
var/list/same_wires = list()
// 12 colours, if you're adding more than 12 wires then add more colours here
var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown", "gold", "gray", "cyan", "navy", "purple", "pink")
/datum/wires
var/random = 0 // Will the wires be different for every single instance.
var/atom/holder = null // The holder
var/holder_type = null // The holder type; used to make sure that the holder is the correct type.
var/wire_count = 0 // Max is 16
var/wires_status = 0 // BITFLAG OF WIRES
var/list/wires = list()
var/list/signallers = list()
var/table_options = " align='center'"
var/row_options1 = " width='80px'"
var/row_options2 = " width='260px'"
var/window_x = 370
var/window_y = 470
/datum/wires/New(var/atom/holder)
..()
src.holder = holder
if(!istype(holder, holder_type))
CRASH("Our holder is null/the wrong type!")
return
// Generate new wires
if(random)
GenerateWires()
// Get the same wires
else
// We don't have any wires to copy yet, generate some and then copy it.
if(!same_wires[holder_type])
GenerateWires()
same_wires[holder_type] = src.wires.Copy()
else
var/list/wires = same_wires[holder_type]
src.wires = wires // Reference the wires list.
/datum/wires/proc/GenerateWires()
var/list/colours_to_pick = wireColours.Copy() // Get a copy, not a reference.
var/list/indexes_to_pick = list()
//Generate our indexes
for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
indexes_to_pick += i
colours_to_pick.len = wire_count // Downsize it to our specifications.
while(colours_to_pick.len && indexes_to_pick.len)
// Pick and remove a colour
var/colour = pick_n_take(colours_to_pick)
// Pick and remove an index
var/index = pick_n_take(indexes_to_pick)
src.wires[colour] = index
//wires = shuffle(wires)
/datum/wires/proc/Interact(var/mob/living/user)
var/html = null
if(holder && CanUse(user))
html = GetInteractWindow()
if(html)
user.set_machine(holder)
else
user.unset_machine()
// No content means no window.
user << browse(null, "window=wires")
return
var/datum/browser/popup = new(user, "wires", holder.name, window_x, window_y)
popup.set_content(html)
popup.set_title_image(user.browse_rsc_icon(holder.icon, holder.icon_state))
popup.open()
/datum/wires/proc/GetInteractWindow()
var/html = \
{" <style>
.colour_display { float: left;
width: 10px;
height: 10px;
margin: 5px;}
</style>
<div class='block'>
<h3>Exposed Wires</h3>
<table[table_options]>"}
for(var/colour in wires)
html += "<tr>"
html += "<td[row_options1]><span class='colour_display' style='background-color:[colour]'></span>[capitalize(colour)]</td>"
html += "<td[row_options2]>"
html += "<A href='?src=\ref[src];action=1;cut=[colour]'>[IsColourCut(colour) ? "Mend" : "Cut"]</A>"
html += " <A href='?src=\ref[src];action=1;pulse=[colour]'>Pulse</A>"
html += " <A href='?src=\ref[src];action=1;attach=[colour]'>[IsAttached(colour) ? "Detach" : "Attach"] Signaller</A></td></tr>"
html += "</table>"
html += "</div>"
return html
/datum/wires/Topic(href, href_list)
..()
if(in_range(holder, usr) && isliving(usr))
var/mob/living/L = usr
if(CanUse(L) && href_list["action"])
var/obj/item/I = L.get_active_hand()
holder.add_hiddenprint(L)
if(href_list["cut"]) // Toggles the cut/mend status
if(istype(I, /obj/item/weapon/wirecutters))
var/colour = href_list["cut"]
CutWireColour(colour)
else
L << "<span class='error'>You need wirecutters!</span>"
else if(href_list["pulse"])
if(istype(I, /obj/item/device/multitool))
var/colour = href_list["pulse"]
PulseColour(colour)
else
L << "<span class='error'>You need a multitool!</span>"
else if(href_list["attach"])
var/colour = href_list["attach"]
// Detach
if(IsAttached(colour))
var/obj/item/O = Detach(colour)
if(O)
L.put_in_hands(O)
// Attach
else
if(istype(I, /obj/item/device/assembly/signaler))
L.drop_item()
Attach(colour, I)
else
L << "<span class='error'>You need a remote signaller!</span>"
// Update Window
Interact(usr)
if(href_list["close"])
usr << browse(null, "window=wires")
usr.unset_machine(holder)
//
// Overridable Procs
//
// Called when wires cut/mended.
/datum/wires/proc/UpdateCut(var/index, var/mended)
return
// Called when wire pulsed. Add code here.
/datum/wires/proc/UpdatePulsed(var/index)
return
/datum/wires/proc/CanUse(var/mob/living/L)
return 1
// Example of use:
/*
var/const/BOLTED= 1
var/const/SHOCKED = 2
var/const/SAFETY = 4
var/const/POWER = 8
/datum/wires/door/UpdateCut(var/index, var/mended)
var/obj/machinery/door/airlock/A = holder
switch(index)
if(BOLTED)
if(!mended)
A.bolt()
if(SHOCKED)
A.shock()
if(SAFETY )
A.safety()
*/
//
// Helper Procs
//
/datum/wires/proc/PulseColour(var/colour)
PulseIndex(GetIndex(colour))
/datum/wires/proc/PulseIndex(var/index)
if(IsIndexCut(index))
return
UpdatePulsed(index)
/datum/wires/proc/GetIndex(var/colour)
if(wires[colour])
var/index = wires[colour]
return index
else
CRASH("[colour] is not a key in wires.")
//
// Is Index/Colour Cut procs
//
/datum/wires/proc/IsColourCut(var/colour)
var/index = GetIndex(colour)
return IsIndexCut(index)
/datum/wires/proc/IsIndexCut(var/index)
return (index & wires_status)
//
// Signaller Procs
//
/datum/wires/proc/IsAttached(var/colour)
if(signallers[colour])
return 1
return 0
/datum/wires/proc/GetAttached(var/colour)
if(signallers[colour])
return signallers[colour]
return null
/datum/wires/proc/Attach(var/colour, var/obj/item/device/assembly/signaler/S)
if(colour && S)
if(!IsAttached(colour))
signallers[colour] = S
S.loc = holder
S.connected = src
return S
/datum/wires/proc/Detach(var/colour)
if(colour)
var/obj/item/device/assembly/signaler/S = GetAttached(colour)
if(S)
signallers -= colour
S.connected = null
S.loc = holder.loc
return S
/datum/wires/proc/Pulse(var/obj/item/device/assembly/signaler/S)
for(var/colour in signallers)
if(S == signallers[colour])
PulseColour(colour)
break
//
// Cut Wire Colour/Index procs
//
/datum/wires/proc/CutWireColour(var/colour)
var/index = GetIndex(colour)
CutWireIndex(index)
/datum/wires/proc/CutWireIndex(var/index)
if(IsIndexCut(index))
wires_status &= ~index
UpdateCut(index, 1)
else
wires_status |= index
UpdateCut(index, 0)
/datum/wires/proc/RandomCut()
var/r = rand(1, wires.len)
CutWireIndex(r)
/datum/wires/proc/CutAll()
for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
CutWireIndex(i)
/datum/wires/proc/IsAllCut()
if(wires_status == (1 << wire_count) - 1)
return 1
return 0
//
//Shuffle and Mend
//
/datum/wires/proc/Shuffle()
wires_status = 0
GenerateWires()
+1 -1
View File
@@ -315,7 +315,7 @@
L.lastarea = newarea
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(!(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return
if(!(L && L.client && (L.client.prefs.asfx_togs & ASFX_AMBIENCE))) return
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
+1
View File
@@ -143,6 +143,7 @@ Stealth and Camouflage Items;
/obj/item/device/chameleon:4:Chameleon-Projector;
Whitespace:Seperator;
Devices and Tools;
/obj/item/shoe_cover:1:Silent Step Fabric;
/obj/item/weapon/card/emag:3:Cryptographic Sequencer;
/obj/item/weapon/storage/toolbox/syndicate:1:Fully Loaded Toolbox;
/obj/item/weapon/storage/box/syndie_kit/space:3:Space Suit;
+1
View File
@@ -58,6 +58,7 @@ Stealth and Camouflage Items;
/obj/item/device/chameleon:4:Chameleon-Projector;
Whitespace:Seperator;
Devices and Tools;
/obj/item/shoe_cover:1:Silent Step Fabric;
/obj/item/weapon/card/emag:3:Cryptographic Sequencer;
/obj/item/weapon/storage/toolbox/syndicate:1:Fully Loaded Toolbox;
/obj/item/weapon/storage/box/syndie_kit/space:3:Space Suit;
@@ -386,6 +386,7 @@
name = "Lush Grass"
icon_state = "grass1"
floor_tile = new/obj/item/stack/tile/grass
footstep_sound = "grassstep"
New()
floor_tile.New() //I guess New() isn't run on objects spawned without the definition of a turf to house them, ah well.
@@ -406,6 +407,7 @@
name = "desert sand"
desc = "Uncomfortably gritty for a hologram."
icon_state = "asteroid"
footstep_sound = "gravelstep"
/turf/simulated/floor/holofloor/desert/New()
..()
+5 -96
View File
@@ -6,11 +6,10 @@
idle_power_usage = 250
active_power_usage = 500
circuit = "/obj/item/weapon/circuitboard/crew"
var/list/tracked = list( )
var/obj/nano_module/crew_monitor/crew_monitor
/obj/machinery/computer/crew/New()
tracked = list()
crew_monitor = new(src)
..()
@@ -25,6 +24,8 @@
return
ui_interact(user)
/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
crew_monitor.ui_interact(user, ui_key, ui, force_open)
/obj/machinery/computer/crew/update_icon()
@@ -38,97 +39,5 @@
icon_state = initial(icon_state)
stat &= ~NOPOWER
/obj/machinery/computer/crew/Topic(href, href_list)
if(..()) return
if (src.z > 6)
usr << "\red <b>Unable to establish a connection</b>: \black You're too far away from the station!"
return 0
if( href_list["close"] )
var/mob/user = usr
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
usr.unset_machine()
ui.close()
return 0
if(href_list["update"])
src.updateDialog()
return 1
/obj/machinery/computer/crew/interact(mob/user)
ui_interact(user)
/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
user.set_machine(src)
src.scan()
var/data[0]
var/list/crewmembers = list()
for(var/obj/item/clothing/under/C in src.tracked)
var/turf/pos = get_turf(C)
if((C) && (C.has_sensor) && (pos) && (pos.z == src.z) && C.sensor_mode)
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
var/list/crewmemberData = list()
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["dead"] = H.stat > 1
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
crewmemberData["name"] = "Unknown"
crewmemberData["rank"] = "Unknown"
if(H.wear_id && istype(H.wear_id, /obj/item/weapon/card/id) )
var/obj/item/weapon/card/id/I = H.wear_id
crewmemberData["name"] = I.name
crewmemberData["rank"] = I.rank
else if(H.wear_id && istype(H.wear_id, /obj/item/device/pda) )
var/obj/item/device/pda/P = H.wear_id
crewmemberData["name"] = (P.id ? P.id.name : "Unknown")
crewmemberData["rank"] = (P.id ? P.id.rank : "Unknown")
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
// Works around list += list2 merging lists; it's not pretty but it works
crewmembers += "temporary item"
crewmembers[crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name")
data["crewmembers"] = crewmembers
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
ui.set_initial_data(data)
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
/obj/machinery/computer/crew/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
tracked |= C
return 1
crew_monitor.ui_interact(user)
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -22,6 +22,7 @@
var/glass = 0
var/normalspeed = 1
var/heat_proof = 0 // For glass airlocks/opacity firedoors
var/emergency = 0
var/air_properties_vary_with_direction = 0
//Multi-tile doors
@@ -72,7 +73,7 @@
if(istype(AM, /obj/machinery/bot))
var/obj/machinery/bot/bot = AM
if(src.check_access(bot.botcard))
if(src.check_access(bot.botcard) || emergency == 1)
if(density)
open()
return
@@ -80,7 +81,7 @@
if(istype(AM, /obj/mecha))
var/obj/mecha/mecha = AM
if(density)
if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access)))
if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access) || emergency == 1))
open()
else
flick("door_deny", src)
@@ -112,8 +113,10 @@
user = null
if(density)
if(allowed(user)) open()
else flick("door_deny", src)
if(allowed(user) || src.emergency == 1)
open()
else
flick("door_deny", src)
return
/obj/machinery/door/meteorhit(obj/M as obj)
@@ -152,7 +155,7 @@
open()
operating = -1
return 1
if(src.allowed(user))
if(src.allowed(user) || src.emergency == 1)
if(src.density)
open()
else
+18
View File
@@ -142,6 +142,24 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
return 1
/obj/machinery/hologram/holopad/proc/face_atom(var/atom/A)
if( !hologram || !A || !hologram.x || !hologram.y || !A.x || !A.y ) return
var/dx = A.x - hologram.x
var/dy = A.y - hologram.y
if(!dx && !dy) // Wall items are graphically shifted but on the floor
if(A.pixel_y > 16) hologram.dir = NORTH
else if(A.pixel_y < -16)hologram.dir = SOUTH
else if(A.pixel_x > 16) hologram.dir = EAST
else if(A.pixel_x < -16)hologram.dir = WEST
return
if(abs(dx) < abs(dy))
if(dy > 0) hologram.dir = NORTH
else hologram.dir = SOUTH
else
if(dx > 0) hologram.dir = EAST
else hologram.dir = WEST
/*
* Hologram
*/
+29 -35
View File
@@ -110,18 +110,43 @@ Class Procs:
var/uid
var/manual = 0
var/global/gl_uid = 1
var/area/myArea
var/interact_offline = 0 // Can the machine be interacted with while de-powered.
/obj/machinery/New()
..()
machines += src
addAtProcessing()
return ..()
/obj/machinery/Del()
machines -= src
if (src in machines)
removeAtProcessing()
..()
/obj/machinery/proc/addAtProcessing()
if (use_power)
myArea = get_area_master(src)
machines += src
/obj/machinery/proc/removeAtProcessing()
if (myArea)
myArea = null
machines -= src
/obj/machinery/process()//If you dont use process or power why are you here
return PROCESS_KILL
/obj/machinery/CanUseTopic(var/mob/user, var/be_close)
if(!interact_offline && (stat & (NOPOWER|BROKEN)))
return STATUS_CLOSE
return ..()
/obj/machinery/CouldUseTopic(var/mob/user)
..()
user.set_machine(src)
/obj/machinery/CouldNotUseTopic(var/mob/user)
usr.unset_machine()
/obj/machinery/emp_act(severity)
if(use_power && stat == 0)
use_power(7500/severity)
@@ -187,37 +212,6 @@ Class Procs:
/obj/machinery/proc/inoperable(var/additional_flags = 0)
return (stat & (NOPOWER|BROKEN|additional_flags))
/obj/machinery/Topic(href, href_list)
..()
if(inoperable())
return 1
if(usr.restrained() || usr.lying || usr.stat)
return 1
if ( ! (istype(usr, /mob/living/carbon/human) || \
istype(usr, /mob/living/silicon) || \
istype(usr, /mob/living/carbon/monkey)) )
usr << "\red You don't have the dexterity to do this!"
return 1
var/norange = 0
if(istype(usr, /mob/living/carbon/human))
var/mob/living/carbon/human/H = usr
if(istype(H.l_hand, /obj/item/tk_grab))
norange = 1
else if(istype(H.r_hand, /obj/item/tk_grab))
norange = 1
if(!norange)
if ((!in_range(src, usr) || !istype(src.loc, /turf)) && !istype(usr, /mob/living/silicon))
return 1
src.add_fingerprint(usr)
var/area/A = get_area(src)
A.master.powerupdate = 1
return 0
/obj/machinery/attack_ai(mob/user as mob)
if(isrobot(user))
// For some reason attack_robot doesn't work
@@ -231,7 +225,7 @@ Class Procs:
return src.attack_hand(user)
/obj/machinery/attack_hand(mob/user as mob)
if(inoperable(MAINT))
if(!interact_offline && stat & (NOPOWER|BROKEN|MAINT))
return 1
if(user.lying || user.stat)
return 1
+8 -1
View File
@@ -51,6 +51,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both.
var/ownjob = null //related to above
var/ownrank = null // this one is rank, never alt title
var/obj/item/device/paicard/pai = null // A slot for a personal AI device
@@ -208,9 +209,13 @@ var/global/list/obj/item/device/pda/PDAs = list()
detonate = 0
/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text)
/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text)
owner = newname
ownjob = newjob
if(newrank)
ownrank = newrank
else
ownrank = ownjob
name = newname + " (" + ownjob + ")"
@@ -571,6 +576,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
id_check(U, 1)
if("UpdateInfo")
ownjob = id.assignment
ownrank = id.rank
name = "PDA-[owner] ([ownjob])"
if("Eject")//Ejects the cart, only done from hub.
if (!isnull(cartridge))
@@ -1103,6 +1109,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(!owner)
owner = idcard.registered_name
ownjob = idcard.assignment
ownrank = idcard.rank
name = "PDA-[owner] ([ownjob])"
user << "<span class='notice'>Card scanned.</span>"
else
+5 -2
View File
@@ -176,6 +176,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
randomItems.Add("/obj/item/clothing/shoes/syndigaloshes") //No-Slip Syndicate Shoes
randomItems.Add("/obj/item/weapon/plastique") //C4
randomItems.Add("/obj/item/weapon/storage/box/syndie_kit/masks_gas")
randomItems.Add("/obj/item/shoe_cover")
if(uses > 0)
randomItems.Add("/obj/item/weapon/soap/syndie") //Syndicate Soap
@@ -207,7 +208,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
uses -= 3
if("/obj/item/ammo_magazine/a357" , "/obj/item/clothing/shoes/syndigaloshes" , "/obj/item/weapon/plastique", "/obj/item/weapon/card/id/syndicate" , "/obj/item/weapon/storage/box/syndie_kit/masks_gas")
uses -= 2
if("/obj/item/weapon/soap/syndie" , "/obj/item/weapon/storage/toolbox/syndicate" , "/obj/item/weapon/storage/box/syndie_kit/masks")
if("/obj/item/weapon/soap/syndie" , "/obj/item/weapon/storage/toolbox/syndicate" , "/obj/item/weapon/storage/box/syndie_kit/masks", "/obj/item/shoe_cover")
uses -= 1
del(randomItems)
return buyItem
@@ -281,7 +282,9 @@ A list of items and costs is stored under the datum of every game mode, alongsid
feedback_add_details("traitor_uplink_items_bought","SR")
if("/obj/item/clothing/gloves/force/syndicate")
feedback_add_details("traitor_uplink_items_bought","FG")
if("/obj/item/shoe_cover")
feedback_add_details("traitor_uplink_items_bought","SFS")
/obj/item/shoe_cover
/obj/item/device/uplink/Topic(href, href_list)
+17
View File
@@ -0,0 +1,17 @@
/obj/item/shoe_cover
name = "strange fabric"
desc = "A fabirc that allows for silent walking."
icon = 'icons/obj/items.dmi'
icon_state = "sheet-cloth"
/obj/item/shoe_cover/afterattack(var/obj/A as obj, mob/user as mob, proximity)
if(!proximity)
return
if (istype(A, /obj/item/clothing/shoes) && get_dist(src,A) <= 1)
var/obj/item/clothing/shoes/S = A
user << "You attahed the [src] to [S] making movement silent"
S.silent = 1
S.desc += " They appear to have some type of fabric soles"
user.drop_from_inventory(src)
del(src)
+24 -1
View File
@@ -128,4 +128,27 @@
var/rendered = "<span class='game say'><span class='name'>[M.name]: </span> <span class='message'>[text]</span></span>"
mo.show_message(rendered, 2)
*/
return
return
/obj/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/custom_state = default_state)
// Calling Topic without a corresponding window open causes runtime errors
if(!nowindow && ..())
return 1
// In the far future no checks are made in an overriding Topic() beyond if(..()) return
// Instead any such checks are made in CanUseTopic()
var/obj/host = nano_host()
if(host.CanUseTopic(usr, href_list, custom_state) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
return 0
CouldNotUseTopic(usr)
return 1
/obj/proc/CouldUseTopic(var/mob/user)
var/atom/host = nano_host()
host.add_fingerprint(user)
/obj/proc/CouldNotUseTopic(var/mob/user)
// Nada
+34 -10
View File
@@ -7,6 +7,19 @@ var/list/clown_sound = list('sound/effects/clownstep1.ogg','sound/effects/clowns
var/list/swing_hit_sound = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')
var/list/hiss_sound = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
var/list/page_sound = list('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')
//FOOTSTEPS
var/list/defaultfootsteps = list('sound/effects/footsteps/tile1.wav','sound/effects/footsteps/tile2.wav','sound/effects/footsteps/tile3.wav','sound/effects/footsteps/tile4.wav')
var/list/concretefootsteps = list('sound/effects/footsteps/concrete1.wav','sound/effects/footsteps/concrete2.wav','sound/effects/footsteps/concrete3.wav','sound/effects/footsteps/concrete4.wav')
var/list/grassfootsteps = list('sound/effects/footsteps/grass1.wav','sound/effects/footsteps/grass2.wav','sound/effects/footsteps/grass3.wav','sound/effects/footsteps/grass4.wav')
var/list/dirtfootsteps = list('sound/effects/footsteps/dirt1.wav','sound/effects/footsteps/dirt2.wav','sound/effects/footsteps/dirt3.wav','sound/effects/footsteps/dirt4.wav')
var/list/waterfootsteps = list('sound/effects/footsteps/slosh1.wav','sound/effects/footsteps/slosh2.wav','sound/effects/footsteps/slosh3.wav','sound/effects/footsteps/slosh4.wav')
var/list/sandfootsteps = list('sound/effects/footsteps/sand1.wav','sound/effects/footsteps/sand2.wav','sound/effects/footsteps/sand3.wav','sound/effects/footsteps/sand4.wav')
var/list/gravelstep = list('sound/effects/footsteps/gravel1.wav','sound/effects/footsteps/gravel2.wav','sound/effects/footsteps/gravel3.wav','sound/effects/footsteps/gravel4.wav')
var/list/footstepfx = list("defaultstep","concretestep","grassstep","dirtstep","waterstep","sandstep")
//var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg')
/proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, var/is_global)
@@ -37,6 +50,11 @@ var/const/FALLOFF_SOUNDS = 0.5
/mob/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global)
if(!src.client || ear_deaf > 0) return
if(soundin in footstepfx)
if(!(src.client.prefs.asfx_togs & ASFX_FOOTSTEPS))
return
soundin = get_sfx(soundin)
var/sound/S = sound(soundin)
@@ -53,34 +71,34 @@ var/const/FALLOFF_SOUNDS = 0.5
if(isturf(turf_source))
// 3D sounds, the technology is here!
var/turf/T = get_turf(src)
//sound volume falloff with distance
var/distance = get_dist(T, turf_source)
S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff.
//sound volume falloff with pressure
var/pressure_factor = 1.0
var/datum/gas_mixture/hearer_env = T.return_air()
var/datum/gas_mixture/source_env = turf_source.return_air()
if (hearer_env && source_env)
var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure())
if (pressure < ONE_ATMOSPHERE)
pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0)
else //in space
pressure_factor = 0
if (distance <= 1)
pressure_factor = max(pressure_factor, 0.15) //hearing through contact
S.volume *= pressure_factor
if (S.volume <= 0)
return //no volume means no sound
var/dx = turf_source.x - T.x // Hearing from the right/left
S.x = dx
var/dz = turf_source.y - T.y // Hearing from infront/behind
@@ -113,4 +131,10 @@ var/const/FALLOFF_SOUNDS = 0.5
if ("hiss") soundin = pick(hiss_sound)
if ("pageturn") soundin = pick(page_sound)
//if ("gunshot") soundin = pick(gun_sound)
if ("defaultstep") soundin = pick(defaultfootsteps)
if ("concretestep") soundin = pick(concretefootsteps)
if ("grassstep") soundin = pick(grassfootsteps)
if ("dirtstep") soundin = pick(dirtfootsteps)
if ("waterstep") soundin = pick(waterfootsteps)
if ("sandstep") soundin = pick(sandfootsteps)
return soundin
+25 -2
View File
@@ -33,9 +33,11 @@ var/list/wood_icons = list("wood","wood-broken")
var/lava = 0
var/broken = 0
var/burnt = 0
var/fire_damage = 0
var/mineral = "metal"
var/obj/item/stack/tile/floor_tile = new/obj/item/stack/tile/plasteel
footstep_sound = "defaultstep"
/turf/simulated/floor/New()
..()
@@ -76,11 +78,31 @@ var/list/wood_icons = list("wood","wood-broken")
return
/turf/simulated/floor/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(!burnt && prob(5))
if(exposed_temperature > 500+T0C && !(fire_damage >= heat_capacity))
fire_damage += round((exposed_temperature * thermal_conductivity)*10)
if(!burnt && fire_damage >= round(heat_capacity / 3))
burn_tile()
else if(prob(1) && !is_plating())
else if(!is_plating() && fire_damage > round(heat_capacity / 1.5)) //What are these numbers, I have no idea, I pulled them out of a hat. No really I did.
make_plating()
burn_tile()
for(var/turf/simulated/floor/RT in AdjacentTurfs())
if(!RT.burnt)
RT.burn_tile()
else if(fire_damage > heat_capacity && prob(1))
for(var/turf/simulated/floor/RT in AdjacentTurfs())
if(istype(RT) && (RT.x == src.x || RT.y == src.y) && prob(20))
RT.burnPipes()
RT.ReplaceWithLattice()
burnPipes()
ReplaceWithLattice()
return
/turf/simulated/floor/proc/burnPipes()
for(var/obj/machinery/M in src)
if(istype(M, /obj/machinery))
M.blob_act()
for(var/obj/structure/disposalpipe/DP in src)
blob_act()
return
/turf/simulated/floor/adjacent_fire_act(turf/simulated/floor/adj_turf, datum/gas_mixture/adj_air, adj_temp, adj_volume)
@@ -558,5 +580,6 @@ turf/simulated/floor/proc/update_icon()
icon_state = "plating"
burnt = 0
broken = 0
fire_damage = 0
else
user << "\blue You need more welding fuel to complete this task."
+10
View File
@@ -140,11 +140,13 @@
/turf/simulated/shuttle/floor
name = "floor"
icon_state = "floor"
footstep_sound = "concretefootsteps"
/turf/simulated/shuttle/plating
name = "plating"
icon = 'icons/turf/floors.dmi'
icon_state = "plating"
footstep_sound = "concretefootsteps"
/turf/simulated/shuttle/plating/vox //Vox skipjack plating
oxygen = 0
@@ -162,19 +164,23 @@
/turf/simulated/floor/beach
name = "Beach"
icon = 'icons/misc/beach.dmi'
footstep_sound = "sandstep"
/turf/simulated/floor/beach/sand
name = "Sand"
icon_state = "sand"
footstep_sound = "sandstep"
/turf/simulated/floor/beach/coastline
name = "Coastline"
icon = 'icons/misc/beach2.dmi'
icon_state = "sandwater"
footstep_sound = "sandstep"
/turf/simulated/floor/beach/water
name = "Water"
icon_state = "water"
footstep_sound = "waterstep"
/turf/simulated/floor/beach/water/New()
..()
@@ -184,6 +190,7 @@
name = "Grass patch"
icon_state = "grass1"
floor_tile = new/obj/item/stack/tile/grass
footstep_sound = "grassstep"
New()
floor_tile.New() //I guess New() isn't ran on objects spawned without the definition of a turf to house them, ah well.
@@ -201,6 +208,8 @@
name = "Carpet"
icon_state = "carpet"
floor_tile = new/obj/item/stack/tile/carpet
footstep_sound = null
New()
floor_tile.New() //I guess New() isn't ran on objects spawned without the definition of a turf to house them, ah well.
@@ -226,6 +235,7 @@
name = "snow"
icon = 'icons/turf/snow.dmi'
icon_state = "snow"
footstep_sound = "grassstep"
/turf/simulated/floor/plating/snow/ex_act(severity)
return
+1
View File
@@ -2,6 +2,7 @@
icon = 'icons/turf/space.dmi'
name = "\proper space"
icon_state = "0"
footstep_sound = null //Override to make sure because yeah
temperature = T0C
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
+16
View File
@@ -26,6 +26,8 @@
var/has_resources
var/list/resources
var/footstep_sound = null
/turf/New()
..()
for(var/atom/movable/AM as mob|obj in src)
@@ -97,6 +99,7 @@
if(movement_disabled)
usr << "\red Movement is admin-disabled." //This is to identify lag problems
return
..()
//vvvvv Infared beam stuff vvvvv
@@ -121,6 +124,19 @@
if(M:lastarea.has_gravity == 0)
inertial_drift(M)
var/mob/living/carbon/human/MOB = M
if(istype(MOB) && !MOB.lying && footstep_sound)
if(istype(MOB.shoes, /obj/item/clothing/shoes) && !MOB.shoes:silent)
if(MOB.m_intent == "run")
if(MOB.footstep >= 2)
MOB.footstep = 0
else
MOB.footstep++
if(MOB.footstep == 0)
playsound(MOB, footstep_sound, 50, 1) // this will get annoying very fast. - Tell them to mute it then -_-
else
playsound(MOB, footstep_sound, 40, 1)
/*
if(M.flags & NOGRAV)
inertial_drift(M)
+3
View File
@@ -5,15 +5,18 @@
/turf/unsimulated/beach/sand
name = "Sand"
icon_state = "sand"
footstep_sound = "sandstep"
/turf/unsimulated/beach/coastline
name = "Coastline"
icon = 'icons/misc/beach2.dmi'
icon_state = "sandwater"
footstep_sound = "sandstep"
/turf/unsimulated/beach/water
name = "Water"
icon_state = "water"
footstep_sound = "waterstep"
/turf/unsimulated/beach/water/New()
..()
-7
View File
@@ -195,13 +195,6 @@ var/forceblob = 0
// nanomanager, the manager for Nano UIs
var/datum/nanomanager/nanomanager = new()
//airlockWireColorToIndex takes a number representing the wire color, e.g. the orange wire is always 1, the dark red wire is always 2, etc. It returns the index for whatever that wire does.
//airlockIndexToWireColor does the opposite thing - it takes the index for what the wire does, for example AIRLOCK_WIRE_IDSCAN is 1, AIRLOCK_WIRE_POWER1 is 2, etc. It returns the wire color number.
//airlockWireColorToFlag takes the wire color number and returns the flag for it (1, 2, 4, 8, 16, etc)
var/list/globalAirlockWireColorToFlag = RandomAirlockWires()
var/list/globalAirlockIndexToFlag
var/list/globalAirlockIndexToWireColor
var/list/globalAirlockWireColorToIndex
var/list/APCWireColorToFlag = RandomAPCWires()
var/list/APCIndexToFlag
var/list/APCIndexToWireColor
+1
View File
@@ -16,6 +16,7 @@
var/obj/item/device/assembly_holder/holder = null
var/cooldown = 0//To prevent spam
var/wires = WIRE_RECEIVE | WIRE_PULSE
var/datum/wires/connected = null // currently only used by timer/signaler
var/const/WIRE_RECEIVE = 1 //Allows Pulsed(0) to call Activate()
var/const/WIRE_PULSE = 2 //Allows Pulse(0) to act on the holder
+4 -7
View File
@@ -118,14 +118,11 @@
pulse(var/radio = 0)
if(istype(src.loc, /obj/machinery/door/airlock) && src.airlock_wire && src.wires)
var/obj/machinery/door/airlock/A = src.loc
A.pulse(src.airlock_wire)
else if(holder)
holder.process_activation(src, 1, 0)
if(src.connected && src.wires)
connected.Pulse(src)
else
..(radio)
return 1
return ..(radio)
receive_signal(datum/signal/signal)
+5 -1
View File
@@ -46,6 +46,7 @@ datum/preferences
var/be_special = 0 //Special role selection
var/UI_style = "Midnight"
var/toggles = TOGGLES_DEFAULT
var/asfx_togs = ASFX_DEFAULT
var/UI_style_color = "#ffffff"
var/UI_style_alpha = 255
@@ -496,7 +497,10 @@ datum/preferences
HTML += "<tr bgcolor='[job.selection_color]'><td width='60%' align='right'>"
var/rank = job.title
lastJob = job
if(jobban_isbanned(user, rank))
if(jobban_isbanned(user, rank) == "Whitelisted Job")
HTML += "<del>[rank]</del></td><td><b> \[WHITELISTED]</b></td></tr>"
continue
else if(jobban_isbanned(user, rank))
HTML += "<del>[rank]</del></td><td><b> \[BANNED]</b></td></tr>"
continue
if(!job.player_old_enough(user.client))
@@ -0,0 +1,52 @@
/var/global/asfx_togs = list(
/client/proc/Toggle_asfx,
/client/proc/Toggle_footsteps,
/client/proc/Toggle_asfx_vote
)
/client/verb/asf_toggle()
set name = "Open ASFX Tab"
set category = "Preferences"
set desc = "Open the ambiance sound effects toggle tab"
verbs ^= asfx_togs
return
/client/proc/Toggle_asfx() //Allgnew ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful
set name = "Hear/Silence Ambience"
set category = "SoundFx Prefs"
set desc = "Toggles hearing ambient sound effects"
prefs.asfx_togs ^= ASFX_AMBIENCE
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_AMBIENCE)
src << "You will now hear ambient sounds."
else
src << "<font color='red'>You will no longer hear ambient sounds.</font>"
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
feedback_add_details("admin_verb","TSFXAmbi") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/Toggle_footsteps()
set name = "Hear/Silence Footsteps"
set category = "SoundFx Prefs"
set desc = "Toggles hearing footstep sound effects"
prefs.asfx_togs ^= ASFX_FOOTSTEPS
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_FOOTSTEPS)
src << "You will now hear footstep sounds."
else
src << "<font color='red'>You will no longer hear footstep sounds.</font>"
feedback_add_details("admin_verb","TSFXFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/Toggle_asfx_vote()
set name = "Hear/Silence Vote Alarm"
set category = "SoundFx Prefs"
set desc = "Toggles hearing of the vote alarm"
prefs.asfx_togs ^= ASFX_VOTE
prefs.save_preferences()
if(prefs.asfx_togs & ASFX_VOTE)
src << "You will now hear the vote alarm."
else
src << "<font color='red'>You will no longer hear the vote alarm.</font>"
feedback_add_details("admin_verb","TSFXFV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -56,6 +56,7 @@
S["toggles"] >> toggles
S["UI_style_color"] >> UI_style_color
S["UI_style_alpha"] >> UI_style_alpha
S["asfx_togs"] >> asfx_togs
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
@@ -64,6 +65,7 @@
be_special = sanitize_integer(be_special, 0, 65535, initial(be_special))
default_slot = sanitize_integer(default_slot, 1, MAX_SAVE_SLOTS, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 65535, initial(toggles))
asfx_togs = sanitize_integer(asfx_togs, 0, 65535, initial(asfx_togs))
UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color))
UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha))
@@ -84,6 +86,7 @@
S["be_special"] << be_special
S["default_slot"] << default_slot
S["toggles"] << toggles
S["asfx_togs"] << asfx_togs
return 1
+2 -1
View File
@@ -121,7 +121,7 @@
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/*
/client/verb/Toggle_Soundscape() //All new ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful
set name = "Hear/Silence Ambience"
set category = "Preferences"
@@ -135,6 +135,7 @@
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
feedback_add_details("admin_verb","TAmbi") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
*/
//be special
/client/verb/toggle_be_special(role in be_special_flags)
+1
View File
@@ -280,6 +280,7 @@ BLIND // can't see anything
slowdown = SHOES_SLOWDOWN
species_restricted = list("exclude","Unathi","Tajaran")
sprite_sheets = list("Vox" = 'icons/mob/species/vox/shoes.dmi')
var/silent = 0
/obj/item/clothing/shoes/update_clothing_icon()
if (ismob(src.loc))
+1
View File
@@ -400,6 +400,7 @@ var/list/artifact_spawn = list() // Runtime fix for geometry loading before cont
var/dug = 0 //0 = has not yet been dug, 1 = has already been dug
var/overlay_detail
has_resources = 1
footstep_sound = "gravelstep"
/turf/simulated/floor/plating/airless/asteroid/New()
+34 -20
View File
@@ -482,39 +482,52 @@
var/obj/vehicle/V = AM
V.RunOver(src)
// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc.
/mob/living/carbon/human/proc/get_authentification_rank(var/if_no_id = "No id", var/if_no_job = "No job")
var/obj/item/device/pda/pda = wear_id
if (istype(pda))
if (pda.id)
return pda.id.rank
else
return pda.ownrank
else
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
return id.rank ? id.rank : if_no_job
else
return if_no_id
//gets assignment from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job")
var/obj/item/device/pda/pda = wear_id
var/obj/item/weapon/card/id/id = wear_id
if (istype(pda))
if (pda.id && istype(pda.id, /obj/item/weapon/card/id))
. = pda.id.assignment
if (pda.id)
return pda.id.assignment
else
. = pda.ownjob
else if (istype(id))
. = id.assignment
return pda.ownjob
else
return if_no_id
if (!.)
. = if_no_job
return
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
return id.assignment ? id.assignment : if_no_job
else
return if_no_id
//gets name from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_authentification_name(var/if_no_id = "Unknown")
var/obj/item/device/pda/pda = wear_id
var/obj/item/weapon/card/id/id = wear_id
if (istype(pda))
if (pda.id)
. = pda.id.registered_name
return pda.id.registered_name
else
. = pda.owner
else if (istype(id))
. = id.registered_name
return pda.owner
else
return if_no_id
return
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
return id.registered_name
else
return if_no_id
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere
/mob/living/carbon/human/proc/get_visible_name()
@@ -955,13 +968,13 @@
if(!lastpuke)
lastpuke = 1
src << "<spawn class='warning'>You feel nauseous...</spawn>"
src << "<span class='warning'>You feel nauseous...</span>"
spawn(150) //15 seconds until second warning
src << "<spawn class='warning'>You feel like you are about to throw up!</spawn>"
src << "<span class='warning'>You feel like you are about to throw up!</span>"
spawn(100) //and you have 10 more for mad dash to the bucket
Stun(5)
src.visible_message("<spawn class='warning'>[src] throws up!","<spawn class='warning'>You throw up!</spawn>")
src.visible_message("<span class='warning'>[src] throws up!</span>","<span class='warning'>You throw up!</span>")
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
var/turf/location = loc
@@ -1077,6 +1090,7 @@
else
target.show_message("\blue You hear a voice that seems to echo around the room: [say]")
usr.show_message("\blue You project your mind into [target.real_name]: [say]")
log_say("[key_name(usr)] sent a telepathic message to [key_name(target)]: [say]")
for(var/mob/dead/observer/G in world)
G.show_message("<i>Telepathic message from <b>[src]</b> to <b>[target]</b>: [say]</i>")
+2 -1
View File
@@ -49,4 +49,5 @@
var/attacktext = "attacks"
var/attack_sound = null
var/friendly = "nuzzles"
var/wall_smash = 0
var/wall_smash = 0
var/footstep = 0
+4
View File
@@ -75,6 +75,7 @@ var/list/ai_verbs_default = list(
var/mob/living/silicon/ai/parent = null
var/apc_override = 0 //hack for letting the AI use its APC even when visionless
var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through.
var/datum/trackable/track = null
var/last_announcement = ""
@@ -820,5 +821,8 @@ var/list/ai_verbs_default = list(
return 1
return 0
/mob/living/silicon/ai/proc/is_in_chassis()
return istype(loc, /turf)
#undef AI_CHECK_WIRELESS
#undef AI_CHECK_RADIO
+4 -2
View File
@@ -1,7 +1,7 @@
json_writer
proc
WriteObject(list/L)
WriteObject(list/L, cached_data = null)
. = "{"
var/i = 1
for(var/k in L)
@@ -9,7 +9,9 @@ json_writer
. += {"\"[k]\":[write(val)]"}
if(i++ < L.len)
. += ","
.+= "}"
if(cached_data)
. = copytext(., 1, lentext(.)) + ",\"cached\":[cached_data]}"
. += "}"
write(val)
if(isnum(val))
+2 -2
View File
@@ -7,6 +7,6 @@ proc
var/static/json_reader/_jsonr = new()
return _jsonr.ReadObject(_jsonr.ScanJson(json))
list2json(list/L)
list2json(list/L, var/cached_data = null)
var/static/json_writer/_jsonw = new()
return _jsonw.WriteObject(L)
return _jsonw.WriteObject(L, cached_data)
@@ -0,0 +1,96 @@
/obj/nano_module/alarm_monitor
name = "Alarm monitor"
var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use.
var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user.
/obj/nano_module/alarm_monitor/ai
list_cameras = 1
/obj/nano_module/alarm_monitor/ai/New()
..()
alarm_handlers = alarm_manager.all_handlers
/obj/nano_module/alarm_monitor/borg/New()
..()
alarm_handlers = alarm_manager.all_handlers
/obj/nano_module/alarm_monitor/engineering/New()
..()
alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm)
/obj/nano_module/alarm_monitor/security/New()
..()
alarm_handlers = list(camera_alarm, motion_alarm)
/obj/nano_module/alarm_monitor/proc/register(var/object, var/procName)
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.register(object, procName)
/obj/nano_module/alarm_monitor/proc/unregister(var/object)
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.unregister(object)
/obj/nano_module/alarm_monitor/proc/all_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.alarms
return all_alarms
/obj/nano_module/alarm_monitor/proc/major_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.major_alarms()
return all_alarms
/obj/nano_module/alarm_monitor/proc/minor_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.minor_alarms()
return all_alarms
/obj/nano_module/alarm_monitor/ai/Topic(ref, href_list)
if(..())
return 1
if(href_list["switchTo"])
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras
if(!C)
return
usr.switch_to_camera(C)
return 1
/obj/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/categories[0]
for(var/datum/alarm_handler/AH in alarm_handlers)
categories[++categories.len] = list("category" = AH.category, "alarms" = list())
for(var/datum/alarm/A in AH.major_alarms())
var/cameras[0]
var/lost_sources[0]
if(list_cameras)
for(var/obj/machinery/camera/C in A.cameras())
cameras[++cameras.len] = C.nano_structure()
for(var/datum/alarm_source/AS in A.sources)
if(!AS.source)
lost_sources[++lost_sources.len] = AS.source_name
categories[categories.len]["alarms"] += list(list(
"name" = sanitize(A.alarm_name()),
"origin_lost" = A.origin == null,
"has_cameras" = cameras.len,
"cameras" = cameras,
"lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
data["categories"] = categories
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
+88
View File
@@ -0,0 +1,88 @@
/obj/nano_module/crew_monitor
name = "Crew monitor"
var/list/tracked = new
/obj/nano_module/crew_monitor/Topic(href, href_list)
if(..()) return
var/turf/T = get_turf(src)
if (!T || !(T.z in config.player_levels))
usr << "<span class='warning'>Unable to establish a connection<span>: You're too far away from the station!"
return 0
if(href_list["close"] )
var/mob/user = usr
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
usr.unset_machine()
ui.close()
return 0
if(href_list["update"])
src.updateDialog()
return 1
/obj/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
user.set_machine(src)
src.scan()
var/data[0]
var/turf/T = get_turf(src)
var/list/crewmembers = list()
for(var/obj/item/clothing/under/C in src.tracked)
var/turf/pos = get_turf(C)
if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
if(H.w_uniform != C)
continue
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1)
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > 1
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmembers[++crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name")
data["crewmembers"] = crewmembers
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
ui.set_initial_data(data)
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
/obj/nano_module/crew_monitor/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
tracked |= C
return 1
@@ -0,0 +1,60 @@
/obj/nano_module/power_monitor
name = "Power monitor"
var/list/grid_sensors
var/active_sensor = null //name_tag of the currently selected sensor
/obj/nano_module/power_monitor/New()
..()
refresh_sensors()
/obj/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/list/data = list()
var/list/sensors = list()
// Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading.
var/obj/machinery/power/sensor/focus = null
// Build list of data from sensor readings.
for(var/obj/machinery/power/sensor/S in grid_sensors)
sensors.Add(list(list(
"name" = S.name_tag,
"alarm" = S.check_grid_warning()
)))
if(S.name_tag == active_sensor)
focus = S
data["all_sensors"] = sensors
if(focus)
data["focus"] = focus.return_reading_data()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
// Proc: refresh_sensors()
// Parameters: None
// Description: Refreshes list of active sensors kept on this computer.
/obj/nano_module/power_monitor/proc/refresh_sensors()
grid_sensors = list()
var/turf/T = get_turf(src)
for(var/obj/machinery/power/sensor/S in machines)
if((T && S.loc.z == T.z) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
else
grid_sensors += S
// Proc: Topic()
// Parameters: 2 (href, href_list - allows us to process UI clicks)
// Description: Allows us to process UI clicks, which are relayed in form of hrefs.
/obj/nano_module/power_monitor/Topic(href, href_list)
if(..())
return
if( href_list["clear"] )
active_sensor = null
if( href_list["refresh"] )
refresh_sensors()
else if( href_list["setsensor"] )
active_sensor = href_list["setsensor"]
+116
View File
@@ -0,0 +1,116 @@
/obj/nano_module/rcon
name = "Power RCON"
var/list/known_SMESs = null
var/list/known_breakers = null
// Allows you to hide specific parts of the UI
var/hide_SMES = 0
var/hide_SMES_details = 0
var/hide_breakers = 0
/obj/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1)
FindDevices() // Update our devices list
var/data[0]
// SMES DATA (simplified view)
var/list/smeslist[0]
for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs)
smeslist.Add(list(list(
"charge" = round(SMES.Percentage()),
"input_set" = SMES.input_attempt,
"input_val" = round(SMES.input_level),
"output_set" = SMES.output_attempt,
"output_val" = round(SMES.output_level),
"output_load" = round(SMES.output_used),
"RCON_tag" = SMES.RCon_tag
)))
data["smes_info"] = sortByKey(smeslist, "RCON_tag")
// BREAKER DATA (simplified view)
var/list/breakerlist[0]
for(var/obj/machinery/power/breakerbox/BR in known_breakers)
breakerlist.Add(list(list(
"RCON_tag" = BR.RCon_tag,
"enabled" = BR.on
)))
data["breaker_info"] = breakerlist
data["hide_smes"] = hide_SMES
data["hide_smes_details"] = hide_SMES_details
data["hide_breakers"] = hide_breakers
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
// Proc: Topic()
// Parameters: 2 (href, href_list - allows us to process UI clicks)
// Description: Allows us to process UI clicks, which are relayed in form of hrefs.
/obj/nano_module/rcon/Topic(href, href_list)
if(..())
return
if(href_list["smes_in_toggle"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_toggle"])
if(SMES)
SMES.toggle_input()
if(href_list["smes_out_toggle"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_toggle"])
if(SMES)
SMES.toggle_output()
if(href_list["smes_in_set"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_set"])
if(SMES)
var/inputset = input(usr, "Enter new input level (0-[SMES.input_level_max])", "SMES Input Power Control") as num
SMES.set_input(inputset)
if(href_list["smes_out_set"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_set"])
if(SMES)
var/outputset = input(usr, "Enter new output level (0-[SMES.output_level_max])", "SMES Input Power Control") as num
SMES.set_output(outputset)
if(href_list["toggle_breaker"])
var/obj/machinery/power/breakerbox/toggle = null
for(var/obj/machinery/power/breakerbox/breaker in known_breakers)
if(breaker.RCon_tag == href_list["toggle_breaker"])
toggle = breaker
if(toggle)
if(toggle.update_locked)
usr << "The breaker box was recently toggled. Please wait before toggling it again."
else
toggle.auto_toggle()
if(href_list["hide_smes"])
hide_SMES = !hide_SMES
if(href_list["hide_smes_details"])
hide_SMES_details = !hide_SMES_details
if(href_list["hide_breakers"])
hide_breakers = !hide_breakers
// Proc: GetSMESByTag()
// Parameters: 1 (tag - RCON tag of SMES we want to look up)
// Description: Looks up and returns SMES which has matching RCON tag
/obj/nano_module/rcon/proc/GetSMESByTag(var/tag)
if(!tag)
return
for(var/obj/machinery/power/smes/buildable/S in known_SMESs)
if(S.RCon_tag == tag)
return S
// Proc: FindDevices()
// Parameters: None
// Description: Refreshes local list of known devices.
/obj/nano_module/rcon/proc/FindDevices()
known_SMESs = new /list()
for(var/obj/machinery/power/smes/buildable/SMES in machines)
if(SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon)
known_SMESs.Add(SMES)
known_breakers = new /list()
for(var/obj/machinery/power/breakerbox/breaker in machines)
if(breaker.RCon_tag != "NO_TAG")
known_breakers.Add(breaker)
+7 -7
View File
@@ -1,5 +1,5 @@
// This file contains all Nano procs/definitions for external classes/objects
// This file contains all Nano procs/definitions for external classes/objects
/**
* Called when a Nano UI window is closed
* This is how Nano handles closed windows
@@ -15,7 +15,7 @@
if (istype(ui))
ui.close()
if(ui.ref)
var/href = "close=1"
src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic()
@@ -31,14 +31,14 @@
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
* @param force_open boolean Force the UI to (re)open, even if it's already open
*
* @return nothing
*/
/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/custom_state = null)
return
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
/mob/var/list/open_uis = list()
+131
View File
@@ -0,0 +1,131 @@
/atom/movable/proc/nano_host()
return src
/obj/nano_module/nano_host()
return loc
/atom/movable/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state)
return user.can_use_topic(nano_host(), custom_state)
/mob/proc/can_use_topic(var/mob/user, var/datum/topic_state/custom_state)
return STATUS_CLOSE // By default no mob can do anything with NanoUI
/mob/dead/observer/can_use_topic()
if(check_rights(R_ADMIN, 0, src))
return STATUS_INTERACTIVE // Admins are more equal
return STATUS_UPDATE // Ghosts can view updates
/mob/living/silicon/pai/can_use_topic(var/src_object)
if(src_object == src && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/living/silicon/robot/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
if(stat || !client)
return STATUS_CLOSE
if(lockcharge || stunned || weakened)
return STATUS_DISABLED
if(custom_state.flags & NANO_IGNORE_DISTANCE)
return STATUS_INTERACTIVE
// robots can interact with things they can see within their view range
if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view)
return STATUS_INTERACTIVE // interactive (green visibility)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
/mob/living/silicon/robot/syndicate/can_use_topic(var/src_object)
. = ..()
if(. != STATUS_INTERACTIVE)
return
if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level
return STATUS_INTERACTIVE
if(istype(get_area(src), /area/syndicate_station)) // If elsewhere, they can interact with everything on the syndicate shuttle
return STATUS_INTERACTIVE
if(istype(src_object, /obj/machinery)) // Otherwise they can only interact with emagged machinery
var/obj/machinery/Machine = src_object
if(Machine.emagged)
return STATUS_INTERACTIVE
return STATUS_UPDATE
/mob/living/silicon/ai/can_use_topic(var/src_object)
if(!client || check_unable(1))
return STATUS_CLOSE
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in config.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
//apc_override is needed here because AIs use their own APC when powerless
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE
return STATUS_INTERACTIVE
else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/proc/shared_living_nano_interaction(var/src_object)
if (src.stat != CONSCIOUS)
return STATUS_CLOSE // no updates, close the interface
else if (restrained() || lying || stat || stunned || weakened)
return STATUS_UPDATE // update only (orange visibility)
return STATUS_INTERACTIVE
//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI.
/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user)
return user.shared_living_nano_distance(src_object)
/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
if(!isturf(src_object.loc))
if(src_object.loc == src) // Item in the inventory
return STATUS_INTERACTIVE
if(src.contents.Find(src_object.loc)) // A hidden uplink inside an item
return STATUS_INTERACTIVE
if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if (dist <= 1)
return STATUS_INTERACTIVE // interactive (green visibility)
else if (dist <= 2)
return STATUS_UPDATE // update only (orange visibility)
else if (dist <= 4)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
return STATUS_CLOSE
/mob/living/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && !(custom_state.flags & NANO_IGNORE_DISTANCE))
if(loc)
. = loc.contents_nano_distance(src_object, src)
else
. = shared_living_nano_distance(src_object)
if(STATUS_INTERACTIVE)
return STATUS_UPDATE
/mob/living/carbon/human/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && !(custom_state.flags & NANO_IGNORE_DISTANCE))
. = shared_living_nano_distance(src_object)
if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction.
return STATUS_INTERACTIVE
/var/global/datum/topic_state/default_state = new()
/datum/topic_state
var/flags = 0
/datum/topic_state/proc/href_list(var/mob/user)
return list()
+32 -30
View File
@@ -21,7 +21,7 @@
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
@@ -29,6 +29,7 @@
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
/**
@@ -47,15 +48,15 @@
if (isnull(ui)) // no ui has been passed, so we'll search for one
{
ui = get_open_ui(user, src_object, ui_key)
}
if (!isnull(ui))
}
if (!isnull(ui))
// The UI is already open
if (!force_open)
ui.push_data(data)
return ui
else
//testing("nanomanager/try_update_ui mob [user.name] [src_object:name] [ui_key] [force_open] - forcing opening of ui")
ui.close()
ui.close()
return null
/**
@@ -72,14 +73,14 @@
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open")
return null
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object")
return null
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if (ui.user == user)
return ui
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found")
return null
@@ -90,21 +91,21 @@
*
* @return int The number of uis updated
*/
/datum/nanomanager/proc/update_uis(src_object)
/datum/nanomanager/proc/update_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
return 0
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user)
if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.process(1)
update_count++
return update_count
/**
* Update /nanoui uis belonging to user
* Update /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
@@ -117,15 +118,15 @@
return 0 // has no open uis
var/update_count = 0
for (var/datum/nanoui/ui in user.open_uis)
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.process(1)
update_count++
return update_count
/**
* Close /nanoui uis belonging to user
* Close /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
@@ -136,16 +137,16 @@
/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/close_user_uis mob [user.name] has no open uis")
return 0 // has no open uis
return 0 // has no open uis
var/close_count = 0
for (var/datum/nanoui/ui in user.open_uis)
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.close()
close_count++
//testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis")
//testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis")
return close_count
/**
@@ -185,14 +186,15 @@
return 0 // wasn't open
processing_uis.Remove(ui)
ui.user.open_uis.Remove(ui)
if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface)
ui.user.open_uis.Remove(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Remove(ui)
//testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
return 1
/**
* This is called on user logout
* Closes/clears all uis attached to the user's /mob
@@ -202,7 +204,7 @@
* @return nothing
*/
//
//
/datum/nanomanager/proc/user_logout(var/mob/user)
//testing("nanomanager/user_logout user [user.name]")
return close_user_uis(user)
@@ -218,7 +220,7 @@
*/
/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
//testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]")
if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/user_transferred mob [oldMob.name] has no open uis")
return 0 // has no open uis
@@ -230,9 +232,9 @@
newMob.open_uis.Add(ui)
oldMob.open_uis.Cut()
return 1 // success
/**
* Sends all nano assets to the client
* This is called on user login
@@ -243,6 +245,6 @@
*/
/datum/nanomanager/proc/send_resources(client)
for(var/file in asset_files)
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client
+70 -70
View File
@@ -6,12 +6,7 @@ nanoui class (or whatever Byond calls classes)
nanoui is used to open and update nano browser uis
**********************************************************/
#define STATUS_INTERACTIVE 2 // GREEN Visability
#define STATUS_UPDATE 1 // ORANGE Visability
#define STATUS_DISABLED 0 // RED Visability
/datum/nanoui
/datum/nanoui
// the user who opened this ui
var/mob/user
// the object this ui "belongs" to
@@ -57,8 +52,12 @@ nanoui is used to open and update nano browser uis
// the current status/visibility of the ui
var/status = STATUS_INTERACTIVE
// Only allow users with a certain user.stat to get updates. Defaults to 0 (concious)
var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive
// Relationship between a master interface and its children. Used in update_status
var/datum/nanoui/master_ui
var/list/datum/nanoui/children = list()
var/datum/topic_state/custom_state = null
var/cached_data = null
/**
* Create a new nanoui instance.
@@ -74,17 +73,22 @@ nanoui is used to open and update nano browser uis
*
* @return /nanoui new nanoui object
*/
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/custom_state = null)
user = nuser
src_object = nsrc_object
ui_key = nui_key
window_id = "[ui_key]\ref[src_object]"
src.master_ui = master_ui
if(master_ui)
master_ui.children += src
src.custom_state = custom_state ? custom_state : new/datum/topic_state()
// add the passed template filename as the "main" template, this is required
add_template("main", ntemplate_filename)
if (ntitle)
title = ntitle
title = sanitize(ntitle)
if (nwidth)
width = nwidth
if (nheight)
@@ -103,13 +107,13 @@ nanoui is used to open and update nano browser uis
add_script("libraries.min.js") // A JS file comprising of jQuery, doT.js and jQuery Timer libraries (compressed together)
add_script("nano_utility.js") // The NanoUtility JS, this is used to store utility functions.
add_script("nano_template.js") // The NanoTemplate JS, this is used to render templates.
add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state
add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from
add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState
add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state
add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from
add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState
add_script("nano_base_callbacks.js") // The NanoBaseCallbacks JS, this is used to set up (before and after update) callbacks which are common to all UIs
add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all UIs
add_stylesheet("shared.css") // this CSS sheet is common to all UIs
add_stylesheet("icons.css") // this CSS sheet is common to all UIs
add_stylesheet("icons.css") // this CSS sheet is common to all UIs
/**
* Set the current status (also known as visibility) of this ui.
@@ -127,7 +131,7 @@ nanoui is used to open and update nano browser uis
update()
else
status = state
if (push_update || status == 0)
if (push_update || status == 0)
push_data(null, 1) // Update the UI, force the update in case the status is 0, data is null so that previous data is used
/**
@@ -138,34 +142,14 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/update_status(var/push_update = 0)
if (istype(user, /mob/living/silicon/ai))
set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
else if (istype(user, /mob/living/silicon/robot))
if (src_object in view(7, user)) // robots can see and interact with things they can see within 7 tiles
set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
else
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
var/atom/movable/host = src_object.nano_host()
var/new_status = host.CanUseTopic(user, list(), custom_state)
if(master_ui)
new_status = min(new_status, master_ui.status)
if(new_status == STATUS_CLOSE)
close()
else
var/dist = get_dist(src_object, user)
if (dist > 4)
close()
return
if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
else if (user.restrained() || user.lying)
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI
set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity.
else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
else if (dist <= 1)
set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
else if (dist <= 2)
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
else if (dist <= 4)
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
set_status(new_status, push_update)
/**
* Set the ui to auto update (every master_controller tick)
@@ -203,7 +187,7 @@ nanoui is used to open and update nano browser uis
"showMap" = show_map,
"mapZLevel" = map_z_level,
"user" = list("name" = user.name)
)
)
return config_data
/**
@@ -215,12 +199,12 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/get_send_data(var/list/data)
var/list/config_data = get_config_data()
var/list/send_data = list("config" = config_data)
if (!isnull(data))
send_data["data"] = data
return send_data
/**
@@ -267,11 +251,11 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/add_template(key, filename)
templates[key] = filename
/**
* Set the layout key for use in the frontend Javascript
* The layout key is the basic layout key for the page
* Two files are loaded on the client based on the layout key varable:
* Two files are loaded on the client based on the layout key varable:
* -> a template in /nano/templates with the filename "layout_<layout_key>.tmpl
* -> a CSS stylesheet in /nano/css with the filename "layout_<layout_key>.css
*
@@ -301,7 +285,7 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/set_auto_update_content(nstate)
auto_update_content = nstate
/**
* Set the state key for use in the frontend Javascript
*
@@ -310,8 +294,8 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/set_state_key(nstate_key)
state_key = nstate_key
state_key = nstate_key
/**
* Toggle showing the map ui
*
@@ -321,7 +305,7 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/set_show_map(nstate)
show_map = nstate
/**
* Toggle showing the map ui
*
@@ -352,21 +336,21 @@ nanoui is used to open and update nano browser uis
// before the UI opens, add the layout files based on the layout key
add_stylesheet("layout_[layout_key].css")
add_template("layout", "layout_[layout_key].tmpl")
var/head_content = ""
for (var/filename in scripts)
head_content += "<script type='text/javascript' src='[filename]'></script> "
for (var/filename in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[filename]'> "
var/template_data_json = "{}" // An empty JSON object
if (templates.len > 0)
template_data_json = list2json(templates)
var/list/send_data = get_send_data(initial_data)
var/initial_data_json = list2json(send_data)
var/initial_data_json = list2json(send_data, cached_data)
var/url_parameters_json = list2json(list("src" = "\ref[src]"))
@@ -378,7 +362,7 @@ nanoui is used to open and update nano browser uis
<script type='text/javascript'>
function receiveUpdateData(jsonString)
{
// We need both jQuery and NanoStateManager to be able to recieve data
// We need both jQuery and NanoStateManager to be able to recieve data
// At the moment any data received before those libraries are loaded will be lost
if (typeof NanoStateManager != 'undefined' && typeof jQuery != 'undefined')
{
@@ -388,7 +372,7 @@ nanoui is used to open and update nano browser uis
</script>
[head_content]
</head>
<body scroll=auto data-template-data='[template_data_json]' data-url-parameters='[url_parameters_json]' data-initial-data='[initial_data_json]'>
<body scroll=auto data-template-data='[template_data_json]' data-url-parameters='[url_parameters_json]' data-initial-data='[initial_data_json]'>
<div id='uiLayout'>
</div>
<noscript>
@@ -407,8 +391,10 @@ nanoui is used to open and update nano browser uis
*
* @return nothing
*/
/datum/nanoui/proc/open()
/datum/nanoui/proc/open()
if(!user.client)
return
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
@@ -428,6 +414,8 @@ nanoui is used to open and update nano browser uis
is_auto_updating = 0
nanomanager.ui_closed(src)
user << browse(null, "window=[window_id]")
for(var/datum/nanoui/child in children)
child.close()
/**
* Set the UI window to call the nanoclose verb when the window is closed
@@ -442,6 +430,19 @@ nanoui is used to open and update nano browser uis
winset(user, window_id, "on-close=\"nanoclose [params]\"")
/**
* Appends already processed json txt to the list2json proc when setting initial-data and data pushes
* Used for data that is fucking huge like manifests and camera lists that doesn't change often.
* And we only want to process them when they change.
* Fuck javascript
*
* @return nothing
*/
/datum/nanoui/proc/load_cached_data(var/data)
cached_data = data
return
/**
* Push data to an already open UI window
*
@@ -453,9 +454,9 @@ nanoui is used to open and update nano browser uis
return // Cannot update UI, no visibility
var/list/send_data = get_send_data(data)
//user << list2json(data) // used for debugging
user << output(list2params(list(list2json(send_data))),"[window_id].browser:receiveUpdateData")
user << output(list2params(list(list2json(send_data,cached_data))),"[window_id].browser:receiveUpdateData")
/**
* This Topic() proc is called whenever a user clicks on a link within a Nano UI
@@ -468,18 +469,18 @@ nanoui is used to open and update nano browser uis
update_status(0) // update the status
if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user
return
// This is used to toggle the nano map ui
var/map_update = 0
if(href_list["showMap"])
set_show_map(text2num(href_list["showMap"]))
map_update = 1
if(href_list["mapZLevel"])
set_map_z_level(text2num(href_list["mapZLevel"]))
map_update = 1
if ((src_object && src_object.Topic(href, href_list)) || map_update)
if ((src_object && src_object.Topic(href, href_list, 0, custom_state)) || map_update)
nanomanager.update_uis(src_object) // update all UIs attached to src_object
/**
@@ -494,17 +495,16 @@ nanoui is used to open and update nano browser uis
if (!src_object || !user)
close()
return
if (status && (update || is_auto_updating))
update() // Update the UI (update_status() is called whenever a UI is updated)
else
update_status(1) // Not updating UI, so lets check here if status has changed
/**
* Update the UI
*
* @return nothing
*/
/datum/nanoui/proc/update(var/force_open = 0)
src_object.ui_interact(user, ui_key, src, force_open)
src_object.ui_interact(user, ui_key, src, force_open, master_ui, custom_state)
+33 -3
View File
@@ -636,7 +636,7 @@ var/list/liftable_structures = list(\
//Preference toggles
#define SOUND_ADMINHELP 1
#define SOUND_MIDI 2
#define SOUND_AMBIENCE 4
//#define SOUND_AMBIENCE 4 //This can get redefined
#define SOUND_LOBBY 8
#define CHAT_OOC 16
#define CHAT_DEAD 32
@@ -650,8 +650,15 @@ var/list/liftable_structures = list(\
#define CHAT_GHOSTRADIO 8192
#define CHAT_SCOPES_DEBUG 16384
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC)
//Sound effects toggles
#define ASFX_AMBIENCE 1
#define ASFX_FOOTSTEPS 2
#define ASFX_VOTE 4
#define ASFX_DEFAULT (ASFX_AMBIENCE|ASFX_FOOTSTEPS|ASFX_VOTE)
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC)
//Status Menu toggles
#define STAT_MENU_MC = 1
@@ -886,4 +893,27 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
// Reagent metabolism defines.
#define FOOD_METABOLISM 0.4
#define ALCOHOL_METABOLISM 0.1
#define ALCOHOL_METABOLISM 0.1
//Click cooldowns, in tenths of a second
#define CLICK_CD_MELEE 8
#define CLICK_CD_RANGE 4
#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
#define CLICK_CD_TKSTRANGLE 10
#define CLICK_CD_POINT 10
#define CLICK_CD_RESIST 20
// NanoUI flags
#define STATUS_INTERACTIVE 2 // GREEN Visability
#define STATUS_UPDATE 1 // ORANGE Visability
#define STATUS_DISABLED 0 // RED Visability
#define STATUS_CLOSE -1 // Close the interface
#define NANO_IGNORE_DISTANCE 1 //Why is this? I don't
// Suit sensor levels
#define SUIT_SENSOR_OFF 0
#define SUIT_SENSOR_BINARY 1
#define SUIT_SENSOR_VITAL 2
#define SUIT_SENSOR_TRACKING 3
+2
View File
@@ -67,6 +67,8 @@ h1.alert, h2.alert {color: #000000;}
.skrell {color: #00CED1;}
.vaurca {color: #9e9e39;}
.soghun {color: #228B22;}
.solcom {color: #22228B;}
.changeling {color: #800080;}
.vox {color: #AA00AA;}
.rough {font-family: "Trebuchet MS", cursive, sans-serif;}
.say_quote {font-family: Georgia, Verdana, sans-serif;}
+25 -2
View File
@@ -29,7 +29,7 @@ hr {
background-color: #40628a;
height: 1px;
}
.link, .linkOn, .linkOff, .selected, .disabled {
.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
float: left;
min-width: 15px;
height: 16px;
@@ -217,6 +217,14 @@ h4 {
font-weight: bold;
}
.redButton {
background: #ea0000;
}
.yellowButton {
background: #cacc00;
}
.redBackground {
background: #ea0000;
}
@@ -275,11 +283,19 @@ div.notice {
}
.itemLabel {
.itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest {
float: left;
width: 30%;
color: #e9c183;
}
.itemLabelNarrow {
width: 20%;
}
.itemLabel {
width: 30%;
}
.itemContent {
float: left;
width: 69%;
@@ -295,6 +311,13 @@ div.notice {
color: #e9c183;
}
.itemLabelWider {
width: 69%;
}
.itemLabelWidest {
width: 100%;
}
.itemContentWide {
float: left;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

After

Width:  |  Height:  |  Size: 571 KiB

+8
View File
@@ -48,6 +48,10 @@ NanoBaseHelpers = function ()
round: function(number) {
return Math.round(number);
},
// Returns the number fixed to 1 decimal
fixed: function(number) {
return Math.round(number * 10) / 10;
},
// Round a number down to integer
floor: function(number) {
return Math.floor(number);
@@ -83,6 +87,10 @@ NanoBaseHelpers = function ()
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
},
// Capitalize the first letter of a string. From http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
capitalizeFirstLetter: function(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
},
// Display a bar. Used to show health, capacity, etc.
displayBar: function(value, rangeMin, rangeMax, styleClass, showText) {
+3 -3
View File
@@ -6,11 +6,11 @@ Used In File(s): \code\game\machinery\computer\crew.dm
<table width="100%"><tbody>
{{for data.crewmembers}}
{{if value.sensor_type == 1}}
<tr><td>{{:value.name}}</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}}</td><td><span class="neutral">Not Available</span></td></tr>
<tr><td>{{:value.name}} ({{:value.assignment}})</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}}</td><td><span class="neutral">Not Available</span></td></tr>
{{else value.sensor_type == 2}}
<tr><td>{{:value.name}}</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}} (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>)</td><td><span class="neutral">Not Available</td></td></tr>
<tr><td>{{:value.name}} ({{:value.assignment}})</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}} (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>)</td><td><span class="neutral">Not Available</td></td></tr>
{{else value.sensor_type == 3}}
<tr><td>{{:value.name}}</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}} (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>)</td><td>{{:value.area}}({{:value.x}}, {{:value.y}})</td></tr>
<tr><td>{{:value.name}} ({{:value.assignment}})</td><td>{{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}} (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>)</td><td>{{:value.area}}({{:value.x}}, {{:value.y}})</td></tr>
{{/if}}
{{/for}}
</tbody></table>
+2 -2
View File
@@ -4,9 +4,9 @@ Used In File(s): \code\game\machinery\computer\crew.dm
-->
{{for data.crewmembers}}
{{if value.sensor_type == 3}}
<div class="mapIcon mapIcon16 rank-{{:value.rank.ckey()}} {{:value.dead ? 'dead' : 'alive'}}" style="left: {{:(value.x)}}px; bottom: {{:(value.y)}}px;" unselectable="on">
<div class="mapIcon mapIcon16 rank-{{:value.rank.ckey()}} {{:value.dead ? 'dead' : 'alive'}}" style="left: {{:(value.x)}}px; bottom: {{:(value.y - 1)}}px;" unselectable="on">
<div class="tooltip hidden">
{{:value.name}} ({{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}}) (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>) ({{:value.area}}: {{:value.x}}, {{:value.y}})
{{:value.name}} ({{:value.assignment}}) ({{:value.dead ? "<span class='bad'>Deceased</span>" : "<span class='good'>Living</span>"}}) (<span class="oxyloss">{{:value.oxy}}</span>/<span class="toxin">{{:value.tox}}</span>/<span class="burn">{{:value.fire}}</span>/<span class="brute">{{:value.brute}}</span>) ({{:value.area}}: {{:value.x}}, {{:value.y}})
</div>
</div>
{{/if}}
+71
View File
@@ -0,0 +1,71 @@
<style type="text/css">
.fixedCell {
width: 78px;
}
.fixedCellWide {
width: 120px;
}
.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
min-width: 70px;
margin: 0px 2px 0px 0px;
}
</style>
<div class="item">
<div class="itemLabelWider">
Main power is
{{if data.main_power_loss == 0}}
online
{{else data.main_power_loss == -1}}
offline
{{else}}
offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}}
{{/if}}.
</div>
<div class="itemContentNarrow">
{{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}}
</div>
</div>
<div class="item">
<div class="itemLabelWider">
Backup power is
{{if data.backup_power_loss == 0}}
online
{{else data.backup_power_loss == -1}}
offline
{{else}}
offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}}
{{/if}}.
</div>
<div class="itemContentNarrow">
{{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}}
</div>
</div>
<div class="item">
<div class="itemLabelWidest">
Electrified Status:
</div>
<div class="itemContentWidest">
{{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, null, data.electrified == 0 ? 'selected' : null)}}
{{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, null, data.electrified > 0 ? 'redButton' : null)}}
{{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, null, data.electrified == -1 ? 'redButton' : null)}}
</div>
</div>
<br>
<table>
{{for data.commands}}
<tr>
<td class='itemLabel fixedCellWide'>{{:value.name}}:</td>
<td class='fixedCell'>{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, null, value.active ? 'selected' : null)}}</td>
<td class='fixedCell'>{{:helper.link(value.disabled,null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, null,!value.active ? (value.danger ? 'redButton' : 'selected') : null)}}</td>
</tr>
{{/for}}
</table>
Binary file not shown.