Merged with dev.

This commit is contained in:
Zuhayr
2015-02-24 17:03:39 +10:30
97 changed files with 2517 additions and 1727 deletions

View File

@@ -93,14 +93,15 @@
#include "code\controllers\lighting_controller.dm"
#include "code\controllers\master_controller.dm"
#include "code\controllers\shuttle_controller.dm"
#include "code\controllers\subsystems.dm"
#include "code\controllers\verbs.dm"
#include "code\controllers\voting.dm"
#include "code\controllers\subsystem\alarms.dm"
#include "code\datums\ai_laws.dm"
#include "code\datums\browser.dm"
#include "code\datums\computerfiles.dm"
#include "code\datums\datacore.dm"
#include "code\datums\datumvars.dm"
#include "code\datums\descriptions.dm"
#include "code\datums\disease.dm"
#include "code\datums\mind.dm"
#include "code\datums\mixed.dm"
@@ -808,6 +809,13 @@
#include "code\modules\admin\verbs\ticklag.dm"
#include "code\modules\admin\verbs\tripAI.dm"
#include "code\modules\admin\verbs\vox_raiders.dm"
#include "code\modules\alarm\alarm.dm"
#include "code\modules\alarm\alarm_handler.dm"
#include "code\modules\alarm\atmosphere_alarm.dm"
#include "code\modules\alarm\camera_alarm.dm"
#include "code\modules\alarm\fire_alarm.dm"
#include "code\modules\alarm\motion_alarm.dm"
#include "code\modules\alarm\power_alarm.dm"
#include "code\modules\assembly\assembly.dm"
#include "code\modules\assembly\bomb.dm"
#include "code\modules\assembly\helpers.dm"
@@ -953,6 +961,13 @@
#include "code\modules\events\spontaneous_appendicitis.dm"
#include "code\modules\events\viral_infection.dm"
#include "code\modules\events\wallrot.dm"
#include "code\modules\examine\examine.dm"
#include "code\modules\examine\descriptions\atmospherics.dm"
#include "code\modules\examine\descriptions\engineering.dm"
#include "code\modules\examine\descriptions\mobs.dm"
#include "code\modules\examine\descriptions\stacks.dm"
#include "code\modules\examine\descriptions\structures.dm"
#include "code\modules\examine\descriptions\turfs.dm"
#include "code\modules\ext_scripts\irc.dm"
#include "code\modules\ext_scripts\python.dm"
#include "code\modules\flufftext\Dreaming.dm"
@@ -1130,7 +1145,6 @@
#include "code\modules\mob\living\carbon\monkey\login.dm"
#include "code\modules\mob\living\carbon\monkey\monkey.dm"
#include "code\modules\mob\living\carbon\monkey\update_icons.dm"
#include "code\modules\mob\living\silicon\alarm.dm"
#include "code\modules\mob\living\silicon\death.dm"
#include "code\modules\mob\living\silicon\laws.dm"
#include "code\modules\mob\living\silicon\login.dm"
@@ -1144,8 +1158,8 @@
#include "code\modules\mob\living\silicon\ai\life.dm"
#include "code\modules\mob\living\silicon\ai\login.dm"
#include "code\modules\mob\living\silicon\ai\logout.dm"
#include "code\modules\mob\living\silicon\ai\nano.dm"
#include "code\modules\mob\living\silicon\ai\say.dm"
#include "code\modules\mob\living\silicon\ai\subsystems.dm"
#include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm"
#include "code\modules\mob\living\silicon\ai\freelook\chunk.dm"
#include "code\modules\mob\living\silicon\ai\freelook\eye.dm"
@@ -1178,6 +1192,7 @@
#include "code\modules\mob\living\silicon\robot\robot_items.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules.dm"
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\subsystems.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_console.dm"
@@ -1236,6 +1251,7 @@
#include "code\modules\nano\nanomanager.dm"
#include "code\modules\nano\nanomapgen.dm"
#include "code\modules\nano\nanoui.dm"
#include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\crew_monitor.dm"
#include "code\modules\nano\modules\power_monitor.dm"
#include "code\modules\nano\modules\rcon.dm"

View File

@@ -383,6 +383,7 @@
user << "You are too far away to read the gauge."
if(welded)
user << "It seems welded shut."
..()
/obj/machinery/atmospherics/unary/vent_pump/power_change()
var/old_stat = stat

View File

@@ -277,6 +277,7 @@
user << "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W"
else
user << "You are too far away to read the gauge."
..()
/obj/machinery/atmospherics/unary/vent_scrubber/Del()
if(initial_loc)

View File

@@ -491,5 +491,8 @@ datum/projectile_data
temps[direction] = rstats
return temps
/proc/MinutesToTicks(var/minutes as num)
return minutes * 60 * 10
/proc/MinutesToTicks(var/minutes)
return SecondsToTicks(60 * minutes)
/proc/SecondsToTicks(var/seconds)
return seconds * 10

View File

@@ -596,3 +596,7 @@ datum/proc/dd_SortValue()
/obj/machinery/camera/dd_SortValue()
return "[c_tag]"
/datum/alarm/dd_SortValue()
return "[sanitize(last_name)]"

View File

@@ -256,59 +256,99 @@ datum/hud/New(mob/owner)
set name = "F12"
set hidden = 1
if(hud_used)
if(ishuman(src))
if(!client) return
if(client.view != world.view)
return
if(hud_used.hud_shown)
hud_used.hud_shown = 0
if(src.hud_used.adding)
src.client.screen -= src.hud_used.adding
if(src.hud_used.other)
src.client.screen -= src.hud_used.other
if(src.hud_used.hotkeybuttons)
src.client.screen -= src.hud_used.hotkeybuttons
if(src.hud_used.item_action_list)
src.client.screen -= src.hud_used.item_action_list
//Due to some poor coding some things need special treatment:
//These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
if(!full)
src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
else
src.client.screen -= src.healths
src.client.screen -= src.internals
src.client.screen -= src.gun_setting_icon
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason.
else
hud_used.hud_shown = 1
if(src.hud_used.adding)
src.client.screen += src.hud_used.adding
if(src.hud_used.other && src.hud_used.inventory_shown)
src.client.screen += src.hud_used.other
if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
src.client.screen += src.hud_used.hotkeybuttons
if(src.healths)
src.client.screen |= src.healths
if(src.internals)
src.client.screen |= src.internals
if(src.gun_setting_icon)
src.client.screen |= src.gun_setting_icon
src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
src.client.screen += src.zone_sel //This one is a special snowflake
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
update_action_buttons()
else
usr << "\red Inventory hiding is currently only supported for human mobs, sorry."
else
if(!hud_used)
usr << "\red This mob type does not use a HUD."
return
if(!ishuman(src))
usr << "\red Inventory hiding is currently only supported for human mobs, sorry."
return
if(!client) return
if(client.view != world.view)
return
if(hud_used.hud_shown)
hud_used.hud_shown = 0
if(src.hud_used.adding)
src.client.screen -= src.hud_used.adding
if(src.hud_used.other)
src.client.screen -= src.hud_used.other
if(src.hud_used.hotkeybuttons)
src.client.screen -= src.hud_used.hotkeybuttons
if(src.hud_used.item_action_list)
src.client.screen -= src.hud_used.item_action_list
//Due to some poor coding some things need special treatment:
//These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
if(!full)
src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
else
src.client.screen -= src.healths
src.client.screen -= src.internals
src.client.screen -= src.gun_setting_icon
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason.
else
hud_used.hud_shown = 1
if(src.hud_used.adding)
src.client.screen += src.hud_used.adding
if(src.hud_used.other && src.hud_used.inventory_shown)
src.client.screen += src.hud_used.other
if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
src.client.screen += src.hud_used.hotkeybuttons
if(src.healths)
src.client.screen |= src.healths
if(src.internals)
src.client.screen |= src.internals
if(src.gun_setting_icon)
src.client.screen |= src.gun_setting_icon
src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
src.client.screen += src.zone_sel //This one is a special snowflake
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
update_action_buttons()
//Similar to button_pressed_F12() but keeps zone_sel, gun_setting_icon, and healths.
/mob/proc/toggle_zoom_hud()
if(!hud_used)
return
if(!ishuman(src))
return
if(!client)
return
if(client.view != world.view)
return
if(hud_used.hud_shown)
hud_used.hud_shown = 0
if(src.hud_used.adding)
src.client.screen -= src.hud_used.adding
if(src.hud_used.other)
src.client.screen -= src.hud_used.other
if(src.hud_used.hotkeybuttons)
src.client.screen -= src.hud_used.hotkeybuttons
if(src.hud_used.item_action_list)
src.client.screen -= src.hud_used.item_action_list
src.client.screen -= src.internals
else
hud_used.hud_shown = 1
if(src.hud_used.adding)
src.client.screen += src.hud_used.adding
if(src.hud_used.other && src.hud_used.inventory_shown)
src.client.screen += src.hud_used.other
if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
src.client.screen += src.hud_used.hotkeybuttons
if(src.internals)
src.client.screen |= src.internals
src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
hud_used.hidden_inventory_update()
hud_used.persistant_inventory_update()
update_action_buttons()

View File

@@ -182,6 +182,8 @@
var/dooc_allowed = 1
var/dsay_allowed = 1
var/starlight = 0 // Whether space turfs have ambient light or not
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -603,6 +605,9 @@
config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2])
config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3])
if("starlight")
config.starlight = 1
else
log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -26,6 +26,7 @@ datum/controller/game_controller
var/powernets_cost = 0
var/nano_cost = 0
var/events_cost = 0
var/alarms_cost = 0
var/ticker_cost = 0
var/total_cost = 0
@@ -231,6 +232,11 @@ datum/controller/game_controller/proc/process()
process_events()
events_cost = (world.timeofday - timer) / 10
//ALARMS
timer = world.timeofday
process_alarms()
alarms_cost = (world.timeofday - timer) / 10
//TICKER
timer = world.timeofday
last_thing_processed = ticker.type
@@ -238,7 +244,7 @@ datum/controller/game_controller/proc/process()
ticker_cost = (world.timeofday - timer) / 10
//TIMING
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + ticker_cost
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + alarms_cost + ticker_cost
var/end_time = world.timeofday
if(end_time < start_time) //why not just use world.time instead?
@@ -334,9 +340,13 @@ datum/controller/game_controller/proc/process_nano()
nanomanager.processing_uis.Cut(i,i+1)
datum/controller/game_controller/proc/process_events()
last_thing_processed = /datum/event
last_thing_processed = /datum/event_manager
event_manager.process()
datum/controller/game_controller/proc/process_alarms()
last_thing_processed = /datum/subsystem/alarm
alarm_manager.fire()
datum/controller/game_controller/proc/Recover() //Mostly a placeholder for now.
var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
for(var/varname in master_controller.vars)

View File

@@ -0,0 +1,33 @@
// We manually initialize the alarm handlers instead of looping over all existing types
// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof.
/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
/var/global/datum/alarm_handler/camera/camera_alarm = new()
/var/global/datum/alarm_handler/fire/fire_alarm = new()
/var/global/datum/alarm_handler/motion/motion_alarm = new()
/var/global/datum/alarm_handler/power/power_alarm = new()
/datum/subsystem/alarm
name = "Alarm"
var/list/datum/alarm/all_handlers
/datum/subsystem/alarm/New()
all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm)
/datum/subsystem/alarm/stat_entry()
stat(null,"Alarm-[master_controller.alarms_cost]\t#[number_of_active_alarms()]")
/datum/subsystem/alarm/fire()
for(var/datum/alarm_handler/AH in all_handlers)
AH.process()
/datum/subsystem/alarm/proc/active_alarms()
var/list/all_alarms = new
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/subsystem/alarm/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len

View File

@@ -0,0 +1,46 @@
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
/datum/subsystem
//things you will want to define
var/name //name of the subsystem
var/priority = 0 //priority affects order of initialization. Higher priorities are initialized first, lower priorities later. Can be decimal and negative values.
var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
//things you will probably want to leave alone
var/can_fire = 0 //prevent fire() calls
var/last_fire = 0 //last world.time we called fire()
var/next_fire = 0 //scheduled world.time for next fire()
var/cpu = 0 //cpu-usage stats (somewhat vague)
var/cost = 0 //average time to execute
var/times_fired = 0 //number of times we have called fire()
//used to initialize the subsystem BEFORE the map has loaded
/datum/subsystem/New()
//previously, this would have been named 'process()' but that name is used everywhere for different things!
//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds.
//fire(), and the procs it calls, SHOULD NOT HAVE ANY SLEEP OPERATIONS in them!
//YE BE WARNED!
/datum/subsystem/proc/fire()
can_fire = 0
//used to initialize the subsystem AFTER the map has loaded
/datum/subsystem/proc/Initialize(start_timeofday)
var/time = (world.timeofday - start_timeofday) / 10
var/msg = "Initialized [name] SubSystem within [time] seconds"
world << "<span class='userdanger'>[msg]</span>"
world.log << msg
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
/datum/subsystem/proc/stat_entry()
stat(name, "[round(cost,0.001)]ds\t(CPU:[round(cpu,1)]%)")
//could be used to postpone a costly subsystem for one cycle
//for instance, during cpu intensive operations like explosions
/datum/subsystem/proc/postpone()
if(next_fire - world.time < wait)
next_fire += wait
//usually called via datum/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
//should attempt to salvage what it can from the old instance of subsystem
/datum/subsystem/proc/Recover()

View File

@@ -56,7 +56,7 @@
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
return
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants"))
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -117,5 +117,8 @@
if("Plants")
debug_variables(plant_controller)
feedback_add_details("admin_verb", "DPlants")
if("Alarm")
debug_variables(alarm_manager)
feedback_add_details("admin_verb", "DAlarm")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return

View File

@@ -1,22 +0,0 @@
/*
This is what is supplied to the examine tab. Everything has a 'descriptions' variable, which is null by default. When it is not null,
it contains this datum. To add this datum to something, all you do is add this to the thing..
descriptions = new/datum/descriptions("I am some helpful blue text","I have backstory text about this obj.","You can use this to kill everyone.")
First string is the 'info' var, second is the 'fluff' var, and third is the 'antag' var. All are optional. Just add it to the object you want to have it.
If you are wondering, BYOND does not let you do desc = new/datum/descriptions .
More strings can be added easily, but you will need to add a proc to retrieve it from the atom. The procs are defined in atoms.dm.
*/
/datum/descriptions
var/info
var/fluff
var/antag
/datum/descriptions/New(var/info, var/fluff, var/antag)
src.info = info
src.fluff = fluff
src.antag = antag

View File

@@ -46,7 +46,7 @@ var/const/AALARM_WIRE_AALARM = 16
//world << "Syphon Wire Cut"
if(AALARM_WIRE_AALARM)
if (A.alarm_area.atmosalert(2))
if (A.alarm_area.atmosalert(2, A))
A.post_alert(2)
A.update_icon()
@@ -88,6 +88,6 @@ var/const/AALARM_WIRE_AALARM = 16
if(AALARM_WIRE_AALARM)
// world << "Aalarm wire pulsed"
if (A.alarm_area.atmosalert(0))
if (A.alarm_area.atmosalert(0, A))
A.post_alert(0)
A.update_icon()

View File

