| '+s.name+" | ";a+="
|---|
| ";var u=s.accesses;if(u)for(var d,p=-1,f=u.length-1;f>p;)d=u[p+=1],a+=""+n.link(d.name,d.req?"check-square-o":"square-o","set",{access:d.id},null,d.req?"selected":null)+" ";a+=" | "}return a+="
diff --git a/code/ATMOSPHERICS/components/unary_devices/cryo.dm b/code/ATMOSPHERICS/components/unary_devices/cryo.dm index 57785704c36..9674aa921e1 100644 --- a/code/ATMOSPHERICS/components/unary_devices/cryo.dm +++ b/code/ATMOSPHERICS/components/unary_devices/cryo.dm @@ -1,312 +1,312 @@ -/obj/machinery/atmospherics/components/unary/cryo_cell - name = "cryo cell" - icon = 'icons/obj/cryogenics.dmi' - icon_state = "cell-off" - density = 1 - anchored = 1 - layer = 4 - - var/on = 0 - var/temperature_archived - var/obj/item/weapon/reagent_containers/glass/beaker = null - var/next_trans = 0 - var/current_heat_capacity = 50 - state_open = 0 - var/efficiency = 1 - var/autoEject = 0 - -/obj/machinery/atmospherics/components/unary/cryo_cell/New() - ..() - initialize_directions = dir - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/cryo_tube(null) - component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/stack/cable_coil(null, 1) - - -/obj/machinery/atmospherics/components/unary/cryo_cell/construction() - ..(dir,dir) - -/obj/machinery/atmospherics/components/unary/cryo_cell/RefreshParts() - var/C - for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) - C += M.rating - current_heat_capacity = 50 * C - efficiency = C - -/obj/machinery/atmospherics/components/unary/cryo_cell/Destroy() - var/turf/T = loc - T.contents += contents - - if(beaker) - beaker.loc = get_step(loc, SOUTH) // Beaker is carefully ejected from the wreckage of the cryotube. - beaker = null - return ..() - -/obj/machinery/atmospherics/components/unary/cryo_cell/process_atmos() - ..() - var/datum/gas_mixture/air_contents = AIR1 - - if(air_contents) - temperature_archived = air_contents.temperature - heat_gas_contents() - if(abs(temperature_archived-air_contents.temperature) > 1) - update_parents() - -/obj/machinery/atmospherics/components/unary/cryo_cell/process() - ..() - if(occupant && occupant.health >= 100) - on = 0 - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - if(autoEject) - open_machine() - - if(!NODE1 || !is_operational()) - return - if(AIR1) - if(on && occupant) - process_occupant() - expel_gas() - - return 1 - -/obj/machinery/atmospherics/components/unary/cryo_cell/MouseDrop_T(mob/target, mob/user) - if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !iscarbon(target)) - return - close_machine(target) - -/obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/user) - return - -/obj/machinery/atmospherics/components/unary/cryo_cell/container_resist() - usr << "You struggle inside the cryotube, kicking the release with your foot." - sleep(150) - if(!src || !usr || (!occupant && !contents.Find(usr))) // Make sure they didn't disappear. - return - open_machine() - -/obj/machinery/atmospherics/components/unary/cryo_cell/examine(mob/user) - ..() - - var/list/otherstuff = contents - beaker - if(otherstuff.len > 0) - user << "You can just about make out some loose objects floating in the murk:" - for(var/atom/movable/floater in otherstuff) - user << "\icon[floater] [floater.name]" - else - user << "Seems empty." - -/obj/machinery/atmospherics/components/unary/cryo_cell/attack_hand(mob/user) - if(..() | !user) - return - interact(user) - -/obj/machinery/atmospherics/components/unary/cryo_cell/interact(mob/user) - if(panel_open) - return - ui_interact(user) - -/obj/machinery/atmospherics/components/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) - ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) - if (!ui) - ui = new(user, src, ui_key, "cryo", name, 520, 600, state = notcontained_state) - ui.open() - -/obj/machinery/atmospherics/components/unary/cryo_cell/get_ui_data() - // this is the data which will be sent to the ui - var/datum/gas_mixture/air_contents = AIR1 - - var/data = list() - data["isOperating"] = on - data["hasOccupant"] = occupant ? 1 : 0 - data["autoEject"] = autoEject - - var/occupantData = list() - if (!occupant) - occupantData["name"] = null - occupantData["stat"] = null - occupantData["health"] = null - occupantData["maxHealth"] = null - occupantData["minHealth"] = null - occupantData["bruteLoss"] = null - occupantData["oxyLoss"] = null - occupantData["toxLoss"] = null - occupantData["fireLoss"] = null - occupantData["bodyTemperature"] = null - else - occupantData["name"] = occupant.name - occupantData["stat"] = occupant.stat - occupantData["health"] = occupant.health - occupantData["maxHealth"] = occupant.maxHealth - occupantData["minHealth"] = config.health_threshold_dead - occupantData["bruteLoss"] = occupant.getBruteLoss() - occupantData["oxyLoss"] = occupant.getOxyLoss() - occupantData["toxLoss"] = occupant.getToxLoss() - occupantData["fireLoss"] = occupant.getFireLoss() - occupantData["bodyTemperature"] = occupant.bodytemperature - data["occupant"] = occupantData - - data["isOpen"] = state_open - data["cellTemperature"] = round(air_contents.temperature) - data["cellTemperatureStatus"] = "good" - if(air_contents.temperature > T0C) // if greater than 273.15 kelvin (0 celcius) - data["cellTemperatureStatus"] = "bad" - else if(air_contents.temperature > 225) - data["cellTemperatureStatus"] = "average" - - data["isBeakerLoaded"] = beaker ? 1 : 0 - var beakerContents[0] - if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... - data["beakerContents"] = beakerContents - return data - -/obj/machinery/atmospherics/components/unary/cryo_cell/ui_act(action, params) - if(..()) - return - - switch(action) - if("open") - open_machine() - if("close") - close_machine() - if("autoeject") - autoEject = !autoEject - if("on") - if(!state_open) - on = 1 - if("off") - on = 0 - if("ejectbeaker") - if(beaker) - beaker.loc = get_step(loc, SOUTH) - beaker = null - update_icon() - return 1 - -/obj/machinery/atmospherics/components/unary/cryo_cell/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/weapon/reagent_containers/glass)) - if(isrobot(user)) - return - if(beaker) - user << "A beaker is already loaded into [src]!" - return - if(!user.drop_item()) - return - - beaker = I - I.loc = src - user.visible_message("[user] places [I] in [src].", \ - "You place [I] in [src].") - - if(!(on || occupant || state_open)) - if(default_deconstruction_screwdriver(user, "cell-o", "cell-off", I)) - return - - if(default_change_direction_wrench(user, I)) - return - - if(exchange_parts(user, I)) - return - - if(default_pry_open(I)) - return - - default_deconstruction_crowbar(I) - -/obj/machinery/atmospherics/components/unary/cryo_cell/open_machine() - if(!state_open && !panel_open) - on = 0 - layer = 3 - if(occupant) - occupant.bodytemperature = Clamp(occupant.bodytemperature, 261, 360) - ..() - if(beaker) - beaker.loc = src - -/obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/M) - if(state_open && !panel_open) - layer = 4 - ..(M) - return occupant - -/obj/machinery/atmospherics/components/unary/cryo_cell/update_icon() - if(panel_open) - icon_state = "cell-o" - return - if(state_open) - icon_state = "cell-open" - return - if(on && is_operational()) - if(occupant) - icon_state = "cell-occupied" - else - icon_state = "cell-on" - else - icon_state = "cell-off" - -/obj/machinery/atmospherics/components/unary/cryo_cell/power_change() - ..() - update_icon() - -/obj/machinery/atmospherics/components/unary/cryo_cell/proc/process_occupant() - var/datum/gas_mixture/air_contents = AIR1 - if(!on) - return - if(air_contents.total_moles() < 10) - return - if(occupant) - if(occupant.stat == 2 || occupant.health >= 100) //Why waste energy on dead or healthy people - occupant.bodytemperature = T0C - return - occupant.bodytemperature += 2*(air_contents.temperature - occupant.bodytemperature) * current_heat_capacity / (current_heat_capacity + air_contents.heat_capacity()) - occupant.bodytemperature = max(occupant.bodytemperature, air_contents.temperature) // this is so ugly i'm sorry for doing it i'll fix it later i promise //TODO: fix someone else's broken promise - duncathan - if(occupant.bodytemperature < T0C) - occupant.sleeping = max(5 / efficiency, (1 / occupant.bodytemperature) * 2000 / efficiency) - occupant.Paralyse(max(5 / efficiency, (1 / occupant.bodytemperature) * 3000 / efficiency)) - if(air_contents.oxygen > 2) - if(occupant.getOxyLoss()) occupant.adjustOxyLoss(-1) - else - occupant.adjustOxyLoss(-1) - // Severe damage should heal waaay slower without proper chemicals... - if(occupant.bodytemperature < 225) - if(occupant.getToxLoss()) - occupant.adjustToxLoss(max(-efficiency, (-20*(efficiency ** 2)) / occupant.getToxLoss())) - var/heal_brute = occupant.getBruteLoss() ? min(efficiency, 20*(efficiency**2) / occupant.getBruteLoss()) : 0 - var/heal_fire = occupant.getFireLoss() ? min(efficiency, 20*(efficiency**2) / occupant.getFireLoss()) : 0 - occupant.heal_organ_damage(heal_brute, heal_fire) - if(beaker && next_trans == 0) - beaker.reagents.trans_to(occupant, 1, 10) - beaker.reagents.reaction(occupant, VAPOR) - next_trans++ - if(next_trans == 10) - next_trans = 0 - - -/obj/machinery/atmospherics/components/unary/cryo_cell/proc/heat_gas_contents() - var/datum/gas_mixture/air_contents = AIR1 - - if(air_contents.total_moles() < 1) - return - var/air_heat_capacity = air_contents.heat_capacity() - var/combined_heat_capacity = current_heat_capacity + air_heat_capacity - if(combined_heat_capacity > 0) - var/combined_energy = T20C * current_heat_capacity + air_heat_capacity * air_contents.temperature - air_contents.temperature = combined_energy/combined_heat_capacity - -/obj/machinery/atmospherics/components/unary/cryo_cell/proc/expel_gas() - var/datum/gas_mixture/air_contents = AIR1 - - if(air_contents.total_moles() < 1) - return - var/datum/gas_mixture/expel_gas = new - var/remove_amount = air_contents.total_moles() / 100 - expel_gas = air_contents.remove(remove_amount) - expel_gas.temperature = T20C //Lets expel hot gas and see if that helps people not die as they are removed - loc.assume_air(expel_gas) +/obj/machinery/atmospherics/components/unary/cryo_cell + name = "cryo cell" + icon = 'icons/obj/cryogenics.dmi' + icon_state = "cell-off" + density = 1 + anchored = 1 + layer = 4 + + var/on = 0 + var/temperature_archived + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/next_trans = 0 + var/current_heat_capacity = 50 + state_open = 0 + var/efficiency = 1 + var/autoEject = 0 + +/obj/machinery/atmospherics/components/unary/cryo_cell/New() + ..() + initialize_directions = dir + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/cryo_tube(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/stack/cable_coil(null, 1) + + +/obj/machinery/atmospherics/components/unary/cryo_cell/construction() + ..(dir,dir) + +/obj/machinery/atmospherics/components/unary/cryo_cell/RefreshParts() + var/C + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + C += M.rating + current_heat_capacity = 50 * C + efficiency = C + +/obj/machinery/atmospherics/components/unary/cryo_cell/Destroy() + var/turf/T = loc + T.contents += contents + + if(beaker) + beaker.loc = get_step(loc, SOUTH) // Beaker is carefully ejected from the wreckage of the cryotube. + beaker = null + return ..() + +/obj/machinery/atmospherics/components/unary/cryo_cell/process_atmos() + ..() + var/datum/gas_mixture/air_contents = AIR1 + + if(air_contents) + temperature_archived = air_contents.temperature + heat_gas_contents() + if(abs(temperature_archived-air_contents.temperature) > 1) + update_parents() + +/obj/machinery/atmospherics/components/unary/cryo_cell/process() + ..() + if(occupant && occupant.health >= 100) + on = 0 + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + if(autoEject) + open_machine() + + if(!NODE1 || !is_operational()) + return + if(AIR1) + if(on && occupant) + process_occupant() + expel_gas() + + return 1 + +/obj/machinery/atmospherics/components/unary/cryo_cell/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !iscarbon(target)) + return + close_machine(target) + +/obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/user) + return + +/obj/machinery/atmospherics/components/unary/cryo_cell/container_resist() + usr << "You struggle inside the cryotube, kicking the release with your foot." + sleep(150) + if(!src || !usr || (!occupant && !contents.Find(usr))) // Make sure they didn't disappear. + return + open_machine() + +/obj/machinery/atmospherics/components/unary/cryo_cell/examine(mob/user) + ..() + + var/list/otherstuff = contents - beaker + if(otherstuff.len > 0) + user << "You can just about make out some loose objects floating in the murk:" + for(var/atom/movable/floater in otherstuff) + user << "\icon[floater] [floater.name]" + else + user << "Seems empty." + +/obj/machinery/atmospherics/components/unary/cryo_cell/attack_hand(mob/user) + if(..() | !user) + return + interact(user) + +/obj/machinery/atmospherics/components/unary/cryo_cell/interact(mob/user) + if(panel_open) + return + ui_interact(user) + +/obj/machinery/atmospherics/components/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) + ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) + if (!ui) + ui = new(user, src, ui_key, "cryo", name, 410, 550, state = notcontained_state) + ui.open() + +/obj/machinery/atmospherics/components/unary/cryo_cell/get_ui_data() + // this is the data which will be sent to the ui + var/datum/gas_mixture/air_contents = AIR1 + + var/data = list() + data["isOperating"] = on + data["hasOccupant"] = occupant ? 1 : 0 + data["autoEject"] = autoEject + + var/occupantData = list() + if (!occupant) + occupantData["name"] = null + occupantData["stat"] = null + occupantData["health"] = null + occupantData["maxHealth"] = null + occupantData["minHealth"] = null + occupantData["bruteLoss"] = null + occupantData["oxyLoss"] = null + occupantData["toxLoss"] = null + occupantData["fireLoss"] = null + occupantData["bodyTemperature"] = null + else + occupantData["name"] = occupant.name + occupantData["stat"] = occupant.stat + occupantData["health"] = occupant.health + occupantData["maxHealth"] = occupant.maxHealth + occupantData["minHealth"] = config.health_threshold_dead + occupantData["bruteLoss"] = occupant.getBruteLoss() + occupantData["oxyLoss"] = occupant.getOxyLoss() + occupantData["toxLoss"] = occupant.getToxLoss() + occupantData["fireLoss"] = occupant.getFireLoss() + occupantData["bodyTemperature"] = occupant.bodytemperature + data["occupant"] = occupantData + + data["isOpen"] = state_open + data["cellTemperature"] = round(air_contents.temperature) + data["cellTemperatureStatus"] = "good" + if(air_contents.temperature > T0C) // if greater than 273.15 kelvin (0 celcius) + data["cellTemperatureStatus"] = "bad" + else if(air_contents.temperature > 225) + data["cellTemperatureStatus"] = "average" + + data["isBeakerLoaded"] = beaker ? 1 : 0 + var beakerContents[0] + if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) + for(var/datum/reagent/R in beaker.reagents.reagent_list) + beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + data["beakerContents"] = beakerContents + return data + +/obj/machinery/atmospherics/components/unary/cryo_cell/ui_act(action, params) + if(..()) + return + + switch(action) + if("open") + open_machine() + if("close") + close_machine() + if("autoeject") + autoEject = !autoEject + if("on") + if(!state_open) + on = 1 + if("off") + on = 0 + if("ejectbeaker") + if(beaker) + beaker.loc = get_step(loc, SOUTH) + beaker = null + update_icon() + return 1 + +/obj/machinery/atmospherics/components/unary/cryo_cell/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + if(isrobot(user)) + return + if(beaker) + user << "A beaker is already loaded into [src]!" + return + if(!user.drop_item()) + return + + beaker = I + I.loc = src + user.visible_message("[user] places [I] in [src].", \ + "You place [I] in [src].") + + if(!(on || occupant || state_open)) + if(default_deconstruction_screwdriver(user, "cell-o", "cell-off", I)) + return + + if(default_change_direction_wrench(user, I)) + return + + if(exchange_parts(user, I)) + return + + if(default_pry_open(I)) + return + + default_deconstruction_crowbar(I) + +/obj/machinery/atmospherics/components/unary/cryo_cell/open_machine() + if(!state_open && !panel_open) + on = 0 + layer = 3 + if(occupant) + occupant.bodytemperature = Clamp(occupant.bodytemperature, 261, 360) + ..() + if(beaker) + beaker.loc = src + +/obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/M) + if(state_open && !panel_open) + layer = 4 + ..(M) + return occupant + +/obj/machinery/atmospherics/components/unary/cryo_cell/update_icon() + if(panel_open) + icon_state = "cell-o" + return + if(state_open) + icon_state = "cell-open" + return + if(on && is_operational()) + if(occupant) + icon_state = "cell-occupied" + else + icon_state = "cell-on" + else + icon_state = "cell-off" + +/obj/machinery/atmospherics/components/unary/cryo_cell/power_change() + ..() + update_icon() + +/obj/machinery/atmospherics/components/unary/cryo_cell/proc/process_occupant() + var/datum/gas_mixture/air_contents = AIR1 + if(!on) + return + if(air_contents.total_moles() < 10) + return + if(occupant) + if(occupant.stat == 2 || occupant.health >= 100) //Why waste energy on dead or healthy people + occupant.bodytemperature = T0C + return + occupant.bodytemperature += 2*(air_contents.temperature - occupant.bodytemperature) * current_heat_capacity / (current_heat_capacity + air_contents.heat_capacity()) + occupant.bodytemperature = max(occupant.bodytemperature, air_contents.temperature) // this is so ugly i'm sorry for doing it i'll fix it later i promise //TODO: fix someone else's broken promise - duncathan + if(occupant.bodytemperature < T0C) + occupant.sleeping = max(5 / efficiency, (1 / occupant.bodytemperature) * 2000 / efficiency) + occupant.Paralyse(max(5 / efficiency, (1 / occupant.bodytemperature) * 3000 / efficiency)) + if(air_contents.oxygen > 2) + if(occupant.getOxyLoss()) occupant.adjustOxyLoss(-1) + else + occupant.adjustOxyLoss(-1) + // Severe damage should heal waaay slower without proper chemicals... + if(occupant.bodytemperature < 225) + if(occupant.getToxLoss()) + occupant.adjustToxLoss(max(-efficiency, (-20*(efficiency ** 2)) / occupant.getToxLoss())) + var/heal_brute = occupant.getBruteLoss() ? min(efficiency, 20*(efficiency**2) / occupant.getBruteLoss()) : 0 + var/heal_fire = occupant.getFireLoss() ? min(efficiency, 20*(efficiency**2) / occupant.getFireLoss()) : 0 + occupant.heal_organ_damage(heal_brute, heal_fire) + if(beaker && next_trans == 0) + beaker.reagents.trans_to(occupant, 1, 10) + beaker.reagents.reaction(occupant, VAPOR) + next_trans++ + if(next_trans == 10) + next_trans = 0 + + +/obj/machinery/atmospherics/components/unary/cryo_cell/proc/heat_gas_contents() + var/datum/gas_mixture/air_contents = AIR1 + + if(air_contents.total_moles() < 1) + return + var/air_heat_capacity = air_contents.heat_capacity() + var/combined_heat_capacity = current_heat_capacity + air_heat_capacity + if(combined_heat_capacity > 0) + var/combined_energy = T20C * current_heat_capacity + air_heat_capacity * air_contents.temperature + air_contents.temperature = combined_energy/combined_heat_capacity + +/obj/machinery/atmospherics/components/unary/cryo_cell/proc/expel_gas() + var/datum/gas_mixture/air_contents = AIR1 + + if(air_contents.total_moles() < 1) + return + var/datum/gas_mixture/expel_gas = new + var/remove_amount = air_contents.total_moles() / 100 + expel_gas = air_contents.remove(remove_amount) + expel_gas.temperature = T20C //Lets expel hot gas and see if that helps people not die as they are removed + loc.assume_air(expel_gas) air_update_turf() \ No newline at end of file diff --git a/code/datums/mind.dm b/code/datums/mind.dm index e68c5d08c52..c565740299b 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -68,7 +68,7 @@ if(current) //remove ourself from our old body's mind variable current.mind = null - SSnano.user_transferred(current, new_character) + SSnano.on_transfer(current, new_character) if(key) if(new_character.key != key) //if we're transfering into a body with a key associated which is not ours diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 91198db5fe4..630da54c790 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -1,240 +1,233 @@ -/* -Asset cache quick users guide: - -Make a datum at the bottom of this file with your assets for your thing. -The simple subsystem will most like be of use for most cases. -Then call get_asset_datum() with the type of the datum you created and store the return -Then call .send(client) on that stored return value. - -You can set verify to TRUE if you want send() to sleep until the client has the assets. -*/ - - -// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping. -// This is doubled for the first asset, then added per asset after -#define ASSET_CACHE_SEND_TIMEOUT 7 - -//When sending mutiple assets, how many before we give the client a quaint little sending resources message -#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 - -/client - var/list/cache = list() // List of all assets sent to this client by the asset cache. - var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement. - var/list/sending = list() - var/last_asset_job = 0 // Last job done. - -//This proc sends the asset to the client, but only if it needs it. -//This proc blocks(sleeps) unless verify is set to false -/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE) - if(!istype(client)) - if(ismob(client)) - var/mob/M = client - if(M.client) - client = M.client - - else - return 0 - - else - return 0 - - if(client.cache.Find(asset_name) || client.sending.Find(asset_name)) - return 0 - - client << browse_rsc(SSasset.cache[asset_name], asset_name) - if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. - if (client) - client.cache += asset_name - return 1 - if (!client) - return 0 - - client.sending |= asset_name - var/job = ++client.last_asset_job - - client << browse({" - - "}, "window=asset_cache_browser") - - var/t = 0 - var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT - while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() - sleep(1) // Lock up the caller until this is received. - t++ - - if(client) - client.sending -= asset_name - client.cache |= asset_name - client.completed_asset_jobs -= job - - return 1 - -//This proc blocks(sleeps) unless verify is set to false -/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE) - if(!istype(client)) - if(ismob(client)) - var/mob/M = client - if(M.client) - client = M.client - - else - return 0 - - else - return 0 - - var/list/unreceived = asset_list - (client.cache + client.sending) - if(!unreceived || !unreceived.len) - return 0 - if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT) - client << "Sending Resources..." - for(var/asset in unreceived) - if (asset in SSasset.cache) - client << browse_rsc(SSasset.cache[asset], asset) - - if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. - if (client) - client.cache += unreceived - return 1 - if (!client) - return 0 - client.sending |= unreceived - var/job = ++client.last_asset_job - - client << browse({" - - "}, "window=asset_cache_browser") - - var/t = 0 - var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len - while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() - sleep(1) // Lock up the caller until this is received. - t++ - - if(client) - client.sending -= unreceived - client.cache |= unreceived - client.completed_asset_jobs -= job - - return 1 - -//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start. -//The proc calls procs that sleep for long times. -/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE) - for(var/file in files) - if (!client) - break - if (register_asset) - register_asset(file,files[file]) - send_asset(client,file) - sleep(-1) //queuing calls like this too quickly can cause issues in some client versions - -//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up. -//if it's an icon or something be careful, you'll have to copy it before further use. -/proc/register_asset(var/asset_name, var/asset) - SSasset.cache[asset_name] = asset - -//These datums are used to populate the asset cache, the proc "register()" does this. - -//all of our asset datums, used for referring to these later -/var/global/list/asset_datums = list() - -//get a assetdatum or make a new one -/proc/get_asset_datum(var/type) - if (!(type in asset_datums)) - return new type() - return asset_datums[type] - -/datum/asset/New() - asset_datums[type] = src - -/datum/asset/proc/register() - return - -/datum/asset/proc/send(client) - return - -//If you don't need anything complicated. -/datum/asset/simple - var/assets = list() - var/verify = FALSE - -/datum/asset/simple/register() - for(var/asset_name in assets) - register_asset(asset_name, assets[asset_name]) -/datum/asset/simple/send(client) - send_asset_list(client,assets,verify) - - -//DEFINITIONS FOR ASSET DATUMS START HERE. - - -/datum/asset/simple/nanoui - assets = list( - "nanoui.lib.js" = 'nano/assets/nanoui.lib.js', - "nanoui.main.js" = 'nano/assets/nanoui.main.js', - "nanoui.templates.js" = 'nano/assets/nanoui.templates.js', - "nanoui.lib.css" = 'nano/assets/nanoui.lib.css', - "nanoui.common.css" = 'nano/assets/nanoui.common.css', - "nanoui.generic.css" = 'nano/assets/nanoui.generic.css', - "nanoui.nanotrasen.css" = 'nano/assets/nanoui.nanotrasen.css', - "fontawesome-webfont.eot" = 'nano/assets/fontawesome-webfont.eot', - "fontawesome-webfont.woff2" = 'nano/assets/fontawesome-webfont.woff2' - ) - -/datum/asset/simple/pda - assets = list( - "pda_atmos.png" = 'icons/pda_icons/pda_atmos.png', - "pda_back.png" = 'icons/pda_icons/pda_back.png', - "pda_bell.png" = 'icons/pda_icons/pda_bell.png', - "pda_blank.png" = 'icons/pda_icons/pda_blank.png', - "pda_boom.png" = 'icons/pda_icons/pda_boom.png', - "pda_bucket.png" = 'icons/pda_icons/pda_bucket.png', - "pda_medbot.png" = 'icons/pda_icons/pda_medbot.png', - "pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png', - "pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png', - "pda_crate.png" = 'icons/pda_icons/pda_crate.png', - "pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png', - "pda_eject.png" = 'icons/pda_icons/pda_eject.png', - "pda_exit.png" = 'icons/pda_icons/pda_exit.png', - "pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png', - "pda_honk.png" = 'icons/pda_icons/pda_honk.png', - "pda_mail.png" = 'icons/pda_icons/pda_mail.png', - "pda_medical.png" = 'icons/pda_icons/pda_medical.png', - "pda_menu.png" = 'icons/pda_icons/pda_menu.png', - "pda_mule.png" = 'icons/pda_icons/pda_mule.png', - "pda_notes.png" = 'icons/pda_icons/pda_notes.png', - "pda_power.png" = 'icons/pda_icons/pda_power.png', - "pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png', - "pda_reagent.png" = 'icons/pda_icons/pda_reagent.png', - "pda_refresh.png" = 'icons/pda_icons/pda_refresh.png', - "pda_scanner.png" = 'icons/pda_icons/pda_scanner.png', - "pda_signaler.png" = 'icons/pda_icons/pda_signaler.png', - "pda_status.png" = 'icons/pda_icons/pda_status.png' - ) - -/datum/asset/simple/paper - assets = list( - "large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png', - "large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png', - "large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png', - "large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png', - "large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png', - "large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png', - "large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png', - "large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png', - "large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png', - "large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png', - "large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png' - ) - - -//Registers HTML Interface assets. -/datum/asset/HTML_interface/register() - for(var/path in typesof(/datum/html_interface)) - var/datum/html_interface/hi = new path() - hi.registerResources() +/* +Asset cache quick users guide: + +Make a datum at the bottom of this file with your assets for your thing. +The simple subsystem will most like be of use for most cases. +Then call get_asset_datum() with the type of the datum you created and store the return +Then call .send(client) on that stored return value. + +You can set verify to TRUE if you want send() to sleep until the client has the assets. +*/ + + +// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping. +// This is doubled for the first asset, then added per asset after +#define ASSET_CACHE_SEND_TIMEOUT 7 + +//When sending mutiple assets, how many before we give the client a quaint little sending resources message +#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 + +/client + var/list/cache = list() // List of all assets sent to this client by the asset cache. + var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement. + var/list/sending = list() + var/last_asset_job = 0 // Last job done. + +//This proc sends the asset to the client, but only if it needs it. +//This proc blocks(sleeps) unless verify is set to false +/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE) + if(!istype(client)) + if(ismob(client)) + var/mob/M = client + if(M.client) + client = M.client + + else + return 0 + + else + return 0 + + if(client.cache.Find(asset_name) || client.sending.Find(asset_name)) + return 0 + + client << browse_rsc(SSasset.cache[asset_name], asset_name) + if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. + if (client) + client.cache += asset_name + return 1 + if (!client) + return 0 + + client.sending |= asset_name + var/job = ++client.last_asset_job + + client << browse({" + + "}, "window=asset_cache_browser") + + var/t = 0 + var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT + while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() + sleep(1) // Lock up the caller until this is received. + t++ + + if(client) + client.sending -= asset_name + client.cache |= asset_name + client.completed_asset_jobs -= job + + return 1 + +//This proc blocks(sleeps) unless verify is set to false +/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE) + if(!istype(client)) + if(ismob(client)) + var/mob/M = client + if(M.client) + client = M.client + + else + return 0 + + else + return 0 + + var/list/unreceived = asset_list - (client.cache + client.sending) + if(!unreceived || !unreceived.len) + return 0 + if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT) + client << "Sending Resources..." + for(var/asset in unreceived) + if (asset in SSasset.cache) + client << browse_rsc(SSasset.cache[asset], asset) + + if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip. + if (client) + client.cache += unreceived + return 1 + if (!client) + return 0 + client.sending |= unreceived + var/job = ++client.last_asset_job + + client << browse({" + + "}, "window=asset_cache_browser") + + var/t = 0 + var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len + while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() + sleep(1) // Lock up the caller until this is received. + t++ + + if(client) + client.sending -= unreceived + client.cache |= unreceived + client.completed_asset_jobs -= job + + return 1 + +//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start. +//The proc calls procs that sleep for long times. +/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE) + for(var/file in files) + if (!client) + break + if (register_asset) + register_asset(file,files[file]) + send_asset(client,file) + sleep(-1) //queuing calls like this too quickly can cause issues in some client versions + +//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up. +//if it's an icon or something be careful, you'll have to copy it before further use. +/proc/register_asset(var/asset_name, var/asset) + SSasset.cache[asset_name] = asset + +//These datums are used to populate the asset cache, the proc "register()" does this. + +//all of our asset datums, used for referring to these later +/var/global/list/asset_datums = list() + +//get a assetdatum or make a new one +/proc/get_asset_datum(var/type) + if (!(type in asset_datums)) + return new type() + return asset_datums[type] + +/datum/asset/New() + asset_datums[type] = src + +/datum/asset/proc/register() + return + +/datum/asset/proc/send(client) + return + +//If you don't need anything complicated. +/datum/asset/simple + var/assets = list() + var/verify = FALSE + +/datum/asset/simple/register() + for(var/asset_name in assets) + register_asset(asset_name, assets[asset_name]) +/datum/asset/simple/send(client) + send_asset_list(client,assets,verify) + + +//DEFINITIONS FOR ASSET DATUMS START HERE. + + +/datum/asset/simple/nanoui + assets = list( + "nanoui.js" = 'nano/assets/nanoui.js', + "nanoui.css" = 'nano/assets/nanoui.css', + ) + +/datum/asset/simple/pda + assets = list( + "pda_atmos.png" = 'icons/pda_icons/pda_atmos.png', + "pda_back.png" = 'icons/pda_icons/pda_back.png', + "pda_bell.png" = 'icons/pda_icons/pda_bell.png', + "pda_blank.png" = 'icons/pda_icons/pda_blank.png', + "pda_boom.png" = 'icons/pda_icons/pda_boom.png', + "pda_bucket.png" = 'icons/pda_icons/pda_bucket.png', + "pda_medbot.png" = 'icons/pda_icons/pda_medbot.png', + "pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png', + "pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png', + "pda_crate.png" = 'icons/pda_icons/pda_crate.png', + "pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png', + "pda_eject.png" = 'icons/pda_icons/pda_eject.png', + "pda_exit.png" = 'icons/pda_icons/pda_exit.png', + "pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png', + "pda_honk.png" = 'icons/pda_icons/pda_honk.png', + "pda_mail.png" = 'icons/pda_icons/pda_mail.png', + "pda_medical.png" = 'icons/pda_icons/pda_medical.png', + "pda_menu.png" = 'icons/pda_icons/pda_menu.png', + "pda_mule.png" = 'icons/pda_icons/pda_mule.png', + "pda_notes.png" = 'icons/pda_icons/pda_notes.png', + "pda_power.png" = 'icons/pda_icons/pda_power.png', + "pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png', + "pda_reagent.png" = 'icons/pda_icons/pda_reagent.png', + "pda_refresh.png" = 'icons/pda_icons/pda_refresh.png', + "pda_scanner.png" = 'icons/pda_icons/pda_scanner.png', + "pda_signaler.png" = 'icons/pda_icons/pda_signaler.png', + "pda_status.png" = 'icons/pda_icons/pda_status.png' + ) + +/datum/asset/simple/paper + assets = list( + "large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png', + "large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png', + "large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png', + "large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png', + "large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png', + "large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png', + "large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png', + "large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png', + "large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png', + "large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png', + "large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png' + ) + + +//Registers HTML Interface assets. +/datum/asset/HTML_interface/register() + for(var/path in typesof(/datum/html_interface)) + var/datum/html_interface/hi = new path() + hi.registerResources() diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index 4c7da6069be..f1bc6dcabcc 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -1,5 +1,5 @@ /mob/Logout() - SSnano.user_logout(src) // this is used to clean up (remove) this user's Nano UIs + SSnano.on_logout(src) player_list -= src log_access("Logout: [key_name(src)]") if(admin_datums[src.ckey]) diff --git a/code/modules/nano/external.dm b/code/modules/nano/external.dm index bd72394934e..fcf1a4cf4d4 100644 --- a/code/modules/nano/external.dm +++ b/code/modules/nano/external.dm @@ -27,6 +27,20 @@ datum/topic_state/state = default_state) return -1 // Sorta implemented. + /** + * public + * + * Data to be sent to the NanoUI. + * This must be implemented for a NanoUI to work. + * + * required user mob The mob interacting with the NanoUI. + * + * return list Data to be sent to the NanoUI. + **/ +/atom/movable/proc/get_ui_data(mob/user) + return list() // Not implemented. + + /** * public * @@ -41,18 +55,6 @@ /atom/movable/proc/ui_act(action, list/params) return // Not implemented. - /** - * public - * - * Data to be sent to the NanoUI. - * This must be implemented for a NanoUI to work. - * - * required user mob The mob interacting with the NanoUI. - * - * return list Data to be sent to the NanoUI. - **/ -/atom/movable/proc/get_ui_data(mob/user) - return list() // Not implemented. /** * private @@ -67,7 +69,6 @@ * global * * Used to track NanoUIs for a mob. - * **/ /mob/var/list/open_uis = list() diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 076d8baba53..b2b76fdf2f5 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -1,405 +1,403 @@ - /** - * NanoUI - * - * Contains the NanoUI datum, and its procs. - * - * /tg/station user interface library - * thanks to baystation12 - * - * modified by neersighted - **/ - - /** - * NanoUI datum: - * - * Represents a NanoUI. - **/ -/datum/nanoui - var/mob/user // The mob who opened/is using the NanoUI. - var/atom/movable/src_object // The object which owns the NanoUI. - var/title // The title of te NanoUI. - var/ui_key // The ui_key of the NanoUI. This allows multiple UIs for one src_object. - var/window_id // The window_id for browse() and onclose(). - var/width = 0 // The window width. - var/height = 0 // The window height - var/window_options = list( // Extra options to winset(). - "focus" = 0, - "titlebar" = 1, - "can_resize" = 1, - "can_minimize" = 1, - "can_maximize" = 0, - "can_close" = 1, - "auto_format" = 0 - ) - var/atom/ref = null // An extra ref to call when the window is closed. - var/layout = "nanotrasen" // The layout to be used for this UI. - var/template // The template to be used for this UI. - var/auto_update = 1 // Update the NanoUI every MC tick. - var/list/initial_data // The data (and datastructure) used to initialize the NanoUI - var/status = NANO_INTERACTIVE // The status/visibility of the NanoUI. - var/datum/topic_state/state = null // Topic state used to determine status. Topic states are in interactions/. - var/datum/nanoui/master_ui // The parent NanoUI. - var/list/datum/nanoui/children = list() // Children of this NanoUI. - - /** - * public - * - * Create a new NanoUI. - * - * required user mob The mob who opened/is using the NanoUI. - * required src_object atom/movable The object which owns the NanoUI. - * required ui_key string The ui_key of the NanoUI. - * required template string The template to render the NanoUI content with. - * optional title string The title of the NanoUI. - * optional width int The window width. - * optional height int The window height. - * optional ref atom An extra ref to use when the window is closed. - * optional master_ui datum/nanoui The parent NanoUI. - * optional state datum/topic_state The state used to determine status. - * - * return datum/nanoui The requested NanoUI. - **/ -/datum/nanoui/New(mob/user, atom/movable/src_object, ui_key, template, \ - title = 0, width = 0, height = 0, \ - atom/ref = null, datum/nanoui/master_ui = null, \ - datum/topic_state/state = default_state) - src.user = user - src.src_object = src_object - src.ui_key = ui_key - src.window_id = "\ref[src_object]-[ui_key]" - - set_template(template) - - if (title) - src.title = sanitize(title) - if (width) - src.width = width - if (height) - src.height = height - - if (ref) - src.ref = ref - - src.master_ui = master_ui - if(master_ui) - master_ui.children += src - src.state = state - - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/nanoui) - assets.send(user) - - - /** - * public - * - * Enable/disable auto-updating of the NanoUI. - * - * required state bool Enable/disable auto-updating. - **/ -/datum/nanoui/proc/set_auto_update(state = 1) - auto_update = state - - /** - * private - * - * Set the data to initialize the NanoUI with. - * The datastructure cannot be changed by subsequent updates. - * - * optional data list The data/datastructure to initialize the NanoUI with. - **/ -/datum/nanoui/proc/set_initial_data(list/data) - initial_data = data - - /** - * private - * - * Get the config data/datastructure to initialize the NanoUI with. - * - * return list The config data. - **/ -/datum/nanoui/proc/get_config_data() - var/list/config_data = list( - "title" = title, - "status" = status, - "ref" = "\ref[src]", - "window" = list( - "width" = width, - "height" = height, - "ref" = window_id - ), - "user" = list( - "name" = user.name, - "fancy" = user.client.prefs.nanoui_fancy, - "ref" = "\ref[user]" - ), - "srcObject" = list( - "name" = src_object.name, - "ref" = "\ref[src_object]" - ), - "templates" = list( - "layout" = "_[layout]", - "content" = "[template]" - ) - ) - return config_data - - /** - * private - * - * Package the data to send to the UI. - * This is the (regular) data and config data, bundled together. - * - * return list The packaged data. - **/ -/datum/nanoui/proc/get_send_data(list/data) - var/list/send_data = list() - - send_data["config"] = get_config_data() - if (!isnull(data)) - send_data["data"] = data - - return send_data - - /** - * public - * - * Sets the browse() window options for this NanoUI. - * - * required window_options list The window options to set. - **/ -/datum/nanoui/proc/set_window_options(list/window_options) - src.window_options = window_options - - /** - * public - * - * Set the layout for this NanoUI. - * This loads custom layout styles and templates for this NanoUI. - * - * required layout string The new UI layout. - **/ -/datum/nanoui/proc/set_layout(layout) - src.layout = lowertext(layout) - - /** - * public - * - * Set the template for this NanoUI. - * - * required template string The new UI template. - **/ -/datum/nanoui/proc/set_template(template) - src.template = lowertext(template) - - /** - * private - * - * Generate HTML for this NanoUI. - * - * return string NanoUI HTML output. - **/ -/datum/nanoui/proc/get_html() - // Generate - - - "} - var/stylesheet_html = {" - - - - - "} - - // Generate JSON. - var/list/send_data = get_send_data(initial_data) - var/initial_data_json = replacetext(JSON.stringify(send_data), "'", "\\'") - - // Generate the HTML document. - return {" - - -
- - - [stylesheet_html] - [script_html] - - - -| '+s.name+" | ";a+="
|---|
| ";var u=s.accesses;if(u)for(var d,p=-1,f=u.length-1;f>p;)d=u[p+=1],a+=""+n.link(d.name,d.req?"check-square-o":"square-o","set",{access:d.id},null,d.req?"selected":null)+" ";a+=" | "}return a+="