@@ -110,7 +110,13 @@ var/list/ghostteleportlocs = list()
power_environ = 0
ambience = list('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg')
/area/space/firealert()
area/space/atmosalert()
return
/area/space/fire_alert()
return
/area/space/fire_reset()
return
/area/space/readyalert()
@@ -633,7 +639,7 @@ var/list/ghostteleportlocs = list()
/area/prison/cell_block/C
name = "Prison Cell Block C"
icon_state = "brig"
////////////////////
//SPACE STATION 13//
////////////////////
@@ -1070,7 +1076,7 @@ var/list/ghostteleportlocs = list()
name = "\improper Engineering"
icon_state = "engineering"
ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
/area/engineering/atmos
name = "\improper Atmospherics"
icon_state = "atmos"
@@ -1082,7 +1088,7 @@ var/list/ghostteleportlocs = list()
/area/engineering/atmos/storage
name = "\improper Atmospherics Storage"
icon_state = "atmos_storage"
/area/engineering/drone_fabrication
name = "\improper Drone Fabrication"
icon_state = "drone_fab"
@@ -1130,7 +1136,7 @@ var/list/ghostteleportlocs = list()
/area/engineering/locker_room
name = "\improper Engineering Locker Room"
icon_state = "engineering_locker"
/area/engineering/workshop
name = "\improper Engineering Workshop"
icon_state = "engineering_workshop"

View File

@@ -30,37 +30,14 @@
power_change() // all machines set to current power level, also updates lighting icon
InitializeLighting()
/area/proc/get_cameras()
var/list/cameras = list()
for (var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
cameras += C
return cameras
/area/proc/poweralert(var/state, var/obj/source as obj)
if (state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
var/list/cameras = list()
for (var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
cameras += C
if(state == 1)
C.network.Remove("Power Alarms")
else
C.network.Add("Power Alarms")
for (var/mob/living/silicon/aiPlayer in player_list)
if(aiPlayer.z == source.z)
if (state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
for(var/obj/machinery/computer/station_alert/a in machines)
if(a.z == source.z)
if(state == 1)
a.cancelAlarm("Power", src, source)
else
a.triggerAlarm("Power", src, cameras, source)
return
/area/proc/atmosalert(danger_level, var/set_firelocks=1)
// if(type==/area) //No atmos alarms in space
// return 0 //redudant
/area/proc/atmosalert(danger_level, var/alarm_source)
//Check all the alarms before lowering atmosalm. Raising is perfectly fine.
for (var/area/RA in related)
for (var/obj/machinery/alarm/AA in RA)
@@ -68,32 +45,16 @@
danger_level = max(danger_level, AA.danger_level)
if(danger_level != atmosalm)
if (set_firelocks && danger_level < 1 && atmosalm >= 1)
if (danger_level < 1 && atmosalm >= 1)
//closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
air_doors_open()
else if (danger_level >= 2 && atmosalm < 2)
air_doors_close()
if (danger_level < 2 && atmosalm >= 2)
for(var/area/RA in related)
for(var/obj/machinery/camera/C in RA)
C.network.Remove("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
aiPlayer.cancelAlarm("Atmosphere", src, src)
for(var/obj/machinery/computer/station_alert/a in machines)
a.cancelAlarm("Atmosphere", src, src)
if (danger_level >= 2 && atmosalm < 2)
var/list/cameras = list()
for(var/area/RA in related)
//updateicon()
for(var/obj/machinery/camera/C in RA)
cameras += C
C.network.Add("Atmosphere Alarms")
for(var/mob/living/silicon/aiPlayer in player_list)
aiPlayer.triggerAlarm("Atmosphere", src, cameras, src)
for(var/obj/machinery/computer/station_alert/a in machines)
a.triggerAlarm("Atmosphere", src, cameras, src)
if (set_firelocks)
air_doors_close()
if (danger_level == 0)
atmosphere_alarm.clearAlarm(master, alarm_source)
else
atmosphere_alarm.triggerAlarm(master, alarm_source, severity = danger_level)
atmosalm = danger_level
for(var/area/RA in related)
@@ -107,9 +68,9 @@
if(!src.master.air_doors_activated)
src.master.air_doors_activated = 1
for(var/obj/machinery/door/firedoor/E in src.master.all_doors)
if(!E:blocked)
if(!E.blocked)
if(E.operating)
E:nextstate = CLOSED
E.nextstate = CLOSED
else if(!E.density)
spawn(0)
E.close()
@@ -118,21 +79,21 @@
if(src.master.air_doors_activated)
src.master.air_doors_activated = 0
for(var/obj/machinery/door/firedoor/E in src.master.all_doors)
if(!E:blocked)
if(!E.blocked)
if(E.operating)
E:nextstate = OPEN
E.nextstate = OPEN
else if(E.density)
spawn(0)
E.open()
/area/proc/firealert()
if(name == "Space") //no fire alarms in space
return
if( !fire )
fire = 1
master.fire = 1 //used for firedoor checks
updateicon()
/area/proc/fire_alert()
if(!fire)
master.fire = 1 //used for firedoor checks
master.updateicon()
for(var/area/A in related)
A.fire = 1
A.updateicon()
mouse_opacity = 0
for(var/obj/machinery/door/firedoor/D in all_doors)
if(!D.blocked)
@@ -141,22 +102,15 @@
else if(!D.density)
spawn()
D.close()
var/list/cameras = list()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
cameras.Add(C)
C.network.Add("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
aiPlayer.triggerAlarm("Fire", src, cameras, src)
for (var/obj/machinery/computer/station_alert/a in machines)
a.triggerAlarm("Fire", src, cameras, src)
/area/proc/firereset()
/area/proc/fire_reset()
if (fire)
fire = 0
master.fire = 0 //used for firedoor checks
master.fire = 0 //used for firedoor checks
master.updateicon()
for(var/area/A in related)
A.fire = 0
A.updateicon()
mouse_opacity = 0
updateicon()
for(var/obj/machinery/door/firedoor/D in all_doors)
if(!D.blocked)
if(D.operating)
@@ -164,13 +118,6 @@
else if(D.density)
spawn(0)
D.open()
for(var/area/RA in related)
for (var/obj/machinery/camera/C in RA)
C.network.Remove("Fire Alarms")
for (var/mob/living/silicon/ai/aiPlayer in player_list)
aiPlayer.cancelAlarm("Fire", src, src)
for (var/obj/machinery/computer/station_alert/a in machines)
a.cancelAlarm("Fire", src, src)
/area/proc/readyalert()
if(!eject)

View File

@@ -12,9 +12,6 @@
var/throwpass = 0
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
//Examine tab
var/datum/descriptions/descriptions = null //See code/datums/descriptions.dm for details.
///Chemistry.
var/datum/reagents/reagents = null
@@ -205,47 +202,8 @@ its easier to just keep the beam vertical.
user << "\icon[src] That's [f_name] [suffix]"
var/datum/descriptions/D = descriptions
if(istype(D))
user.description_holders["info"] = get_descriptions_info()
user.description_holders["fluff"] = get_descriptions_fluff()
if(user.mind.special_role)
user.description_holders["antag"] = get_descriptions_antag()
else
user.description_holders["info"] = null
user.description_holders["fluff"] = null
user.description_holders["antag"] = null
if(name) //This shouldn't be needed but I'm paranoid.
user.description_holders["name"] = "[src.name]" //\icon[src]
user.description_holders["icon"] = "\icon[src]"
if(desc)
user << desc
user.description_holders["desc"] = src.desc
else
user.description_holders["desc"] = null //This is needed, or else if you examine one thing with a desc, then another without, the panel will retain the first examined's desc.
return distance == -1 || (get_dist(src, user) <= distance)
//Override these if you need special behaviour for a specific type.
/atom/proc/get_descriptions_info()
if(descriptions && descriptions.info)
return descriptions.info
return
/atom/proc/get_descriptions_fluff()
if(descriptions && descriptions.fluff)
return descriptions.fluff
return
/atom/proc/get_descriptions_antag()
if(descriptions && descriptions.antag)
return descriptions.antag
return
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.
// see code/modules/mob/mob_movement.dm for more.
/atom/proc/relaymove()

View File

@@ -28,7 +28,6 @@
recommended_enemies = 4
uplink_welcome = "Nar-Sie Uplink Console:"
uplink_uses = 10
var/datum/mind/sacrifice_target = null
var/finished = 0

View File

@@ -30,30 +30,37 @@
var/newscaster_announcements = null
var/ert_disabled = 0
var/uplink_welcome = "Illegal Uplink Console:"
var/uplink_uses = 10
var/uplink_uses = 12
var/list/datum/uplink_item/uplink_items = list(
"Ammunition" = list(
new/datum/uplink_item(/obj/item/ammo_magazine/a357, 2, ".357", "RA"),
new/datum/uplink_item(/obj/item/ammo_magazine/mc9mm, 2, "9mm", "R9"),
new/datum/uplink_item(/obj/item/ammo_magazine/chemdart, 2, "Darts", "AD"),
new/datum/uplink_item(/obj/item/weapon/storage/box/sniperammo, 3, "14.5mm", "RA")
),
"Highly Visible and Dangerous Weapons" = list(
new/datum/uplink_item(/obj/item/ammo_magazine/mc9mm, 2, "Ammo-9mm", "R9"),
new/datum/uplink_item(/obj/item/ammo_magazine/a357, 2, "Ammo-357", "RA"),
new/datum/uplink_item(/obj/item/weapon/storage/box/emps, 3, "5 EMP Grenades", "EM"),
new/datum/uplink_item(/obj/item/weapon/melee/energy/sword, 4, "Energy Sword", "ES"),
new/datum/uplink_item(/obj/item/weapon/gun/projectile/dartgun, 5, "Dart Gun", "DG"),
new/datum/uplink_item(/obj/item/weapon/gun/energy/crossbow, 5, "Energy Crossbow", "XB"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/g9mm, 5, "Silenced 9mm", "S9"),
new/datum/uplink_item(/obj/item/mecha_parts/mecha_equipment/weapon/energy/riggedlaser, 6, "Exosuit Rigged Laser", "RL"),
new/datum/uplink_item(/obj/item/weapon/gun/projectile/revolver, 6, "Revolver", "RE"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndicate, 10, "Mercenary Bundle", "BU")
new/datum/uplink_item(/obj/item/weapon/storage/box/syndicate, 10, "Mercenary Bundle", "BU"),
new/datum/uplink_item(/obj/item/weapon/gun/projectile/heavysniper, 12, "PTRS Rifle", "BU")
),
"Stealthy and Inconspicuous Weapons" = list(
new/datum/uplink_item(/obj/item/weapon/soap/syndie, 1, "Subversive Soap", "SP"),
new/datum/uplink_item(/obj/item/weapon/cane/concealed, 2, "Concealed Cane Sword", "CC"),
new/datum/uplink_item(/obj/item/weapon/cartridge/syndicate, 3, "Detomatix PDA Cartridge", "DC"),
new/datum/uplink_item(/obj/item/weapon/pen/paralysis, 3, "Paralysis Pen", "PP"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/cigarette, 4, "Cigarette Kit", "BH")
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/cigarette, 4, "Cigarette Kit", "BH"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/toxin, 4, "Random Toxin - Beaker", "RT")
),
"Stealth and Camouflage Items" = list(
new/datum/uplink_item(/obj/item/weapon/card/id/syndicate, 2, "Agent ID card", "AC"),
new/datum/uplink_item(/obj/item/clothing/shoes/syndigaloshes, 2, "No-Slip Shoes", "SH"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/spy, 2, "Bug Kit", "SK"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/spy, 2, "Bug Kit", "BK"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/chameleon, 3, "Chameleon Kit", "CB"),
new/datum/uplink_item(/obj/item/device/chameleon, 4, "Chameleon-Projector", "CP"),
new/datum/uplink_item(/obj/item/clothing/mask/gas/voice, 4, "Voice Changer", "VC"),
@@ -62,11 +69,13 @@
"Devices and Tools" = list(
new/datum/uplink_item(/obj/item/weapon/storage/toolbox/syndicate, 1, "Fully Loaded Toolbox", "ST"),
new/datum/uplink_item(/obj/item/weapon/plastique, 2, "C-4 (Destroys walls)", "C4"),
new/datum/uplink_item(/obj/item/device/encryptionkey/syndicate, 2, "Encrypted Radio Channel Key", "ER"),
new/datum/uplink_item(/obj/item/device/encryptionkey/binary, 3, "Binary Translator Key", "BT"),
new/datum/uplink_item(/obj/item/weapon/card/emag, 3, "Cryptographic Sequencer", "EC"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/clerical, 3, "Morphic Clerical Kit", "CK"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/space, 3, "Space Suit", "SS"),
new/datum/uplink_item(/obj/item/clothing/glasses/thermal/syndi, 3, "Thermal Imaging Glasses", "TM"),
new/datum/uplink_item(/obj/item/clothing/suit/storage/vest/heavy/merc, 4, "Heavy Armor Vest", "HAV"),
new/datum/uplink_item(/obj/item/weapon/aiModule/syndicate, 7, "Hacked AI Upload Module", "AI"),
new/datum/uplink_item(/obj/item/device/powersink, 5, "Powersink (DANGER!)", "PS",),
new/datum/uplink_item(/obj/item/device/radio/beacon/syndicate, 7, "Singularity Beacon (DANGER!)", "SB"),
@@ -78,10 +87,20 @@
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/imp_explosive, 6, "Explosive Implant (DANGER!)", "EI"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/imp_uplink, 10, "Uplink Implant (Contains 5 Telecrystals)", "UI")
),
"Health Aids" = list(
new/datum/uplink_item(/obj/item/weapon/storage/box/donkpockets, 1, "Box of Donk-Pockets", "DP"),
"Medical" = list(
new/datum/uplink_item(/obj/item/weapon/storage/box/donkpockets, 1, "Box of Sin-Pockets", "DP"),
new/datum/uplink_item(/obj/item/weapon/storage/firstaid/surgery, 5, "Surgery kit", "SK"),
new/datum/uplink_item(/obj/item/weapon/storage/firstaid/combat, 5, "Combat medical kit", "CM")
),
"Hardsuit Modules" = list(
new/datum/uplink_item(/obj/item/rig_module/vision/thermal, 2, "Thermal Scanner", "RTS"),
new/datum/uplink_item(/obj/item/rig_module/fabricator/energy_net, 3, "Net Projector", "REN"),
new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/ewar_voice, 4, "Electrowarfare Suite and Voice Synthesiser", "REV"),
new/datum/uplink_item(/obj/item/rig_module/maneuvering_jets, 4, "Maneuvering Jets", "RMJ"),
new/datum/uplink_item(/obj/item/rig_module/mounted/egun, 6, "Mounted Energy Gun", "REG"),
new/datum/uplink_item(/obj/item/rig_module/power_sink, 6, "Power Sink", "RPS"),
new/datum/uplink_item(/obj/item/rig_module/mounted, 8, "Mounted Laser Cannon", "RLC")
),
"(Pointless) Badassery" = list(
new/datum/uplink_item(/obj/item/toy/syndicateballoon, 10, "For showing that You Are The BOSS (Useless Balloon)", "BS"),
new/datum/uplink_item(/obj/item/toy/nanotrasenballoon, 10, "For showing that you love NT SOO much (Useless Balloon)", "NT")
@@ -251,16 +270,6 @@
special_role == "Head Revolutionary" && prob(30))
suspects += man
// If they're a traitor or likewise, give them extra TC in exchange.
var/obj/item/device/uplink/hidden/suplink = man.mind.find_syndicate_uplink()
if(suplink)
var/extra = 4
suplink.uses += extra
man << "\red We have received notice that enemy intelligence suspects you to be linked with us. We have thus invested significant resources to increase your uplink's capacity."
else
// Give them a warning!
man << "\red They are on to you!"
// Some poor people who were just in the wrong place at the wrong time..
else if(prob(10))
suspects += man

View File

@@ -10,7 +10,6 @@
recommended_enemies = 1
uplink_welcome = "Crazy AI Uplink Console:"
uplink_uses = 10
var/const/waittime_l = 600
var/const/waittime_h = 1800 // started at 1800

View File

@@ -9,7 +9,6 @@
votable = 0
uplink_welcome = "EVIL METEOR Uplink Console:"
uplink_uses = 10
/datum/game_mode/meteor/announce()

View File

@@ -9,7 +9,7 @@
recommended_enemies = 3
uplink_welcome = "AntagCorp Uplink Console:"
uplink_uses = 5
uplink_uses = 7
newscaster_announcements = /datum/news_announcement/revolution_inciting_event

View File

@@ -13,7 +13,6 @@
uplink_welcome = "AntagCorp Portable Teleportation Relay:"
uplink_uses = 10
var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds)
var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)

View File

@@ -117,19 +117,6 @@
first_run()
/obj/machinery/alarm/Del()
//If there's an active alarm, clear it after minute so that alarms don't keep going forver
delayed_reset()
..()
//needed to cancel the alarm after it is deleted
/obj/machinery/alarm/proc/delayed_reset()
var/area/A = alarm_area
src = null
spawn(600)
//It makes sense not to touch firelocks here. The alarm itself is gone, we have no idea what the atmos is like.
A.atmosalert(0, set_firelocks=0)
/obj/machinery/alarm/proc/first_run()
alarm_area = get_area(src)
if (alarm_area.master)
@@ -441,7 +428,7 @@
send_signal(device_id, list("power"= 0) )
/obj/machinery/alarm/proc/apply_danger_level(var/new_danger_level)
if (report_danger_level && alarm_area.atmosalert(new_danger_level))
if (report_danger_level && alarm_area.atmosalert(new_danger_level, src))
post_alert(new_danger_level)
update_icon()
@@ -769,13 +756,13 @@
return 1
if(href_list["atmos_alarm"])
if (alarm_area.atmosalert(2))
if (alarm_area.atmosalert(2, src))
apply_danger_level(2)
update_icon()
return 1
if(href_list["atmos_reset"])
if (alarm_area.atmosalert(0))
if (alarm_area.atmosalert(0, src))
apply_danger_level(0)
update_icon()
return 1
@@ -947,7 +934,6 @@ FIRE ALARM
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
/obj/machinery/firealarm/update_icon()
if(wiresexposed)
switch(buildstage)
if(2)
@@ -981,7 +967,8 @@ FIRE ALARM
return src.alarm()
/obj/machinery/firealarm/emp_act(severity)
if(prob(50/severity)) alarm()
if(prob(50/severity))
alarm(rand(30/severity, 60/severity))
..()
/obj/machinery/firealarm/attackby(obj/item/W as obj, mob/user as mob)
@@ -1080,6 +1067,7 @@ FIRE ALARM
var/d2
if (istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon))
A = A.loc
A = A.master
if (A.fire)
d1 = text("<A href='?src=\ref[];reset=1'>Reset - Lockdown</A>", src)
@@ -1145,26 +1133,26 @@ FIRE ALARM
/obj/machinery/firealarm/proc/reset()
if (!( src.working ))
return
var/area/A = src.loc
A = A.loc
if (!( istype(A, /area) ))
return
A.firereset()
var/area/area = get_area(src)
for(var/area/A in area.related)
for(var/obj/machinery/firealarm/FA in A)
fire_alarm.clearAlarm(loc, FA)
update_icon()
return
/obj/machinery/firealarm/proc/alarm()
if (!( src.working ))
/obj/machinery/firealarm/proc/alarm(var/duration = 0)
if (!( src.working))
return
var/area/A = src.loc
A = A.loc
if (!( istype(A, /area) ))
return
A.firealert()
var/area/area = get_area(src)
for(var/area/A in area.related)
for(var/obj/machinery/firealarm/FA in A)
fire_alarm.triggerAlarm(loc, FA, duration)
update_icon()
//playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0)
return
/obj/machinery/firealarm/New(loc, dir, building)
..()
@@ -1180,20 +1168,6 @@ FIRE ALARM
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
/obj/machinery/firealarm/Del()
//so fire alarms don't keep going forever
delayed_reset()
..()
//needed to cancel the alarm after it is deleted
/obj/machinery/firealarm/proc/delayed_reset()
var/area/A = get_area(src)
if (!A) return
src = null
spawn(600)
A.firereset()
/obj/machinery/firealarm/initialize()
if(z in config.contact_levels)
if(security_level)

View File

@@ -53,13 +53,6 @@
ASSERT(src.network.len > 0)
..()
/obj/machinery/camera/Del()
if(!alarm_on)
triggerCameraAlarm()
cancelCameraAlarm()
..()
/obj/machinery/camera/emp_act(severity)
if(!isEmpProof())
if(prob(100/severity))
@@ -67,7 +60,7 @@
stat |= EMPED
SetLuminosity(0)
kick_viewers()
triggerCameraAlarm()
triggerCameraAlarm(10 * severity)
update_icon()
spawn(900)
@@ -261,22 +254,16 @@
else
icon_state = initial(icon_state)
/obj/machinery/camera/proc/triggerCameraAlarm()
/obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0)
alarm_on = 1
if(!get_area(src))
return
for(var/mob/living/silicon/S in mob_list)
S.triggerAlarm("Camera", get_area(src), list(src), src)
camera_alarm.triggerAlarm(loc, src, duration)
/obj/machinery/camera/proc/cancelCameraAlarm()
alarm_on = 0
if(!get_area(src))
if(wires.IsIndexCut(CAMERA_WIRE_ALARM))
return
for(var/mob/living/silicon/S in mob_list)
S.cancelAlarm("Camera", get_area(src), src)
alarm_on = 0
camera_alarm.clearAlarm(loc, src)
//if false, then the camera is listed as DEACTIVATED and cannot be used
/obj/machinery/camera/proc/can_use()
@@ -361,3 +348,13 @@
user.set_machine(src)
wires.Interact(user)
/obj/machinery/camera/proc/nano_structure()
var/cam[0]
cam["name"] = sanitize(c_tag)
cam["deact"] = !can_use()
cam["camera"] = "\ref[src]"
cam["x"] = x
cam["y"] = y
cam["z"] = z
return cam

View File

@@ -45,8 +45,7 @@
if (!status || (stat & NOPOWER))
return 0
if (detectTime == -1)
for (var/mob/living/silicon/aiPlayer in player_list)
aiPlayer.cancelAlarm("Motion", get_area(src), src)
motion_alarm.clearAlarm(loc, src)
detectTime = 0
return 1
@@ -54,8 +53,7 @@
if (!status || (stat & NOPOWER))
return 0
if (!detectTime) return 0
for (var/mob/living/silicon/aiPlayer in player_list)
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
motion_alarm.triggerAlarm(loc, src)
detectTime = -1
return 1

View File

@@ -1,116 +1,85 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
// Converting these to global lists may be a bit laggy when removal procs are called. Consider
// rewriting this properly to fix the update bug, rather than unifying all monitors. ~Z
var/global/list/priority_air_alarms = list()
var/global/list/minor_air_alarms = list()
/obj/machinery/computer/atmos_alert
name = "atmospheric alert computer"
desc = "Used to access the station's atmospheric sensors."
circuit = "/obj/item/weapon/circuitboard/atmos_alert"
icon_state = "alert:0"
var/receive_frequency = 1437
var/datum/radio_frequency/radio_connection
/obj/machinery/computer/atmos_alert/initialize()
/obj/machinery/computer/atmos_alert/New()
..()
set_frequency(receive_frequency)
/obj/machinery/computer/atmos_alert/receive_signal(datum/signal/signal)
if(!signal || signal.encryption) return
var/zone = signal.data["zone"]
var/severity = signal.data["alert"]
if(!zone || !severity) return
minor_air_alarms -= zone
priority_air_alarms -= zone
if(severity=="severe")
priority_air_alarms |= zone
else if (severity=="minor")
minor_air_alarms |= zone
update_icon()
return
/obj/machinery/computer/atmos_alert/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, receive_frequency)
receive_frequency = new_frequency
radio_connection = radio_controller.add_object(src, receive_frequency, RADIO_ATMOSIA)
atmosphere_alarm.register(src, /obj/machinery/computer/station_alert/update_icon)
/obj/machinery/computer/atmos_alert/Del()
atmosphere_alarm.unregister(src)
..()
/obj/machinery/computer/atmos_alert/attack_hand(mob/user)
if(..(user))
return
user << browse(return_text(),"window=computer")
user.set_machine(src)
onclose(user, "computer")
ui_interact(user)
/obj/machinery/computer/atmos_alert/process()
if(..())
src.updateDialog()
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/major_alarms[0]
var/minor_alarms[0]
for(var/datum/alarm/alarm in atmosphere_alarm.major_alarms())
major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
for(var/datum/alarm/alarm in atmosphere_alarm.minor_alarms())
minor_alarms[++minor_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
data["priority_alarms"] = major_alarms
data["minor_alarms"] = minor_alarms
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/atmos_alert/update_icon()
..()
if(stat & (NOPOWER|BROKEN))
return
if(priority_air_alarms.len)
var/list/alarms = atmosphere_alarm.major_alarms()
if(alarms.len)
icon_state = "alert:2"
else if(minor_air_alarms.len)
icon_state = "alert:1"
else
icon_state = "alert:0"
alarms = atmosphere_alarm.minor_alarms()
if(alarms.len)
icon_state = "alert:1"
else
icon_state = initial(icon_state)
return
/obj/machinery/computer/atmos_alert/proc/return_text()
var/priority_text
var/minor_text
if(priority_air_alarms.len)
for(var/zone in priority_air_alarms)
priority_text += "<FONT color='red'><B>[zone]</B></FONT> <A href='?src=\ref[src];priority_clear=[ckey(zone)]'>X</A><BR>"
else
priority_text = "No priority alerts detected.<BR>"
if(minor_air_alarms.len)
for(var/zone in minor_air_alarms)
minor_text += "<B>[zone]</B> <A href='?src=\ref[src];minor_clear=[ckey(zone)]'>X</A><BR>"
else
minor_text = "No minor alerts detected.<BR>"
var/output = {"<B>[name]</B><HR>
<B>Priority Alerts:</B><BR>
[priority_text]
<BR>
<HR>
<B>Minor Alerts:</B><BR>
[minor_text]
<BR>"}
return output
/obj/machinery/computer/atmos_alert/Topic(href, href_list)
if(..())
return
return 1
if(href_list["priority_clear"])
var/removing_zone = href_list["priority_clear"]
for(var/zone in priority_air_alarms)
if(ckey(zone) == removing_zone)
priority_air_alarms -= zone
if(href_list["clear_alarm"])
var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in atmosphere_alarm.alarms
if(alarm)
for(var/datum/alarm_source/alarm_source in alarm.sources)
var/obj/machinery/alarm/air_alarm = alarm_source.source
if(istype(air_alarm))
var/list/new_ref = list("atmos_reset" = 1)
air_alarm.Topic(href, new_ref, custom_state = atmos_alert_topic)
return 1
if(href_list["minor_clear"])
var/removing_zone = href_list["minor_clear"]
for(var/zone in minor_air_alarms)
if(ckey(zone) == removing_zone)
minor_air_alarms -= zone
update_icon()
return
var/datum/topic_state/atmos_alert/atmos_alert_topic = new()
/datum/topic_state/atmos_alert
flags = NANO_IGNORE_DISTANCE
/datum/topic_state/air_alarm/href_list(var/mob/user)
var/list/extra_href = list()
extra_href["remote_connection"] = 1
extra_href["remote_access"] = 1
return extra_href

View File

@@ -3,6 +3,8 @@
/proc/invalidateCameraCache()
for(var/obj/machinery/computer/security/s in world)
s.camera_cache = null
for(var/datum/alarm/A in world)
A.cameras = null
/obj/machinery/computer/security
name = "security camera monitor"
@@ -43,33 +45,17 @@
if(!can_access_camera(C))
continue
var/cam[0]
cam["name"] = sanitize(C.c_tag)
cam["deact"] = !C.can_use()
cam["camera"] = "\ref[C]"
cam["x"] = C.x
cam["y"] = C.y
cam["z"] = C.z
var/cam = C.nano_structure()
cameras[++cameras.len] = cam
if(C == current)
data["current"] = cam
var/list/camera_list = list("cameras" = cameras)
camera_cache=list2json(camera_list)
var/list/camera_list = list("cameras" = cameras)
camera_cache=list2json(camera_list)
else
if(current)
var/cam[0]
cam["name"] = current.c_tag
cam["deact"] = !current.can_use()
cam["camera"] = "\ref[current]"
cam["x"] = current.x
cam["y"] = current.y
cam["z"] = current.z
data["current"] = cam
data["current"] = current.nano_structure()
if(ui)

View File

@@ -5,106 +5,42 @@
icon_state = "alert:0"
circuit = "/obj/item/weapon/circuitboard/stationalert"
var/alarms = list("Fire"=list(), "Atmosphere"=list(), "Power"=list())
var/obj/nano_module/alarm_monitor/engineering/alarm_monitor
/obj/machinery/computer/station_alert/New()
..()
alarm_monitor = new(src)
alarm_monitor.register(src, /obj/machinery/computer/station_alert/update_icon)
attack_ai(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
/obj/machinery/computer/station_alert/Del()
alarm_monitor.unregister(src)
..()
/obj/machinery/computer/station_alert/attack_ai(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
return
/obj/machinery/computer/station_alert/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
return
/obj/machinery/computer/station_alert/interact(mob/user)
alarm_monitor.ui_interact(user)
/obj/machinery/computer/station_alert/update_icon()
..()
if(stat & (BROKEN|NOPOWER))
return
attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
return
interact(mob/user)
usr.set_machine(src)
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += "<A HREF='?src=\ref[user];mach_close=alerts'>Close</A><br><br>"
for (var/cat in src.alarms)
dat += text("<B>[]</B><BR>\n", cat)
var/list/L = src.alarms[cat]
if (L.len)
for (var/alarm in L)
var/list/alm = L[alarm]
var/area/A = alm[1]
var/list/sources = alm[3]
dat += "<NOBR>"
dat += "&bull; "
dat += "[A.name]"
if (sources.len > 1)
dat += text(" - [] sources", sources.len)
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
user << browse(dat, "window=alerts")
onclose(user, "alerts")
Topic(href, href_list)
if(..())
return
return
proc/triggerAlarm(var/class, area/A, var/O, var/alarmsource)
if(stat & (BROKEN))
return
var/list/L = src.alarms[class]
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(alarmsource in sources))
sources += alarmsource
return 1
var/obj/machinery/camera/C = null
var/list/CL = null
if (O && istype(O, /list))
CL = O
if (CL.len == 1)
C = CL[1]
else if (O && istype(O, /obj/machinery/camera))
C = O
L[A.name] = list(A, (C) ? C : O, list(alarmsource))
return 1
proc/cancelAlarm(var/class, area/A as area, obj/origin)
if(stat & (BROKEN))
return
var/list/L = src.alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
return !cleared
process()
if(stat & (BROKEN|NOPOWER))
icon_state = "atmos0"
return
var/active_alarms = 0
for (var/cat in src.alarms)
var/list/L = src.alarms[cat]
if(L.len) active_alarms = 1
if(active_alarms)
icon_state = "alert:2"
else
icon_state = "alert:0"
..()
return
var/list/alarms = alarm_monitor.active_alarms()
if(alarms.len)
icon_state = "alert:2"
else
icon_state = initial(icon_state)
return

View File

@@ -250,6 +250,9 @@
target = safepick(view(3,target))
if(!target)
return
if(istype(target, /obj/machinery))
if (src.interface_action(target))
return
if(!target.Adjacent(src))
if(selected && selected.is_ranged())
selected.action(target)
@@ -259,6 +262,29 @@
src.melee_action(target)
return
/obj/mecha/proc/interface_action(obj/machinery/target)
if(istype(target, /obj/machinery/access_button))
src.occupant_message("<span class='notice'>Interfacing with [target].</span>")
src.log_message("Interfaced with [target].")
target.attack_hand(src.occupant)
return 1
if(istype(target, /obj/machinery/embedded_controller))
target.ui_interact(src.occupant)
return 1
return 0
/obj/mecha/contents_nano_distance(var/src_object, var/mob/living/user)
. = user.shared_living_nano_distance(src_object) //allow them to interact with anything they can interact with normally.
if(. != STATUS_INTERACTIVE)
//Allow interaction with the mecha or anything that is part of the mecha
if(src_object == src || (src_object in src))
return STATUS_INTERACTIVE
if(src.Adjacent(src_object))
src.occupant_message("<span class='notice'>Interfacing with [src_object]...</span>")
src.log_message("Interfaced with [src_object].")
return STATUS_INTERACTIVE
if(src_object in view(2, src))
return STATUS_UPDATE //if they're close enough, allow the occupant to see the screen through the viewport or whatever.
/obj/mecha/proc/melee_action(atom/target)
return

View File

@@ -198,11 +198,7 @@
// apparently called whenever an item is removed from a slot, container, or anything else.
/obj/item/proc/dropped(mob/user as mob)
..()
if(zoom) //binoculars, scope, etc
user.client.view = world.view
user.client.pixel_x = 0
user.client.pixel_y = 0
zoom = 0
if(zoom) zoom() //binoculars, scope, etc
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
@@ -660,9 +656,8 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
cannotzoom = 1
if(!zoom && !cannotzoom)
if(!usr.hud_used.hud_shown)
usr.button_pressed_F12(1) // If the user has already limited their HUD this avoids them having a HUD when they zoom in
usr.button_pressed_F12(1)
if(usr.hud_used.hud_shown)
usr.toggle_zoom_hud() // If the user has already limited their HUD this avoids them having a HUD when they zoom in
usr.client.view = viewsize
zoom = 1
@@ -688,7 +683,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
else
usr.client.view = world.view
if(!usr.hud_used.hud_shown)
usr.button_pressed_F12(1)
usr.toggle_zoom_hud()
zoom = 0
usr.client.pixel_x = 0

View File

@@ -28,3 +28,30 @@
new /obj/item/weapon/reagent_containers/pill/zoom( src )
new /obj/item/weapon/reagent_containers/pill/zoom( src )
new /obj/item/weapon/reagent_containers/pill/zoom( src )
/obj/item/weapon/reagent_containers/glass/beaker/vial/random
flags = 0
var/list/random_reagent_list = list(list("water" = 15) = 1, list("cleaner" = 15) = 1)
/obj/item/weapon/reagent_containers/glass/beaker/vial/random/toxin
random_reagent_list = list(
list("mindbreaker" = 10, "space_drugs" = 20) = 3,
list("carpotoxin" = 15) = 2,
list("impedrezene" = 15) = 2,
list("zombiepowder" = 10) = 1)
/obj/item/weapon/reagent_containers/glass/beaker/vial/random/New()
..()
if(is_open_container())
flags ^= OPENCONTAINER
var/list/picked_reagents = pickweight(random_reagent_list)
for(var/reagent in picked_reagents)
reagents.add_reagent(reagent, picked_reagents[reagent])
var/list/names = new
for(var/datum/reagent/R in reagents.reagent_list)
names += R.name
desc = "Contains [english_list(names)]."
update_icon()

View File

@@ -11,12 +11,30 @@ A list of items and costs is stored under the datum of every game mode, alongsid
var/cost = 0
var/path = null
var/reference = ""
var/description = ""
datum/uplink_item/New(var/itemPath, var/itemCost as num, var/itemName as text, var/itemReference as text)
datum/uplink_item/New(var/itemPath, var/itemCost as num, var/itemName as text, var/itemReference as text, var/itemDescription)
cost = itemCost
path = itemPath
name = itemName
reference = itemReference
description = itemDescription
datum/uplink_item/proc/description()
if(!description)
// Fallback description
var/obj/temp = src.path
description = replacetext(initial(temp.desc), "\n", "<br>")
return description
/datum/uplink_item/proc/generate_item(var/newloc)
var/list/L = list()
if(ispath(path))
L += new path(newloc)
else if(islist(path))
for(var/item_path in path)
L += new item_path(newloc)
return L
datum/nano_item_lists
var/list/items_nano
@@ -41,16 +59,17 @@ datum/nano_item_lists
uses = ticker.mode.uplink_uses
ItemsCategory = ticker.mode.uplink_items
var/datum/nano_item_lists/IL = generate_item_lists()
nanoui_items = IL.items_nano
ItemsReference = IL.items_reference
world_uplinks += src
/obj/item/device/uplink/Del()
world_uplinks -= src
..()
/obj/item/device/uplink/proc/generate_items()
var/datum/nano_item_lists/IL = generate_item_lists()
nanoui_items = IL.items_nano
ItemsReference = IL.items_reference
// BS12 no longer use this menu but there are forks that do, hency why we keep it
/obj/item/device/uplink/proc/generate_menu()
var/dat = "<B>[src.welcome]</B><BR>"
@@ -87,7 +106,7 @@ datum/nano_item_lists
for(var/category in ItemsCategory)
nano[++nano.len] = list("Category" = category, "items" = list())
for(var/datum/uplink_item/I in ItemsCategory[category])
nano[nano.len]["items"] += list(list("Name" = I.name, "Cost" = I.cost, "obj_path" = I.reference))
nano[nano.len]["items"] += list(list("Name" = I.name, "Description" = I.description(),"Cost" = I.cost, "obj_path" = I.reference))
reference[I.reference] = I
var/datum/nano_item_lists/result = new
@@ -126,10 +145,11 @@ datum/nano_item_lists
used_TC += UI.cost
feedback_add_details("traitor_uplink_items_bought", reference)
var/obj/I = new UI.path(get_turf(usr))
var/list/L = UI.generate_item(get_turf(usr))
if(ishuman(usr))
var/mob/living/carbon/human/A = usr
A.put_in_any_hand_if_possible(I)
for(var/obj/I in L)
A.put_in_any_hand_if_possible(I)
purchase_log[UI] = purchase_log[UI] + 1
@@ -189,6 +209,8 @@ datum/nano_item_lists
data["welcome"] = welcome
data["crystals"] = uses
data["menu"] = nanoui_menu
if(!nanoui_items)
generate_items()
data["nano_items"] = nanoui_items
data += nanoui_data

View File

@@ -219,8 +219,8 @@
new /obj/item/ammo_casing/shotgun/stunshell(src)
new /obj/item/ammo_casing/shotgun/stunshell(src)
/obj/item/weapon/storage/box/heavysniperammo
name = "box of 14.5mm AP shells"
/obj/item/weapon/storage/box/sniperammo
name = "box of 14.5mm shells"
desc = "It has a picture of a gun and several warning symbols on the front.<br>WARNING: Live ammunition. Misuse may result in serious injury or death."
New()

View File

@@ -128,6 +128,22 @@
new /obj/item/stack/medical/splint(src)
return
/obj/item/weapon/storage/firstaid/surgery
name = "surgery kit"
desc = "Contains tools for surgery."
/obj/item/weapon/storage/firstaid/surgery/New()
..()
if (empty) return
new /obj/item/weapon/bonesetter(src)
new /obj/item/weapon/cautery(src)
new /obj/item/weapon/circular_saw(src)
new /obj/item/weapon/hemostat(src)
new /obj/item/weapon/retractor(src)
new /obj/item/weapon/scalpel(src)
new /obj/item/weapon/surgicaldrill(src)
return
/*
* Pill Bottles
*/

View File

@@ -30,6 +30,7 @@
new /obj/item/ammo_magazine/a357(src)
new /obj/item/weapon/card/emag(src)
new /obj/item/weapon/plastique(src)
new /obj/item/weapon/plastique(src)
return
if("murder")
@@ -47,6 +48,7 @@
return
if("hacker")
new /obj/item/device/encryptionkey/syndicate(src)
new /obj/item/weapon/aiModule/syndicate(src)
new /obj/item/weapon/card/emag(src)
new /obj/item/device/encryptionkey/binary(src)
@@ -62,10 +64,9 @@
return
if("smoothoperator")
new /obj/item/weapon/gun/projectile/pistol(src)
new /obj/item/weapon/silencer(src)
new /obj/item/weapon/soap/syndie(src)
new /obj/item/weapon/storage/box/syndie_kit/g9mm(src)
new /obj/item/weapon/storage/bag/trash(src)
new /obj/item/weapon/soap/syndie(src)
new /obj/item/bodybag(src)
new /obj/item/clothing/under/suit_jacket(src)
new /obj/item/clothing/shoes/laceup(src)
@@ -176,6 +177,15 @@
new /obj/item/weapon/gun/projectile/pistol(src)
new /obj/item/weapon/silencer(src)
/obj/item/weapon/storage/box/syndie_kit/toxin
name = "toxin kit"
desc = "An apple will not be enough to keep the doctor away after this."
/obj/item/weapon/storage/box/syndie_kit/toxin/New()
..()
new /obj/item/weapon/reagent_containers/glass/beaker/vial/random/toxin(src)
new /obj/item/weapon/reagent_containers/syringe(src)
/obj/item/weapon/storage/box/syndie_kit/cigarette
name = "\improper Tricky smokes"
desc = "Comes with the following brands of cigarettes, in this order: 2xFlash, 2xSmoke, 1xMindBreaker, 1xTricordrazine. Avoid mixing them up."
@@ -217,3 +227,11 @@
for(var/reagent in reagents)
C.reagents.add_reagent(reagent, reagents[reagent] * C.storage_slots)
/obj/item/weapon/storage/box/syndie_kit/ewar_voice
name = "Electrowarfare and Voice Synthesiser kit"
desc = "Kit for confounding organic and synthetic entities alike."
/obj/item/weapon/storage/box/syndie_kit/ewar_voice/New()
..()
new /obj/item/rig_module/electrowarfare_suite(src)
new /obj/item/rig_module/voice(src)

View File

@@ -14,6 +14,15 @@ var/list/accessible_z_levels = list("1" = 5, "3" = 10, "4" = 15, "5" = 10, "6" =
/turf/space/New()
if(!istype(src, /turf/space/transit))
icon_state = "[((x + y) ^ ~(x * y) + z) % 25]"
update_starlight()
/turf/space/proc/update_starlight()
if(!config.starlight)
return
if(locate(/turf/simulated) in orange(src,1))
SetLuminosity(3)
else
SetLuminosity(0)
/turf/space/attackby(obj/item/C as obj, mob/user as mob)

View File

@@ -251,6 +251,9 @@
if(air_master)
air_master.mark_for_update(src)
for(var/turf/space/S in range(W,1))
S.update_starlight()
W.levelupdate()
return W
@@ -272,6 +275,9 @@
if(air_master)
air_master.mark_for_update(src)
for(var/turf/space/S in range(W,1))
S.update_starlight()
W.levelupdate()
return W

View File

@@ -174,8 +174,9 @@ var/gravity_is_on = 1
var/join_motd = null
var/forceblob = 0
var/datum/nanomanager/nanomanager = new() // NanoManager, the manager for Nano UIs.
var/datum/event_manager/event_manager = new() // Event Manager, the manager for events.
var/datum/nanomanager/nanomanager = new() // NanoManager, the manager for Nano UIs.
var/datum/event_manager/event_manager = new() // Event Manager, the manager for events.
var/datum/subsystem/alarm/alarm_manager = new() // Alarm Manager, the manager for alarms.
var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to.

View File

@@ -292,7 +292,7 @@
if("monkey") M.change_mob_type( /mob/living/carbon/monkey , null, null, delmob )
if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob )
if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob )
if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/Runtime , null, null, delmob )
if("runtime") M.change_mob_type( /mob/living/simple_animal/cat/fluff/Runtime , null, null, delmob )
if("corgi") M.change_mob_type( /mob/living/simple_animal/corgi , null, null, delmob )
if("ian") M.change_mob_type( /mob/living/simple_animal/corgi/Ian , null, null, delmob )
if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob )

138
code/modules/alarm/alarm.dm Normal file
View File

@@ -0,0 +1,138 @@
#define ALARM_RESET_DELAY 100 // How long will the alarm/trigger remain active once origin/source has been found to be gone?
/datum/alarm_source
var/source = null // The source trigger
var/source_name = "" // The name of the source should it be lost (for example a destroyed camera)
var/duration = 0 // How long this source will be alarming, 0 for indefinetely.
var/severity = 1 // How severe the alarm from this source is.
var/start_time = 0 // When this source began alarming.
var/end_time = 0 // Use to set when this trigger should clear, in case the source is lost.
/datum/alarm_source/New(var/atom/source)
src.source = source
start_time = world.time
source_name = source.get_source_name()
/datum/alarm
var/atom/origin //Used to identify the alarm area.
var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared.
var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source.
var/list/cameras //List of cameras that can be switched to, if the player has that capability.
var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera).
var/area/last_name //The last acquired name, used should origin be lost
var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated.
var/end_time //Used to set when this alarm should clear, in case the origin is lost.
/datum/alarm/New(var/atom/origin, var/atom/source, var/duration, var/severity)
src.origin = origin
cameras() // Sets up both cameras and last alarm area.
set_source_data(source, duration, severity)
/datum/alarm/proc/process()
// Has origin gone missing?
if(!origin && !end_time)
end_time = world.time + ALARM_RESET_DELAY
for(var/datum/alarm_source/AS in sources)
// Has the alarm passed its best before date?
if((AS.end_time && world.time > AS.end_time) || (AS.duration && world.time > (AS.start_time + AS.duration)))
sources -= AS
// Has the source gone missing? Then reset the normal duration and set end_time
if(!AS.source && !AS.end_time) // end_time is used instead of duration to ensure the reset doesn't remain in the future indefinetely.
AS.duration = 0
AS.end_time = world.time + ALARM_RESET_DELAY
/datum/alarm/proc/set_source_data(var/atom/source, var/duration, var/severity)
var/datum/alarm_source/AS = sources_assoc[source]
if(!AS)
AS = new/datum/alarm_source(source)
sources += AS
sources_assoc[source] = AS
// Currently only non-0 durations can be altered (normal alarms VS EMP blasts)
if(AS.duration)
duration = SecondsToTicks(duration)
AS.duration = duration
AS.severity = severity
/datum/alarm/proc/clear(var/source)
var/datum/alarm_source/AS = sources_assoc[source]
sources -= AS
sources_assoc -= source
/datum/alarm/proc/alarm_area()
if(!origin)
return last_area
last_area = origin.get_alarm_area()
return last_area
/datum/alarm/proc/alarm_name()
if(!origin)
return last_name
last_name = origin.get_alarm_name()
return last_name
/datum/alarm/proc/cameras()
// If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras
if(cameras && (last_camera_area != alarm_area()))
cameras = null
// The list of cameras is also reset by /proc/invalidateCameraCache()
if(!cameras)
cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras()
last_camera_area = last_area
return cameras
/datum/alarm/proc/max_severity()
var/max_severity = 0
for(var/datum/alarm_source/AS in sources)
max_severity = max(AS.severity, max_severity)
return max_severity
/******************
* Assisting procs *
******************/
/atom/proc/get_alarm_area()
var/area/A = get_area(src)
return A.master
/area/get_alarm_area()
return src.master
/atom/proc/get_alarm_name()
var/area/A = get_area(src)
return A.master.name
/area/get_alarm_name()
return master.name
/mob/get_alarm_name()
return name
/atom/proc/get_source_name()
return name
/obj/machinery/camera/get_source_name()
return c_tag
/atom/proc/get_alarm_cameras()
var/area/A = get_area(src)
return A.get_cameras()
/area/get_alarm_cameras()
return get_cameras()
/mob/living/silicon/robot/get_alarm_cameras()
var/list/cameras = ..()
if(camera)
cameras += camera
return cameras
/mob/living/silicon/robot/syndicate/get_alarm_cameras()
return list()
#undef ALARM_LOSS_DELAY

View File

@@ -0,0 +1,99 @@
#define ALARM_RAISED 1
#define ALARM_CLEARED 0
/datum/alarm_handler
var/category = ""
var/list/datum/alarm/alarms = new // All alarms, to handle cases when an origin has been deleted with one or more active alarms
var/list/datum/alarm/alarms_assoc = new // Associative list of alarms, to efficiently acquire them based on origin.
var/list/listeners = new // A list of all objects interested in alarm changes.
/datum/alarm_handler/proc/process()
for(var/datum/alarm/A in alarms)
A.process()
check_alarm_cleared(A)
/datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
var/new_alarm
//Proper origin and source mandatory
if(!(origin && source))
return
origin = origin.get_alarm_origin()
new_alarm = 0
//see if there is already an alarm of this origin
var/datum/alarm/existing = alarms_assoc[origin]
if(existing)
existing.set_source_data(source, duration, severity)
else
existing = new/datum/alarm(origin, source, duration, severity)
new_alarm = 1
alarms |= existing
alarms_assoc[origin] = existing
if(new_alarm)
alarms = dd_sortedObjectList(alarms)
on_alarm_change(existing, ALARM_RAISED)
return new_alarm
/datum/alarm_handler/proc/clearAlarm(var/atom/origin, var/source)
//Proper origin and source mandatory
if(!(origin && source))
return
origin = origin.get_alarm_origin()
var/datum/alarm/existing = alarms_assoc[origin]
if(existing)
existing.clear(source)
return check_alarm_cleared(existing)
/datum/alarm_handler/proc/major_alarms()
return alarms
/datum/alarm_handler/proc/minor_alarms()
return alarms
/datum/alarm_handler/proc/check_alarm_cleared(var/datum/alarm/alarm)
if ((alarm.end_time && world.time > alarm.end_time) || !alarm.sources.len)
alarms -= alarm
alarms_assoc -= alarm.origin
on_alarm_change(alarm, ALARM_CLEARED)
return 1
return 0
/datum/alarm_handler/proc/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
for(var/obj/machinery/camera/C in alarm.cameras())
if(was_raised)
C.network.Add(category)
invalidateCameraCache()
else
C.network.Remove(category)
notify_listeners(alarm, was_raised)
/datum/alarm_handler/proc/get_alarm_severity_for_origin(var/atom/origin)
if(!origin)
return
origin = origin.get_alarm_origin()
var/datum/alarm/existing = alarms_assoc[origin]
if(!existing)
return
return existing.max_severity()
/atom/proc/get_alarm_origin()
return src
/turf/get_alarm_origin()
var/area/area = get_area(src)
return area.master // Very important to get area.master, as dynamic lightning can and will split areas.
/datum/alarm_handler/proc/register(var/object, var/procName)
listeners[object] = procName
/datum/alarm_handler/proc/unregister(var/object)
listeners -= object
/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised)
for(var/listener in listeners)
call(listener, listeners[listener])(src, alarm, was_raised)

View File

@@ -0,0 +1,19 @@
/datum/alarm_handler/atmosphere
category = "Atmosphere Alarms"
/datum/alarm_handler/atmosphere/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
..()
/datum/alarm_handler/atmosphere/major_alarms()
var/list/major_alarms = new()
for(var/datum/alarm/A in alarms)
if(A.max_severity() > 1)
major_alarms.Add(A)
return major_alarms
/datum/alarm_handler/atmosphere/minor_alarms()
var/list/minor_alarms = new()
for(var/datum/alarm/A in alarms)
if(A.max_severity() == 1)
minor_alarms.Add(A)
return minor_alarms

View File

@@ -0,0 +1,2 @@
/datum/alarm_handler/camera
category = "Camera Alarms"

View File

@@ -0,0 +1,11 @@
/datum/alarm_handler/fire
category = "Fire Alarms"
/datum/alarm_handler/fire/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
var/area/A = alarm.origin
if(istype(A))
if(was_raised)
A.fire_alert()
else
A.fire_reset()
..()

View File

@@ -0,0 +1,2 @@
/datum/alarm_handler/motion
category = "Motion Alarms"

View File

@@ -0,0 +1,10 @@
/datum/alarm_handler/power
category = "Power Alarms"
/datum/alarm_handler/power/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
var/area/A = alarm.origin
if(istype(A))
A.power_alert(was_raised)
..()
/area/proc/power_alert(var/alarming)

View File

@@ -24,4 +24,11 @@
/obj/item/rig_module/electrowarfare_suite,
/obj/item/rig_module/chem_dispenser/combat,
/obj/item/rig_module/fabricator/energy_net
)
//Has most of the modules removed
/obj/item/weapon/rig/merc/empty
initial_modules = list(
/obj/item/rig_module/ai_container,
/obj/item/rig_module/electrowarfare_suite, //might as well
)

View File

@@ -1412,12 +1412,6 @@
////////////////////////////// Foxler - Erstatz Vryroxes /////////////////////////////////////////////////
/obj/item/weapon/holder/cat/fluff/bones
name = "Bones"
desc = "It's Bones! Meow."
gender = MALE
icon_state = "cat3"
//Use this subtype for spawning in the custom item.
/obj/item/weapon/holder/cat/fluff/bones/custom_item
@@ -1426,6 +1420,12 @@
new/mob/living/simple_animal/cat/fluff/bones (src)
..()
/obj/item/weapon/holder/cat/fluff/bones
name = "Bones"
desc = "It's Bones! Meow."
gender = MALE
icon_state = "cat3"
/mob/living/simple_animal/cat/fluff/bones
name = "Bones"
desc = "That's Bones the cat. He's a laid back, black cat. Meow."
@@ -1434,61 +1434,12 @@
icon_living = "cat3"
icon_dead = "cat3_dead"
holder_type = /obj/item/weapon/holder/cat/fluff/bones
bff_name = "Erstatz Vryroxes"
var/friend_name = "Erstatz Vryroxes"
/mob/living/simple_animal/cat/fluff
var/bff_name
var/mob/living/carbon/human/bff
/mob/living/simple_animal/cat/fluff/handle_movement_target()
if (!bff)
/mob/living/simple_animal/cat/fluff/bones/handle_movement_target()
if (!friend)
for (var/mob/living/carbon/human/M in player_list)
if (M.real_name == bff_name)
bff = M
if (M.real_name == friend_name)
friend = M
break
if (bff)
var/follow_dist = 5
if (bff.stat >= DEAD || bff.health <= config.health_threshold_softcrit) //danger
follow_dist = 1
else if (bff.stat || bff.health <= 50) //danger or just sleeping
follow_dist = 2
var/near_dist = max(follow_dist - 3, 1)
var/current_dist = get_dist(src, bff)
if (movement_target != bff)
if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (bff in oview(src)))
//stop existing movement
walk_to(src,0)
turns_since_scan = 0
//walk to bff
stop_automated_movement = 1
movement_target = bff
walk_to(src, movement_target, near_dist, 4)
//already following and close enough, stop
else if (current_dist <= near_dist)
walk_to(src,0)
movement_target = null
stop_automated_movement = 0
if (!(bff && movement_target == bff))
..()
/mob/living/simple_animal/cat/fluff/Life()
..()
if (stat || !bff)
return
if (get_dist(src, bff) <= 1)
if (bff.stat >= DEAD || bff.health <= config.health_threshold_softcrit)
if (prob((bff.stat < DEAD)? 50 : 15))
audible_emote(pick("meows in distress.", "meows anxiously."))
else
if (prob(5))
visible_emote(pick("nuzzles [bff].",
"brushes against [bff].",
"rubs against [bff].",
"purrs."))
else if (bff.health <= 50)
if (prob(10)) audible_emote("meows anxiously.")

View File

@@ -0,0 +1,166 @@
/obj/machinery/atmospherics/pipe
description_info = "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \
be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser."
/obj/machinery/atmospherics/pipe/New() //This is needed or else 20+ lines of copypasta to dance around inheritence.
..()
description_info += "<br>Most pipes and atmospheric devices can be connected or disconnected with a wrench. The pipe's pressure must not be too high, \
or if it is a device, it must be turned off first."
//HE pipes
/obj/machinery/atmospherics/pipe/simple/heat_exchanging
description_info = "This radiates heat from the pipe's gas to space, cooling it down."
//Supply/Scrubber pipes
/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/visible/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Universal adapters
/obj/machinery/atmospherics/pipe/simple/visible/universal
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
/obj/machinery/atmospherics/pipe/simple/hidden/universal
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
//Three way manifolds
/obj/machinery/atmospherics/pipe/manifold
description_info = "A normal pipe with three ends to connect to."
/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/visible/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Insulated pipes
/obj/machinery/atmospherics/pipe/simple/insulated
description_info = "This is completely useless, use a normal pipe." //Sorry, but it's true.
//Four way manifolds
/obj/machinery/atmospherics/pipe/manifold4w
description_info = "This is a four-way pipe."
/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Endcaps
/obj/machinery/atmospherics/pipe/cap
description_info = "This is a cosmetic attachment, as pipes currently do not spill their contents into the air."
//T-shaped valves
/obj/machinery/atmospherics/tvalve
description_info = "Click this to toggle the mode. The direction with the green light is where the gas will flow."
//Normal valves
/obj/machinery/atmospherics/valve
description_info = "Click this to turn the valve. If red, the pipes on each end are seperated. Otherwise, they are connected."
//TEG ports
/obj/machinery/atmospherics/binary/circulator
description_info = "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
the center of the machine gives an indicator of how much elecrtricity is being generated."
//Passive gates
/obj/machinery/atmospherics/binary/passive_gate
description_info = "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing."
//Normal pumps (high power one inherits from this)
/obj/machinery/atmospherics/binary/pump
description_info = "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output."
//Vents
/obj/machinery/atmospherics/unary/vent_pump
description_info = "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm."
//Freezers
/obj/machinery/atmospherics/unary/freezer
description_info = "Cools down the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
//Heaters
/obj/machinery/atmospherics/unary/heater
description_info = "Heats up the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
//Gas injectors
/obj/machinery/atmospherics/unary/outlet_injector
description_info = "Outputs the pipe's gas into the atmosphere, similar to an airvent. It can be controlled by a nearby atmospherics computer. \
A green light on it means it is on."
//Scrubbers
/obj/machinery/atmospherics/unary/vent_scrubber
description_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
//Omni filters
/obj/machinery/atmospherics/omni/filter
description_info = "Filters gas from a custom input direction, with up to two filtered outputs and a 'everything else' \
output. The filtered output's arrows glow orange."
//Omni mixers
/obj/machinery/atmospherics/omni/mixer
description_info = "Combines gas from custom input and output directions. The percentage of combined gas can be defined."
//Canisters
/obj/machinery/portable_atmospherics/canister
description_info = "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \
can be filled by the canister, by using the tank on the canister, increasing the release pressure, then opening the valve until it is full, and then close it. \
*DO NOT* remove the tank until the valve is closed. A gas analyzer can be used to check the contents of the canister."
description_antag = "Canisters can be damaged, spilling their contents into the air, or you can just leave the release valve open."
//Portable pumps
/obj/machinery/portable_atmospherics/powered/pump
description_info = "Invaluable for filling air in a room rapidly after a breach repair. The internal gas container can be filled by \
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the air pump."
//Portable scrubbers
/obj/machinery/portable_atmospherics/powered/scrubber
description_info = "Filters the air, placing harmful gases into the internal gas container. The container can be emptied by \
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the scrubber. "
//Meters
/obj/machinery/meter
description_info = "Measures the volume and temperature of the pipe under the meter."
//Pipe dispensers
/obj/machinery/pipedispenser
description_info = "This can be moved by using a wrench. You will need to wrench it again when you want to use it. You can put \
excess (atmospheric) pipes into the dispenser, as well. The dispenser requires electricity to function."

View File

@@ -0,0 +1,35 @@
/obj/machinery/power/supermatter
description_info = "When energized by a laser (or something hitting it), it emits radiation and heat. If the heat reaches above 7000 kelvin, it will send an alert and start taking damage. \
After integrity falls to zero percent, it will delaminate, causing a massive explosion, station-wide radiation spikes, and hallucinations. \
Supermatter reacts badly to oxygen in the atmosphere. It'll also heat up really quick if it is in vacuum.<br>\
<br>\
Supermatter cores are extremely dangerous to be close to, and requires protection to handle properly. The protection you will need is:<br>\
Optical meson scanners on your eyes, to prevent hallucinations when looking at the supermatter.<br>\
Radiation helmet and suit, as the supermatter is radioactive.<br>\
<br>\
Touching the supermatter will result in *instant death*, with no corpse left behind! You can drag the supermatter, but anything else will kill you. \
It is advised to obtain a genetic backup before trying to drag it."
description_antag = "Exposing the supermatter to oxygen or vaccum will cause it to start rapidly heating up. Sabotaging the supermatter and making it explode will \
cause a period of lag as the explosion is processed by the server, as well as irradiating the entire station and causing hallucinations to happen. \
Wearing radiation equipment will protect you from most of the delamination effects sans explosion."
/obj/machinery/power/apc
description_info = "An APC (Area Power Controller) regulates and supplies backup power for the area they are in. Their power channels are divided \
out into 'environmental' (Items that manipulate airflow and temperature), 'lighting' (the lights), and 'equipment' (Everything else that consumes power). \
Power consumption and backup power cell charge can be seen from the interface, further controls (turning a specific channel on, off or automatic, \
toggling the APC's ability to charge the backup cell, or toggling power for the entire area via master breaker) first requires the interface to be unlocked \
with an ID with Engineering access or by one of the station's robots or the artificial intelligence."
description_antag = "This can be emagged to unlock it. It will cause the APC to have a blue error screen. \
Wires can be pulsed remotely with a signaler attached to it. A powersink will also drain any APCs connected to the same wire the powersink is on."
/obj/item/inflatable
description_info = "Inflate by using it in your hand. The inflatable barrier will inflate on your tile. To deflate it, use the 'deflate' verb."
/obj/structure/inflatable
description_info = "To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."
/obj/structure/inflatable/door
description_info = "Click the door to open or close it. It only stops air while closed.<br>\
To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."

View File

@@ -0,0 +1,8 @@
/mob/living/silicon/robot/drone
description_info = "Drones are player-controlled synthetics which are lawed to maintain the station and not \
interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \
They fuction similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \
such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \
An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access."
description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause."

View File

@@ -0,0 +1,24 @@
/obj/item/stack/rods
description_info = "Made from metal sheets. You can build a grille by using it in your hand. \
Clicking on a floor without any tiles will reinforce the floor. You can make reinforced glass by combining rods and normal glass sheets."
/obj/item/stack/sheet/glass
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets."
/obj/item/stack/sheet/glass/cyborg
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets.<br>\
As a synthetic, you can acquire more sheets of glass by recharging."
/obj/item/stack/sheet/glass/reinforced
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage."
/obj/item/stack/sheet/glass/reinforced/cyborg
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage.<br>\
As a synthetic, you can gain more reinforced glass by recharging."
/obj/item/stack/sheet/metal/cyborg
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it.<br>\
You can replenish your supply of metal as a synthetic by recharging."
/obj/item/stack/sheet
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it."

View File

@@ -0,0 +1,15 @@
/obj/structure/girder
description_info = "Use metal sheets on this to build a normal wall. Adding plasteel instead will make a reinforced wall.<br>\
A false wall can be made by using a crowbar on this girder, and then adding metal or plasteel.<br>\
You can dismantle the grider with a wrench."
/obj/structure/girder/reinforced
description_info = "Add another sheet of plasteel to finish."
/obj/structure/grille
description_info = "A powered and knotted wire underneath this will cause the grille to shock anyone not wearing insulated gloves.<br>\
Wirecutters will turn the grille into metal rods instantly. Grilles are made with metal rods."
/obj/structure/lattice
description_info = "Add a metal floor tile to build a floor on top of the lattice.<br>\
Lattices can be made by applying metal rods to a space tile."

View File

@@ -0,0 +1,3 @@
/turf/simulated/wall
description_info = "You can deconstruct this by welding it, and then wrenching the girder.<br>\
You can build a wall by using metal sheets and making a girder, then adding more metal or plasteel."

View File

@@ -0,0 +1,71 @@
/* This code is responsible for the examine tab. When someone examines something, it copies the examined object's description_info,
description_fluff, and description_antag, and shows it in a new tab.
In this file, some atom and mob stuff is defined here. It is defined here instead of in the normal files, to keep the whole system self-contained.
This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort.
*/
/atom/
var/description_info = null //Helpful blue text.
var/description_fluff = null //Green text about the atom's fluff, if any exists.
var/description_antag = null //Malicious red text, for the antags.
/atom/examine(mob/user)
..()
user.description_holders["info"] = get_description_info()
user.description_holders["fluff"] = get_description_fluff()
if(user.mind && user.mind.special_role || isobserver(user)) //Runtime prevention, as ghosts don't have minds.
user.description_holders["antag"] = get_description_antag()
if(name) //This shouldn't be needed but I'm paranoid.
user.description_holders["name"] = "[src.name]" //\icon[src]
user.description_holders["icon"] = "\icon[src]"
if(desc)
user << desc
user.description_holders["desc"] = src.desc
else
user.description_holders["desc"] = null //This is needed, or else if you examine one thing with a desc, then another without, the panel will retain the first examined's desc.
//Override these if you need special behaviour for a specific type.
/atom/proc/get_description_info()
if(description_info)
return description_info
return
/atom/proc/get_description_fluff()
if(description_fluff)
return description_fluff
return
/atom/proc/get_description_antag()
if(description_antag)
return description_antag
return
/mob/
var/description_holders[0]
/mob/Stat()
..()
if(statpanel("Examine"))
stat(null,"[description_holders["icon"]] <font size='5'>[description_holders["name"]]</font>") //The name, written in big letters.
stat(null,"[description_holders["desc"]]") //the default examine text.
if(description_holders["info"])
stat(null,"<font color='#084B8A'><b>[description_holders["info"]]</b></font>") //Blue, informative text.
if(description_holders["fluff"])
stat(null,"<font color='#298A08'><b>[description_holders["fluff"]]</b></font>") //Yellow, fluff-related text.
if(description_holders["antag"])
stat(null,"<font color='#8A0808'><b>[description_holders["antag"]]</b></font>") //Red, malicious antag-related text
/mob/living/get_description_fluff()
if(flavor_text) //Get flavor text for the green text.
return flavor_text
else //No flavor text? Try for hardcoded fluff instead.
return ..()
/mob/living/carbon/human/get_description_fluff()
return print_flavor_text(0)

View File

@@ -1280,9 +1280,6 @@
else
return ..()
/mob/living/carbon/human/get_descriptions_fluff()
return print_flavor_text(0)
/mob/living/carbon/human/getDNA()
if(species.flags & NO_SCAN)
return null

View File

@@ -1240,7 +1240,7 @@
if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO
if(healths) healths.icon_state = "health7" //DEAD healthmeter
if(client)
if(client.view != world.view) // If mob moves while zoomed in with device, unzoom them.
if(client.view != world.view) // If mob dies while zoomed in with device, unzoom them.
for(var/obj/item/item in contents)
if(item.zoom)
item.zoom()

View File

@@ -171,13 +171,6 @@
// ++++ROCKDTBEN++++ MOB PROCS //END
/mob/living/get_descriptions_fluff()
if(flavor_text) //Get flavor text for the green text.
return flavor_text
else //No flavor text? Try for hardcoded fluff instead.
return ..()
/mob/proc/get_contents()

View File

@@ -3,7 +3,6 @@
var/list/ai_list = list()
var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/ai_alerts,
/mob/living/silicon/ai/proc/ai_announcement,
/mob/living/silicon/ai/proc/ai_call_shuttle,
// /mob/living/silicon/ai/proc/ai_recall_shuttle,
@@ -23,10 +22,7 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/sensor_mode,
/mob/living/silicon/ai/proc/show_laws_verb,
/mob/living/silicon/ai/proc/toggle_acceleration,
/mob/living/silicon/ai/proc/toggle_camera_light,
/mob/living/silicon/ai/proc/nano_rcon,
/mob/living/silicon/ai/proc/nano_crew_monitor,
/mob/living/silicon/ai/proc/nano_power_monitor
/mob/living/silicon/ai/proc/toggle_camera_light
)
//Not sure why this is necessary...
@@ -83,9 +79,11 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/add_ai_verbs()
src.verbs |= ai_verbs_default
src.verbs |= ai_verbs_subsystems
/mob/living/silicon/ai/proc/remove_ai_verbs()
src.verbs -= ai_verbs_default
src.verbs -= ai_verbs_subsystems
/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
announcement = new()
@@ -166,8 +164,6 @@ var/list/ai_verbs_default = list(
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
init_subsystems()
ai_list += src
..()
return
@@ -325,36 +321,6 @@ var/list/ai_verbs_default = list(
if(malf && malf.apcs >= 3)
stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds")
/mob/living/silicon/ai/proc/ai_alerts()
set category = "AI Commands"
set name = "Show Alerts"
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += "<A HREF='?src=\ref[src];mach_close=aialerts'>Close</A><BR><BR>"
for (var/cat in alarms)
dat += text("<B>[]</B><BR>\n", cat)
var/list/alarmlist = alarms[cat]
if (alarmlist.len)
for (var/area_name in alarmlist)
var/datum/alarm/alarm = alarmlist[area_name]
dat += "<NOBR>"
var/cameratext = ""
if (alarm.cameras)
for (var/obj/machinery/camera/I in alarm.cameras)
cameratext += text("[]<A HREF=?src=\ref[];switchcamera=\ref[]>[]</A>", (cameratext=="") ? "" : " | ", src, I, I.c_tag)
dat += text("-- [] ([])", alarm.area.name, (cameratext)? cameratext : "No Camera")
if (alarm.sources.len > 1)
dat += text(" - [] sources", alarm.sources.len)
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=aialerts&can_close=0")
// this verb lets the ai see the stations manifest
/mob/living/silicon/ai/proc/ai_roster()
set category = "AI Commands"
@@ -451,7 +417,7 @@ var/list/ai_verbs_default = list(
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
subsystem_alarm_monitor()
//Carn: holopad requests
if (href_list["jumptoholopad"])
var/obj/machinery/hologram/holopad/H = locate(href_list["jumptoholopad"])
@@ -526,29 +492,6 @@ var/list/ai_verbs_default = list(
return 1
/mob/living/silicon/ai/triggerAlarm(var/class, area/A, list/cameralist, var/source)
if (stat == 2)
return 1
..()
var/cameratext = ""
for (var/obj/machinery/camera/C in cameralist)
cameratext += "[(cameratext == "")? "" : "|"]<A HREF=?src=\ref[src];switchcamera=\ref[C]>[C.c_tag]</A>"
queueAlarm("--- [class] alarm detected in [A.name]! ([(cameratext)? cameratext : "No Camera"])", class)
if (viewalerts) ai_alerts()
/mob/living/silicon/ai/cancelAlarm(var/class, area/A as area, var/source)
var/has_alarm = ..()
if (!has_alarm)
queueAlarm(text("--- [] alarm in [] has been cleared.", class, A.name), class, 0)
if (viewalerts) ai_alerts()
return has_alarm
/mob/living/silicon/ai/cancel_camera()
set category = "AI Commands"
set name = "Cancel Camera View"

View File

@@ -171,6 +171,7 @@
sleep(50)
theAPC = null
process_queued_alarms()
regular_hud_updates()
switch(src.sensor_mode)
if (SEC_HUD)

View File

@@ -1,27 +0,0 @@
var/obj/nano_module/crew_monitor/crew_monitor
var/obj/nano_module/rcon/rcon
var/obj/nano_module/power_monitor/power_monitor
/mob/living/silicon/ai/proc/init_subsystems()
crew_monitor = new(src)
rcon = new(src)
power_monitor = new(src)
/mob/living/silicon/ai/proc/nano_crew_monitor()
set category = "AI Subystems"
set name = "Crew Monitor"
crew_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/nano_power_monitor()
set category = "AI Subystems"
set name = "Power Monitor"
power_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/nano_rcon()
set category = "AI Subystems"
set name = "RCON"
rcon.ui_interact(usr)

View File

@@ -0,0 +1,44 @@
var/list/ai_verbs_subsystems = list(
/mob/living/silicon/ai/proc/subsystem_alarm_monitor,
/mob/living/silicon/ai/proc/subsystem_crew_monitor,
/mob/living/silicon/ai/proc/subsystem_power_monitor,
/mob/living/silicon/ai/proc/subsystem_rcon
)
/mob/living/silicon/ai
var/
var/obj/nano_module/crew_monitor/crew_monitor
var/obj/nano_module/rcon/rcon
var/obj/nano_module/power_monitor/power_monitor
/mob/living/silicon/ai/init_subsystems()
..()
del(alarm_monitor)
alarm_monitor = new/obj/nano_module/alarm_monitor/ai(src)
crew_monitor = new(src)
rcon = new(src)
power_monitor = new(src)
/mob/living/silicon/ai/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "AI Subystems"
alarm_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/subsystem_crew_monitor()
set category = "AI Subystems"
set name = "Crew Monitor"
crew_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/subsystem_power_monitor()
set category = "AI Subystems"
set name = "Power Monitor"
power_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/subsystem_rcon()
set category = "AI Subystems"
set name = "RCON"
rcon.ui_interact(usr)

View File

@@ -1,111 +0,0 @@
/datum/alarm
var/area/area //the area associated with the alarm. Used to identify the alarm
var/list/sources //list of things triggering the alarm. Used to determine when the alarm should be cleared.
var/list/cameras //list of cameras that can be switched to, if the player has that capability.
/datum/alarm/New(area/A, list/sourcelist=list(), list/cameralist=list())
area = A
sources = sourcelist
cameras = cameralist
/mob/living/silicon
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list()) //each sublist stores alarms keyed by the area name
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
/mob/living/silicon/proc/triggerAlarm(var/class, area/A, list/cameralist, var/source)
var/list/alarmlist = alarms[class]
//see if there is already an alarm of this class for this area
if (A.name in alarmlist)
var/datum/alarm/existing = alarmlist[A.name]
existing.sources += source
existing.cameras |= cameralist
else
alarmlist[A.name] = new /datum/alarm(A, list(source), cameralist)
/mob/living/silicon/proc/cancelAlarm(var/class, area/A as area, var/source)
var/cleared = 0
var/list/alarmlist = alarms[class]
if (A.name in alarmlist)
var/datum/alarm/alarm = alarmlist[A.name]
alarm.sources -= source
if (!(alarm.sources.len))
cleared = 1
alarmlist -= A.name
return !cleared
/mob/living/silicon/proc/queueAlarm(var/message, var/type, var/incoming = 1)
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
if(incoming)
alarms_to_show += message
alarm_types_show[type] += 1
else
alarms_to_clear += message
alarm_types_clear[type] += 1
if(!in_cooldown)
spawn(10 * 10) // 10 seconds
if(alarms_to_show.len < 5)
for(var/msg in alarms_to_show)
src << msg
else if(alarms_to_show.len)
var/msg = "--- "
if(alarm_types_show["Motion"])
msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
if(alarm_types_show["Fire"])
msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
if(alarm_types_show["Atmosphere"])
msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
if(alarm_types_show["Power"])
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_show["Power"]] alarms detected. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
if(alarms_to_clear.len < 3)
for(var/msg in alarms_to_clear)
src << msg
else if(alarms_to_clear.len)
var/msg = "--- "
if(alarm_types_clear["Motion"])
msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
if(alarm_types_clear["Fire"])
msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
if(alarm_types_clear["Atmosphere"])
msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
if(alarm_types_clear["Power"])
msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_show["Power"]] alarms detected. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
alarms_to_show = list()
alarms_to_clear = list()
for(var/i = 1; i < alarm_types_show.len; i++)
alarm_types_show[i] = 0
for(var/i = 1; i < alarm_types_clear.len; i++)
alarm_types_clear[i] = 0

View File

@@ -3,13 +3,6 @@
real_name = "drone"
icon = 'icons/mob/robots.dmi'
icon_state = "repairbot"
descriptions = new/datum/descriptions("Drones are player-controlled synthetics which are lawed to maintain the station and not \
interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \
They fuction similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \
such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \
An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access.",\
,"An <u>Electromagnetic Sequencer</u> can be used to subvert the drone to your cause.")
//desc_fluff is already provided with flavor_text.
maxHealth = 35
health = 35
universal_speak = 0

View File

@@ -18,6 +18,7 @@
use_power()
process_killswitch()
process_locks()
process_queued_alarms()
update_canmove()
/mob/living/silicon/robot/proc/clamp_values()

View File

@@ -437,39 +437,12 @@ var/list/robot_verbs_default = list(
updatename()
updateicon()
/mob/living/silicon/robot/verb/cmd_robot_alerts()
set category = "Robot Commands"
set name = "Show Alerts"
robot_alerts()
// this verb lets cyborgs see the stations manifest
/mob/living/silicon/robot/verb/cmd_station_manifest()
set category = "Robot Commands"
set name = "Show Crew Manifest"
show_station_manifest()
/mob/living/silicon/robot/proc/robot_alerts()
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += "<A HREF='?src=\ref[src];mach_close=robotalerts'>Close</A><BR><BR>"
for (var/cat in alarms)
dat += text("<B>[cat]</B><BR>\n")
var/list/alarmlist = alarms[cat]
if (alarmlist.len)
for (var/area_name in alarmlist)
var/datum/alarm/alarm = alarmlist[area_name]
dat += "<NOBR>"
dat += text("-- [area_name]")
if (alarm.sources.len > 1)
dat += text("- [alarm.sources.len] sources")
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=robotalerts&can_close=0")
/mob/living/silicon/robot/proc/self_diagnosis()
if(!is_component_functioning("diagnosis unit"))
return null
@@ -639,25 +612,6 @@ var/list/robot_verbs_default = list(
return
return
/mob/living/silicon/robot/triggerAlarm(var/class, area/A, list/cameralist, var/source)
if (stat == 2)
return 1
..()
queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
/mob/living/silicon/robot/cancelAlarm(var/class, area/A as area, obj/origin)
var/has_alarm = ..()
if (!has_alarm)
queueAlarm(text("--- [class] alarm in [A.name] has been cleared."), class, 0)
// if (viewalerts) robot_alerts()
return has_alarm
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
return
@@ -1043,30 +997,31 @@ var/list/robot_verbs_default = list(
/mob/living/silicon/robot/Topic(href, href_list)
if(..())
return
return 1
if(usr != src)
return
return 1
if (href_list["showalerts"])
robot_alerts()
return
subsystem_alarm_monitor()
return 1
if (href_list["mod"])
var/obj/item/O = locate(href_list["mod"])
if (istype(O) && (O.loc == src))
O.attack_self(src)
return 1
if (href_list["act"])
var/obj/item/O = locate(href_list["act"])
if (!istype(O))
return
return 1
if(!((O in src.module.modules) || (O == src.module.emag)))
return
return 1
if(activated(O))
src << "Already activated"
return
return 1
if(!module_state_1)
module_state_1 = O
O.layer = 20
@@ -1088,6 +1043,7 @@ var/list/robot_verbs_default = list(
else
src << "You need to disable a module first!"
installed_modules()
return 1
if (href_list["deact"])
var/obj/item/O = locate(href_list["deact"])
@@ -1106,6 +1062,7 @@ var/list/robot_verbs_default = list(
else
src << "Module isn't activated"
installed_modules()
return 1
if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawc"])
@@ -1114,6 +1071,7 @@ var/list/robot_verbs_default = list(
if ("No") lawcheck[L+1] = "Yes"
// src << text ("Switching Law [L]'s report status to []", lawcheck[L+1])
checklaws()
return 1
if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawi"])
@@ -1122,9 +1080,11 @@ var/list/robot_verbs_default = list(
if ("No") ioncheck[L] = "Yes"
// src << text ("Switching Law [L]'s report status to []", lawcheck[L+1])
checklaws()
return 1
if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite
statelaws()
return 1
return
/mob/living/silicon/robot/proc/radio_menu()
@@ -1257,9 +1217,11 @@ var/list/robot_verbs_default = list(
/mob/living/silicon/robot/proc/add_robot_verbs()
src.verbs |= robot_verbs_default
src.verbs |= robot_verbs_subsystems
/mob/living/silicon/robot/proc/remove_robot_verbs()
src.verbs -= robot_verbs_default
src.verbs -= robot_verbs_subsystems
// Uses power from cyborg's cell. Returns 1 on success or 0 on failure.
// Properly converts using CELLRATE now! Amount is in Joules.

View File

@@ -0,0 +1,9 @@
var/list/robot_verbs_subsystems = list(
/mob/living/silicon/robot/proc/subsystem_alarm_monitor
)
/mob/living/silicon/robot/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "Robot Subystems"
alarm_monitor.ui_interact(usr)

View File

@@ -22,13 +22,26 @@
var/obj/item/device/camera/siliconcam/aiCamera = null //photography
var/local_transmit //If set, can only speak to others of the same type within a short range.
// Subsystems
var/obj/nano_module/alarm_monitor = null
var/sensor_mode = 0 //Determines the current HUD.
var/next_alarm_notice
var/list/datum/alarm/queued_alarms = new()
#define SEC_HUD 1 //Security HUD mode
#define MED_HUD 2 //Medical HUD mode
/mob/living/silicon/New()
..()
add_language("Galactic Common")
init_subsystems()
/mob/living/silicon/Del()
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
AH.unregister(src)
..()
/mob/living/silicon/proc/SetName(pickedName as text)
real_name = pickedName
@@ -243,7 +256,8 @@
return 1
/mob/living/silicon/Topic(href, href_list)
..()
if(..())
return 1
if (href_list["lawr"]) // Selects on which channel to state laws
var/list/channels = list(MAIN_CHANNEL)
@@ -282,3 +296,62 @@
adjustBruteLoss(30)
updatehealth()
/mob/living/silicon/proc/init_subsystems()
alarm_monitor = new/obj/nano_module/alarm_monitor/borg(src)
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
AH.register(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
if(!next_alarm_notice)
next_alarm_notice = world.time + SecondsToTicks(10)
var/list/alarms = queued_alarms[alarm_handler]
if(was_raised)
// Raised alarms are always set
alarms[alarm] = 1
else
// Alarms that were raised but then cleared before the next notice are instead removed
if(alarm in alarms)
alarms -= alarm
// And alarms that have only been cleared thus far are set as such
else
alarms[alarm] = -1
/mob/living/silicon/proc/process_queued_alarms()
if(next_alarm_notice && (world.time > next_alarm_notice))
next_alarm_notice = 0
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
var/reported = 0
for(var/datum/alarm/A in alarms)
if(alarms[A] == 1)
if(!reported)
reported = 1
src << "<span class='warning'>--- [AH.category] Detected ---</span>"
raised_alarm(A)
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
var/reported = 0
for(var/datum/alarm/A in alarms)
if(alarms[A] == -1)
if(!reported)
reported = 1
src << "<span class='notice'>--- [AH.category] Cleared ---</span>"
src << "\The [A.alarm_name()]."
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
alarms.Cut()
/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A)
src << "[A.alarm_name()]!"
/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A)
var/cameratext = ""
for(var/obj/machinery/camera/C in A.cameras())
cameratext += "[(cameratext == "")? "" : "|"]<A HREF=?src=\ref[src];switchcamera=\ref[C]>[C.c_tag]</A>"
src << "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])"

View File

@@ -18,6 +18,7 @@
response_harm = "kicks"
var/turns_since_scan = 0
var/mob/living/simple_animal/mouse/movement_target
var/mob/flee_target
min_oxy = 16 //Require atleast 16kPA oxygen
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
@@ -44,27 +45,71 @@
break
if(!stat && !resting && !buckled)
handle_movement_target()
turns_since_scan++
if (turns_since_scan > 5)
walk_to(src,0)
turns_since_scan = 0
if (flee_target) //fleeing takes precendence
handle_flee_target()
else
handle_movement_target()
/mob/living/simple_animal/cat/proc/handle_movement_target()
turns_since_scan++
if(turns_since_scan > 5)
walk_to(src,0)
turns_since_scan = 0
/mob/living/simple_animal/cat/proc/handle_movement_target()
//if our target is neither inside a turf or inside a human(???), stop
if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
movement_target = null
stop_automated_movement = 0
//if we have no target or our current one is out of sight/too far away
if( !movement_target || !(movement_target.loc in oview(src, 4)) )
movement_target = null
stop_automated_movement = 0
for(var/mob/living/simple_animal/mouse/snack in oview(src)) //search for a new target
if(isturf(snack.loc) && !snack.stat)
movement_target = snack
break
if(movement_target)
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
movement_target = null
stop_automated_movement = 0
if( !movement_target || !(movement_target.loc in oview(src, 4)) )
movement_target = null
stop_automated_movement = 0
for(var/mob/living/simple_animal/mouse/snack in oview(src))
if(isturf(snack.loc) && !snack.stat)
movement_target = snack
break
if(movement_target)
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
/mob/living/simple_animal/cat/proc/handle_flee_target()
//see if we should stop fleeing
if (flee_target && !(flee_target.loc in view(src)))
flee_target = null
stop_automated_movement = 0
if (flee_target)
if(prob(25)) say("HSSSSS")
stop_automated_movement = 1
walk_away(src, flee_target, 7, 2)
/mob/living/simple_animal/cat/proc/set_flee_target(atom/A)
if(A)
flee_target = A
turns_since_scan = 5
/mob/living/simple_animal/cat/attackby(var/obj/item/O, var/mob/user)
. = ..()
if(O.force)
set_flee_target(user? user : src.loc)
/mob/living/simple_animal/cat/attack_hand(mob/living/carbon/human/M as mob)
. = ..()
if(M.a_intent == "hurt")
set_flee_target(M)
/mob/living/simple_animal/cat/ex_act()
. = ..()
set_flee_target(src.loc)
/mob/living/simple_animal/cat/bullet_act(var/obj/item/projectile/proj)
. = ..()
set_flee_target(proj.firer? proj.firer : src.loc)
/mob/living/simple_animal/cat/hitby(atom/movable/AM)
. = ..()
set_flee_target(AM.thrower? AM.thrower : src.loc)
/mob/living/simple_animal/cat/MouseDrop(atom/over_object)
@@ -82,14 +127,91 @@
return //since the holder icon looks like a living cat
..()
//Basic friend AI
/mob/living/simple_animal/cat/fluff
var/mob/living/carbon/human/friend
var/befriend_job = null
/mob/living/simple_animal/cat/fluff/handle_movement_target()
if (friend)
var/follow_dist = 5
if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit) //danger
follow_dist = 1
else if (friend.stat || friend.health <= 50) //danger or just sleeping
follow_dist = 2
var/near_dist = max(follow_dist - 2, 1)
var/current_dist = get_dist(src, friend)
if (movement_target != friend)
if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (friend in oview(src)))
//stop existing movement
walk_to(src,0)
turns_since_scan = 0
//walk to friend
stop_automated_movement = 1
movement_target = friend
walk_to(src, movement_target, near_dist, 4)
//already following and close enough, stop
else if (current_dist <= near_dist)
walk_to(src,0)
movement_target = null
stop_automated_movement = 0
if (prob(10))
say("Meow!")
if (!friend || movement_target != friend)
..()
/mob/living/simple_animal/cat/fluff/Life()
..()
if (stat || !friend)
return
if (get_dist(src, friend) <= 1)
if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit)
if (prob((friend.stat < DEAD)? 50 : 15))
var/verb = pick("meows", "mews", "mrowls")
audible_emote(pick("[verb] in distress.", "[verb] anxiously."))
else
if (prob(5))
visible_emote(pick("nuzzles [friend].",
"brushes against [friend].",
"rubs against [friend].",
"purrs."))
else if (friend.health <= 50)
if (prob(10))
var/verb = pick("meows", "mews", "mrowls")
audible_emote("[verb] anxiously.")
/mob/living/simple_animal/cat/fluff/verb/friend()
set name = "Become Friends"
set category = "IC"
set src in view(1)
if(friend && usr == friend)
set_dir(get_dir(src, friend))
say("Meow!")
return
if (!(ishuman(usr) && befriend_job && usr.job == befriend_job))
usr << "<span class='notice'>[src] ignores you.</span>"
return
friend = usr
set_dir(get_dir(src, friend))
say("Meow!")
//RUNTIME IS ALIVE! SQUEEEEEEEE~
/mob/living/simple_animal/cat/Runtime
/mob/living/simple_animal/cat/fluff/Runtime
name = "Runtime"
desc = "Her fur has the look and feel of velvet, and her tail quivers occasionally."
gender = FEMALE
icon_state = "cat"
icon_living = "cat"
icon_dead = "cat_dead"
befriend_job = "Chief Medical Officer"
/mob/living/simple_animal/cat/kitten
name = "kitten"
@@ -97,4 +219,8 @@
icon_state = "kitten"
icon_living = "kitten"
icon_dead = "kitten_dead"
gender = NEUTER
gender = NEUTER
/mob/living/simple_animal/cat/kitten/New()
gender = pick(MALE, FEMALE)
..()

View File

@@ -265,7 +265,7 @@
adjustBruteLoss(-medical_pack.heal_brute)
visible_message("<span class='warning'>\The [user] applies the [medical_pack] to \the [src].</span>")
else
user << "<span class='warning'>\The [src] cannot benefit from medical items in its current state.</span>"
user << "<span class='warning'>\The [src] cannot benefit from medical items in \his current state.</span>"
return
else if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch))

View File

@@ -792,26 +792,25 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/Stat()
..()
if(statpanel("MC")) //not looking at that panel
if(client && client.holder)
if(client && client.holder)
if(statpanel("Status"))
stat(null,"Location:\t([x], [y], [z])")
stat(null,"CPU:\t[world.cpu]")
stat(null,"Instances:\t[world.contents.len]")
if(master_controller)
stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])")
stat(null,"Air-[master_controller.air_cost]\tSun-[master_controller.sun_cost]")
stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]")
stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]")
stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]")
stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
stat(null,"Events-[master_controller.events_cost]\t#[event_manager.active_events.len]")
stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
else
stat(null,"MasterController-ERROR")
if(statpanel("MC") && master_controller)
stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])")
stat(null,"Air-[master_controller.air_cost]\tSun-[master_controller.sun_cost]")
stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]")
stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]")
stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]")
stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
stat(null,"Event-[master_controller.events_cost]\t#[event_manager.active_events.len]")
alarm_manager.stat_entry()
stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
else
stat(null,"MasterController-ERROR")
if(listed_turf && client)
if(!TurfAdjacent(listed_turf))
@@ -834,16 +833,6 @@ note dizziness decrements automatically in the mob's Life() proc.
statpanel("Spells","[S.charge_counter]/[S.charge_max]",S)
if("holdervar")
statpanel("Spells","[S.holder_var_type] [S.holder_var_amount]",S)
if(statpanel("Examine"))
stat(null,"[description_holders["icon"]] <font size='5'>[description_holders["name"]]</font>") //The name, written in big letters.
stat(null,"[description_holders["desc"]]") //the default examine text.
if(description_holders["info"])
stat(null,"<font color='#084B8A'><b>[description_holders["info"]]</b></font>") //Blue, informative text.
if(description_holders["fluff"])
stat(null,"<font color='#298A08'><b>[description_holders["fluff"]]</b></font>") //Yellow, fluff-related text.
if(mind.special_role)
if(description_holders["antag"])
stat(null,"<font color='#8A0808'><b>[description_holders["antag"]]</b></font>") //Red, malicious antag-related text

View File

@@ -224,7 +224,4 @@
var/list/active_genes=list()
//Examine tab vars
//These hold the descriptions and other info, to relay to the actual tab.
var/description_holders[0]

View File

@@ -559,3 +559,16 @@ proc/is_blind(A)
say_dead_direct("The ghost of <span class='name'>[name]</span> now [pick("skulks","lurks","prowls","creeps","stalks")] among the dead. [message]")
else
say_dead_direct("<span class='name'>[name]</span> no longer [pick("skulks","lurks","prowls","creeps","stalks")] in the realm of the dead. [message]")
/mob/proc/switch_to_camera(var/obj/machinery/camera/C)
if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || blinded || !canmove))
return 0
check_eye(src)
return 1
/mob/living/silicon/ai/switch_to_camera(var/obj/machinery/camera/C)
if(!C.can_use() || !is_in_chassis())
return 0
eyeobj.setLoc(C)
return 1

View File

@@ -0,0 +1,83 @@
/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/active_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
var/list/alarms = AH.alarms
all_alarms += 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" = 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)

View File

@@ -1,5 +1,5 @@
/obj/nano_module/rcon
name = "RCON interface"
name = "Power RCON"
var/list/known_SMESs = null
var/list/known_breakers = null

View File

@@ -78,6 +78,10 @@
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
@@ -100,7 +104,10 @@
/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))
. = shared_living_nano_distance(src_object)
if(loc)
. = loc.contents_nano_distance(src_object, src)
else
. = shared_living_nano_distance(src_object)
if(STATUS_INTERACTIVE)
return STATUS_UPDATE

View File

@@ -497,10 +497,11 @@ Note that amputating the affected organ does in fact remove the infection from t
H = owner
for(var/datum/wound/W in wounds)
if(W.damage_type == CUT || W.damage_type == BRUISE)
brute_dam += W.damage
else if(W.damage_type == BURN)
burn_dam += W.damage
if(!W.internal) //so IB doesn't count towards crit/paincrit
if(W.damage_type == CUT || W.damage_type == BRUISE)
brute_dam += W.damage
else if(W.damage_type == BURN)
burn_dam += W.damage
if(!(status & ORGAN_ROBOT) && W.bleeding() && (H && !(H.species.flags & NO_BLOOD)))
W.bleed_timer--

View File

@@ -183,9 +183,6 @@
if(terminal)
disconnect_terminal()
//If there's no more APC then there shouldn't be a cause for alarm I guess
area.poweralert(1, src) //so that alarms don't go on forever
..()
/obj/machinery/power/apc/proc/make_terminal()
@@ -725,7 +722,7 @@
src.interact(user)
/obj/machinery/power/apc/attack_ghost(user as mob)
if(stat & (BROKEN|MAINT))
if(stat & (BROKEN|MAINT))
return
return ui_interact(user)
@@ -1164,29 +1161,27 @@
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
autoflag = 3
area.poweralert(1, src)
if(cell.charge >= 4000)
area.poweralert(1, src)
power_alarm.clearAlarm(loc, src)
else if((cell.percent() <= 30) && (cell.percent() > 15) && longtermpower < 0) // <30%, turn off equipment
if(autoflag != 2)
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
area.poweralert(0, src)
power_alarm.triggerAlarm(loc, src)
autoflag = 2
else if(cell.percent() <= 15) // <15%, turn off lighting & equipment
if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0))
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 2)
environ = autoset(environ, 1)
area.poweralert(0, src)
power_alarm.triggerAlarm(loc, src)
autoflag = 1
else // zero charge, turn all off
if(autoflag != 0)
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
area.poweralert(0, src)
power_alarm.triggerAlarm(loc, src)
autoflag = 0
// now trickle-charge the cell
@@ -1233,7 +1228,7 @@
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
area.poweralert(0, src)
power_alarm.triggerAlarm(loc, src)
autoflag = 0
// update icon & area power if anything changed

View File

@@ -1,4 +1,4 @@
/area/engineering/poweralert(var/state, var/source)
if (state != poweralm)
/area/engineering/power_alert(var/alarming)
if (alarming)
investigate_log("has a power alarm!","singulo")
..()

View File

@@ -76,7 +76,13 @@
/obj/item/weapon/gun/energy/update_icon()
if(charge_meter)
var/ratio = power_supply.charge / power_supply.maxcharge
ratio = round(ratio, 0.25) * 100
//make sure that rounding down will not give us the empty state even if we have charge for a shot left.
if(power_supply.charge < charge_cost)
ratio = 0
else
ratio = max(round(ratio, 0.25) * 100, 25)
if(modifystate)
icon_state = "[modifystate][ratio]"
else

View File

@@ -2,9 +2,10 @@
name = "ion rifle"
desc = "A man portable anti-armor weapon designed to disable mechanical threats"
icon_state = "ionrifle"
item_state = "ionrifle"
fire_sound = 'sound/weapons/Laser.ogg'
origin_tech = "combat=2;magnets=4"
w_class = 4.0
w_class = 4
force = 10
flags = CONDUCT
slot_flags = SLOT_BACK
@@ -16,6 +17,13 @@
return //so it doesn't EMP itself, I guess
..()
/obj/item/weapon/gun/energy/ionrifle/update_icon()
..()
if(power_supply.charge < charge_cost)
item_state = "ionrifle-empty"
else
item_state = initial(item_state)
/obj/item/weapon/gun/energy/decloner
name = "biological demolecularisor"
desc = "A gun that discharges high amounts of controlled radiation to slowly break a target into component elements."

View File

@@ -1,6 +1,6 @@
/obj/item/weapon/gun/projectile/heavysniper
name = "\improper PTRS-7 rifle"
desc = "A portable anti-armour rifle fitted with a scope. Originally designed to used against armoured exosuits, it is capable of punching through non-reinforced walls with ease. Fires armor piercing 14.5mm shells."
desc = "A portable anti-armour rifle fitted with a scope. Originally designed to used against armoured exosuits, it is capable of punching through windows and non-reinforced walls with ease. Fires armor piercing 14.5mm shells."
icon_state = "heavysniper"
item_state = "shotgun"
w_class = 4

View File

@@ -43,10 +43,10 @@
var/chance = 0
if(istype(A, /turf/simulated/wall))
var/turf/simulated/wall/W = A
chance = round(damage/W.damage_cap*180)
chance = round(damage/W.damage_cap*250)
else if(istype(A, /obj/machinery/door))
var/obj/machinery/door/D = A
chance = round(damage/D.maxhealth*100)
chance = round(damage/D.maxhealth*150)
else if(istype(A, /obj/structure/girder) || istype(A, /obj/structure/cultgirder))
chance = 100
else if(istype(A, /obj/machinery) || istype(A, /obj/structure))
@@ -141,13 +141,13 @@
penetrating = 1
/obj/item/projectile/bullet/rifle/a145
damage = 80
damage = 60
stun = 3
weaken = 3
penetrating = 5
/obj/item/projectile/bullet/rifle/a556
damage = 50
damage = 40
penetrating = 1
/* Miscellaneous */

View File

@@ -320,4 +320,7 @@ EVENT_CUSTOM_START_MAJOR 80;100
#DISABLE_DSAY
## Uncomment to disable respawning by default.
#DISABLE_RESPAWN
#DISABLE_RESPAWN
## Uncomment to make space turfs have a short-range ambient light.
# STARLIGHT

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -271,6 +271,12 @@ div.notice {
color: #e9c183;
}
.itemLabelWidest {
float: left;
width: 100%;
color: #e9c183;
}
.itemContentWide {
float: left;
width: 79%;

View File

@@ -0,0 +1,37 @@
<!--
Title: Alarm Monitor Console (Main content)
Used In File(s): \code\modules\nano\modules\alarm_monitor.dm
-->
{{for data.categories}}
<H2><span class="itemLabelWidest">{{:value.category}}</span></H2>
{{for value.alarms :alarmValue:alarmIndex}}
{{if alarmValue.origin_lost}}
{{:alarmValue.name}} <span class='notice'>Alarm Origin Lost</span><br>
{{else}}
{{:alarmValue.name}}<br>
{{/if}}
{{if alarmValue.has_cameras || alarmValue.lost_sources != ""}}
<div class="item">
{{if alarmValue.has_cameras}}
<div class="itemContent" style="width: 100%;">
{{for alarmValue.cameras :cameraValue:cameraIndex}}
{{if cameraValue.deact}}
{{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}}
{{else}}
{{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}}
{{/if}}
{{/for}}
</div>
{{/if}}
{{if alarmValue.lost_sources != ""}}
<div class="itemContent" style="width: 100%;">
<H4><span class='notice'>Lost Alarm Sources: {{:alarmValue.lost_sources}}</span></H4>
</div>
{{/if}}
</div>
{{/if}}
{{empty}}
<span class="white">--All Systems Nominal</span>
{{/for}}
{{/for}}

View File

@@ -0,0 +1,17 @@
<H1>Priority Alerts</H1>
{{for data.priority_alarms}}
<div class="item">
{{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}}
</div>
{{empty}}
No priority alerts detected.
{{/for}}
<H3>Minor Alerts</H3>
<div class="item">
{{for data.minor_alarms}}
{{:value.name}} {{:helper.link('Reset', null, {'clear_alarm' : value.ref})}}
{{empty}}
No minor alerts detected.
{{/for}}
</div>

View File

@@ -1,93 +1,99 @@
<!--
Title: Syndicate Uplink, uses some javascript to change nanoUI up a bit.
Used In File(s): \code\game\objects\items\devices\uplinks.dm
-->
{{:helper.syndicateMode()}}
<H2><span class="white">{{:data.welcome}}</span></H2>
<br>
<div class="item">
<div class="itemLabelNarrow">
<b>Functions</b>:
</div>
<div class="itemContent">
{{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}}
{{:helper.link('Exploitable Information', 'gear', {'menu' : 1}, null, 'fixedLeftWider')}}
{{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}}
{{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}}
</div>
</div>
<br>
{{if data.menu == 0}}
<H2><span class="white">Request items:</span></H2>
<span class="white"><i>Each item costs a number of tele-crystals as indicated by the number following their name.</i></span>
<div class="item">
<div class="itemLabel">
<b>Tele-Crystals</b>:
</div>
<div class="itemContent">
{{:data.crystals}}
</div>
</div>
<br>
{{for data.nano_items}}
<div class="item">
<H3><span class="white">{{:value.Category}}</span></H3>
</div>
{{for value.items :itemValue:itemIndex}}
<div class="item">
{{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - <span class="white">{{:itemValue.Cost}}</span>
</div>
{{/for}}
<br>
{{/for}}
<div class="item">
{{:helper.link('Buy Random (??)' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, null)}}
</div>
{{else data.menu == 1}}
<H2><span class="white">Information Record List:</span></H2>
<br>
<div class="item">
Select a Record
</div>
<br>
{{for data.exploit_records}}
<div class="item">
{{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}}
</div>
{{/for}}
{{else data.menu == 11}}
<H2><span class="white">Information Record:</span></H2>
<br>
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.exploit_exists == 1}}
<span class="good">Name: </span> <span class="average">{{:data.exploit.name}} </span><br>
<span class="good">Sex: </span> <span class="average">{{:data.exploit.sex}} </span><br>
<span class="good">Species: </span> <span class="average">{{:data.exploit.species}} </span><br>
<span class="good">Age: </span> <span class="average">{{:data.exploit.age}} </span><br>
<span class="good">Rank: </span> <span class="average">{{:data.exploit.rank}} </span><br>
<span class="good">Home System: </span> <span class="average">{{:data.exploit.home_system}} </span><br>
<span class="good">Citizenship: </span> <span class="average">{{:data.exploit.citizenship}} </span><br>
<span class="good">Faction: </span> <span class="average">{{:data.exploit.faction}} </span><br>
<span class="good">Religion: </span> <span class="average">{{:data.exploit.religion}} </span><br>
<span class="good">Fingerprint: </span> <span class="average">{{:data.exploit.fingerprint}} </span><br>
<br>Acquired Information:<br>
<span class="good">Notes:<br> </span> <span class="average">{{:data.exploit.nanoui_exploit_record}}</span><br><br>
{{else}}
<span class="bad">
No exploitative information acquired!
<br>
<br>
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}
<!--
Title: Syndicate Uplink, uses some javascript to change nanoUI up a bit.
Used In File(s): \code\game\objects\items\devices\uplinks.dm
-->
{{:helper.syndicateMode()}}
<H2><span class="white">{{:data.welcome}}</span></H2>
<br>
<div class="item">
<div class="itemLabelNarrow">
<b>Functions</b>:
</div>
<div class="itemContent">
{{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}}
{{:helper.link('Exploitable Information', 'gear', {'menu' : 1}, null, 'fixedLeftWider')}}
{{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}}
{{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}}
</div>
</div>
<br>
{{if data.menu == 0}}
<H2><span class="white">Request items:</span></H2>
<span class="white"><i>Each item costs a number of tele-crystals as indicated by the number following their name.</i></span>
<div class="item">
<div class="itemLabel">
<b>Tele-Crystals</b>:
</div>
<div class="itemContent">
{{:data.crystals}}
</div>
</div>
<br>
{{for data.nano_items}}
<div class="item">
<H3><span class="white">{{:value.Category}}</span></H3>
</div>
{{for value.items :itemValue:itemIndex}}
<div class="item">
{{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - <span class="white">{{:itemValue.Cost}}</span>
</div>
{{if itemValue.Cost <= data.crystals}}
<div class="item">
{{:itemValue.Description}}
</div>
{{/if}}
{{/for}}
<br>
{{/for}}
<div class="item">
{{:helper.link('Buy Random (??)' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, null)}}
</div>
{{else data.menu == 1}}
<H2><span class="white">Information Record List:</span></H2>
<br>
<div class="item">
Select a Record
</div>
<br>
{{for data.exploit_records}}
<div class="item">
{{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}}
</div>
{{/for}}
{{else data.menu == 11}}
<H2><span class="white">Information Record:</span></H2>
<br>
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.exploit_exists == 1}}
<span class="good">Name: </span> <span class="average">{{:data.exploit.name}} </span><br>
<span class="good">Sex: </span> <span class="average">{{:data.exploit.sex}} </span><br>
<span class="good">Species: </span> <span class="average">{{:data.exploit.species}} </span><br>
<span class="good">Age: </span> <span class="average">{{:data.exploit.age}} </span><br>
<span class="good">Rank: </span> <span class="average">{{:data.exploit.rank}} </span><br>
<span class="good">Home System: </span> <span class="average">{{:data.exploit.home_system}} </span><br>
<span class="good">Citizenship: </span> <span class="average">{{:data.exploit.citizenship}} </span><br>
<span class="good">Faction: </span> <span class="average">{{:data.exploit.faction}} </span><br>
<span class="good">Religion: </span> <span class="average">{{:data.exploit.religion}} </span><br>
<span class="good">Fingerprint: </span> <span class="average">{{:data.exploit.fingerprint}} </span><br>
<br>Acquired Information:<br>
<span class="good">Notes:<br> </span> <span class="average">{{:data.exploit.nanoui_exploit_record}}</span><br><br>
{{else}}
<span class="bad">
No exploitative information acquired!
<br>
<br>
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}