fix conflicts

This commit is contained in:
Greenjoe12345
2020-09-02 02:07:20 +01:00
256 changed files with 25059 additions and 323 deletions
+1 -1
View File
@@ -450,7 +450,7 @@ var/global/datum/controller/subsystem/ticker/ticker
if(captainless)
for(var/mob/M in player_list)
if(!istype(M,/mob/new_player))
to_chat(M, "<span class='notice'>Colony Directorship not forced on anyone.</span>")
to_chat(M, "<span class='notice'>Site Management is not forced on anyone.</span>")
/datum/controller/subsystem/ticker/proc/declare_completion()
+7
View File
@@ -32,6 +32,13 @@
containertype = /obj/structure/closet/crate/nanomed
containername = "BloodPack crate"
/datum/supply_pack/med/synthplas
name = "BloodPack (Synthplas) crate"
contains = list(/obj/item/weapon/reagent_containers/blood/synthplas = 6)
cost = 80
containertype = /obj/structure/closet/crate/nanomed
containername = "SynthPlas crate"
/datum/supply_pack/med/bodybag
name = "Body bag crate"
contains = list(/obj/item/weapon/storage/box/bodybags = 3)
+2 -2
View File
@@ -297,9 +297,9 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
M.add_ion_law("HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE")
if(5)
to_chat(M, "<br>")
to_chat(M, "<span class='danger'>THE COLONY DIRECTOR, HOP AND HOS ARE [who2]...LAWS UPDATED</span>")
to_chat(M, "<span class='danger'>THE SITE MANAGER, HOP AND HOS ARE [who2]...LAWS UPDATED</span>")
to_chat(M, "<br>")
M.add_ion_law("THE COLONY DIRECTOR, HOP AND HOS ARE [who2]")
M.add_ion_law("THE SITE MANAGER, HOP AND HOS ARE [who2]")
if(6)
to_chat(M, "<br>")
to_chat(M, "<span class='danger'>THE STATION IS BUILT FOR [who2]...LAWS UPDATED</span>")
+6 -2
View File
@@ -438,11 +438,15 @@ steam.start() -- spawns the effect
if(src.processing)
src.processing = 0
spawn(0)
var/turf/T = get_turf(src.holder)
var/turf/T
if(istype(holder, /atom/movable))
var/atom/movable/AM = holder
if(AM.locs && AM.locs.len)
T = pick(AM.locs)
T = get_turf(pick(AM.locs))
else
T = get_turf(AM)
else //when would this ever be attached a non-atom/movable?
T = get_turf(src.holder)
if(T != src.oldposition)
if(isturf(T))
var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition)
@@ -63,7 +63,7 @@
/obj/structure/closet/secure_closet/hos
name = "head of security's locker"
req_access = list(access_hos)
storage_capacity = 2.5 * MOB_MEDIUM
storage_capacity = 2.6 * MOB_MEDIUM
closet_appearance = /decl/closet_appearance/secure_closet/security/hos
starts_with = list(
@@ -99,7 +99,8 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/security,
/obj/item/clothing/shoes/boots/winter/security,
/obj/item/device/flashlight/maglight,
/obj/item/clothing/mask/gas/half)
/obj/item/clothing/mask/gas/half,
/obj/item/clothing/mask/gas/sechailer/swat/hos)
/obj/structure/closet/secure_closet/hos/Initialize()
if(prob(50))
@@ -113,6 +114,7 @@
/obj/structure/closet/secure_closet/warden
name = "warden's locker"
storage_capacity = 42
req_access = list(access_armory)
closet_appearance = /decl/closet_appearance/secure_closet/security/warden
@@ -143,7 +145,8 @@
/obj/item/clothing/shoes/boots/winter/security,
/obj/item/device/flashlight/maglight,
/obj/item/device/megaphone,
/obj/item/clothing/mask/gas/half)
/obj/item/clothing/mask/gas/half,
/obj/item/clothing/mask/gas/sechailer/swat/warden)
/obj/structure/closet/secure_closet/warden/Initialize()
if(prob(50))
@@ -406,7 +406,8 @@
/obj/item/clothing/gloves/swat,
/obj/item/clothing/mask/balaclava/tactical,
/obj/item/clothing/mask/balaclava,
/obj/item/clothing/mask/bandana/skull = 2)
/obj/item/clothing/mask/bandana/skull = 2,
/obj/item/clothing/mask/gas/sechailer/swat)
/obj/structure/closet/wardrobe/suit
@@ -397,6 +397,7 @@
/datum/gear/suit/teshcoat/New()
..()
gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/teshcoatwhite
@@ -417,4 +418,17 @@
/datum/gear/accessory/teshneckscarf/New()
..()
gear_tweaks += gear_tweak_free_color_choice
gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/toelessjack
display_name = "toe-less jackboots"
path = /obj/item/clothing/shoes/boots/jackboots/toeless
/datum/gear/shoes/toelessknee
display_name = "toe-less jackboots, knee-length"
path = /obj/item/clothing/shoes/boots/jackboots/toeless/knee
/datum/gear/shoes/toelessthigh
display_name = "toe-less jackboots, thigh-length"
path = /obj/item/clothing/shoes/boots/jackboots/toeless/thigh
+17
View File
@@ -42,6 +42,23 @@
w_class = ITEMSIZE_SMALL
armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0)
//Turn it into a hailer mask
/obj/item/clothing/mask/gas/half/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/device/hailer))
playsound(src, 'sound/items/Screwdriver.ogg', 50, 1)
user.drop_item(src)
var/obj/item/clothing/mask/gas/sechailer/N = new /obj/item/clothing/mask/gas/sechailer(src.loc)
N.fingerprints = src.fingerprints
N.fingerprintshidden = src.fingerprintshidden
N.fingerprintslast = src.fingerprintslast
N.suit_fibers = src.suit_fibers
N.hailer = I
I.loc = N
if(!isturf(N.loc))
user.put_in_hands(N)
qdel(src)
..()
//Plague Dr suit can be found in clothing/suits/bio.dm
/obj/item/clothing/mask/gas/plaguedoctor
name = "plague doctor mask"
+165
View File
@@ -0,0 +1,165 @@
/obj/item/clothing/mask/gas/sechailer
name = "hailer face mask"
desc = "A compact, durable gas mask that can be connected to an air supply. This one possesses a security hailer."
description_info = "This mask has a hailer attached, you can activate it on the button or use the Halt! verb, for switching phrases you can alt+click it or change it using the change phrase verb."
icon_state = "halfgas"
armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0)
action_button_name = "HALT!"
body_parts_covered = FACE
var/obj/item/device/hailer/hailer
var/cooldown = 0
var/phrase = 1
var/aggressiveness = 1
var/safety = 1
var/list/phrase_list = list(
"halt" = "HALT! HALT! HALT! HALT!",
"bobby" = "Stop in the name of the Law.",
"compliance" = "Compliance is in your best interest.",
"justice" = "Prepare for justice!",
"running" = "Running will only increase your sentence.",
"dontmove" = "Don't move, Creep!",
"floor" = "Down on the floor, Creep!",
"robocop" = "Dead or alive you're coming with me.",
"god" = "God made today for the crooks we could not catch yesterday.",
"freeze" = "Freeze, Scum Bag!",
"imperial" = "Stop right there, criminal scum!",
"bash" = "Stop or I'll bash you.",
"harry" = "Go ahead, make my day.",
"asshole" = "Stop breaking the law, asshole.",
"stfu" = "You have the right to shut the fuck up",
"shutup" = "Shut up crime!",
"super" = "Face the wrath of the golden bolt.",
"dredd" = "I am, the LAW!"
)
/obj/item/clothing/mask/gas/sechailer/swat/hos
name = "\improper HOS SWAT mask"
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a tan stripe."
icon_state = "hosmask"
/obj/item/clothing/mask/gas/sechailer/swat/warden
name = "\improper Warden SWAT mask"
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a blue stripe."
icon_state = "wardenmask"
/obj/item/clothing/mask/gas/sechailer/swat
name = "\improper SWAT mask"
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000."
icon_state = "officermask"
body_parts_covered = HEAD|FACE|EYES
flags_inv = HIDEFACE|BLOCKHAIR
aggressiveness = 3
phrase = 12
/obj/item/clothing/mask/gas/sechailer/ui_action_click()
halt()
/obj/item/clothing/mask/gas/sechailer/AltClick(mob/user)
selectphrase()
/obj/item/clothing/mask/gas/sechailer/verb/selectphrase()
set name = "Select gas mask phrase"
set category = "Object"
set desc = "Alter the message shouted by your complionator gas mask."
var/key = phrase_list[phrase]
var/message = phrase_list[key]
if (!safety)
to_chat(usr, "<span class='notice'>You set the restrictor to: FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT.</span>")
return
switch(aggressiveness)
if(1)
phrase = (phrase < 6) ? (phrase + 1) : 1
key = phrase_list[phrase]
message = phrase_list[key]
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
if(2)
phrase = (phrase < 11 && phrase >= 7) ? (phrase + 1) : 7
key = phrase_list[phrase]
message = phrase_list[key]
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
if(3)
phrase = (phrase < 18 && phrase >= 12 ) ? (phrase + 1) : 12
key = phrase_list[phrase]
message = phrase_list[key]
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
if(4)
phrase = (phrase < 18 && phrase >= 1 ) ? (phrase + 1) : 1
key = phrase_list[phrase]
message = phrase_list[key]
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
else
to_chat(usr, "<span class='notice'>It's broken.</span>")
/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user)
if(safety)
safety = 0
to_chat(user, "<span class='warning'>You silently fry [src]'s vocal circuit with the cryptographic sequencer.</span>")
else
return
/obj/item/clothing/mask/gas/sechailer/attackby(obj/item/I, mob/user)
if(I.is_screwdriver())
switch(aggressiveness)
if(1)
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the second position.</span>")
aggressiveness = 2
phrase = 7
if(2)
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the third position.</span>")
aggressiveness = 3
phrase = 13
if(3)
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the fourth position.</span>")
aggressiveness = 4
phrase = 1
if(4)
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the first position.</span>")
aggressiveness = 1
phrase = 1
if(5)
to_chat(user, "<span class='warning'>You adjust the restrictor but nothing happens, probably because its broken.</span>")
if(I.is_wirecutter())
if(aggressiveness != 5)
to_chat(user, "<span class='warning'>You broke it!</span>")
aggressiveness = 5
if(I.is_crowbar())
if(!hailer)
to_chat(user, "<span class='warning'>This mask has an integrated hailer, you can't remove it!</span>")
else
var/obj/N = new /obj/item/clothing/mask/gas/half(src.loc)
playsound(src, 'sound/items/Screwdriver.ogg', 50, 1)
N.fingerprints = src.fingerprints
N.fingerprintshidden = src.fingerprintshidden
N.fingerprintslast = src.fingerprintslast
N.suit_fibers = src.suit_fibers
if(!isturf(N.loc))
user.put_in_hands(hailer)
user.put_in_hands(N)
else
hailer.loc = N.loc
qdel(src)
return
..()
/obj/item/clothing/mask/gas/sechailer/verb/halt()
set name = "HALT!"
set category = "Objects"
set desc = "Activate your face mask hailer."
var/key = phrase_list[phrase]
var/message = phrase_list[key]
if(cooldown < world.time - 35) // A cooldown, to stop people being jerks
if(!safety)
message = "FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT."
usr.visible_message("[usr]'s Compli-o-Nator: <font color='red' size='4'><b>[message]</b></font>")
playsound(src, 'sound/voice/binsult.ogg', 50, 0, 4) //Future sound channel = something like SFX
cooldown = world.time
return
usr.visible_message("[usr]'s Compli-o-Nator: <font color='red' size='4'><b>[message]</b></font>")
playsound(src, "sound/voice/complionator/[key].ogg", 50, 0, 4) //future sound channel = something like SFX
cooldown = world.time
+4 -4
View File
@@ -39,19 +39,19 @@
/obj/item/clothing/under/seromi/smock/dress/science
name = "small research dress"
icon_state = "seromi_dress_science"
icon_state = "tesh_dress_science"
/obj/item/clothing/under/seromi/smock/dress/security
name = "small security dress"
icon_state = "seromi_dress_security"
icon_state = "tesh_dress_security"
/obj/item/clothing/under/seromi/smock/dress/engine
name = "small engineering dress"
icon_state = "seromi_dress_engine"
icon_state = "tesh_dress_engine"
/obj/item/clothing/under/seromi/smock/dress/medical
name = "small medical dress"
icon_state = "seromi_dress_medical"
icon_state = "tesh_dress_medical"
/obj/item/clothing/under/seromi/smock/uniform
name = "small command uniform"
+2 -2
View File
@@ -133,9 +133,9 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
M.add_ion_law("HUMANS NEED TO EAT [what2pref] [what2] TO SURVIVE")
if(5)
to_chat(M, "<br>")
to_chat(M, "<font color='red'>THE COLONY DIRECTOR, HOP AND HOS ARE [who2]...LAWS UPDATED</font>")
to_chat(M, "<font color='red'>THE SITE MANAGER, HOP AND HOS ARE [who2]...LAWS UPDATED</font>")
to_chat(M, "<br>")
M.add_ion_law("THE COLONY DIRECTOR, HOP AND HOS ARE [who2]")
M.add_ion_law("THE SITE MANAGER, HOP AND HOS ARE [who2]")
if(6)
to_chat(M, "<br>")
to_chat(M, "<font color='red'>THE STATION IS BUILT FOR [who2]...LAWS UPDATED</font>")
+1 -1
View File
@@ -6,7 +6,7 @@
item_state = "electronic"
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
matter = list(DEFAULT_WALL_MATERIAL = 150)
var/scan_time = 5 SECONDS
var/scan_time = 2 SECONDS
/obj/item/weapon/mining_scanner/attack_self(mob/user as mob)
to_chat(user, "<span class='notice'>You begin sweeping \the [src] about, scanning for metal deposits.</span>")
+1 -1
View File
@@ -63,7 +63,7 @@ var/global/list/SKILL_PRE = list("Engineer" = SKILL_ENGINEER, "Roboticist" = SKI
/datum/skill/knowledge/law
ID = "law"
name = "Corporate Law"
desc = "Your knowledge of corporate law and procedures. This includes Corporate Regulations, as well as general station rulings and procedures. A low level in this skill is typical for security officers, a high level in this skill is typical for Colony Directors."
desc = "Your knowledge of corporate law and procedures. This includes Corporate Regulations, as well as general station rulings and procedures. A low level in this skill is typical for security officers, a high level in this skill is typical for Site Managers."
field = "Security"
secondary = 1
+9 -1
View File
@@ -71,6 +71,10 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
if(linked)
apply_visual(user)
user.reset_view(linked)
if(isliving(user))
var/mob/living/L = user
L.looking_elsewhere = 1
L.handle_vision()
user.set_viewsize(world.view + extra_view)
GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
// TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
@@ -78,6 +82,10 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
/obj/machinery/computer/ship/proc/unlook(var/mob/user)
user.reset_view()
if(isliving(user))
var/mob/living/L = user
L.looking_elsewhere = 0
L.handle_vision()
user.set_viewsize() // reset to default
GLOB.moved_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
// TODO GLOB.stat_set_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
@@ -109,4 +117,4 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
var/M = W.resolve()
if(M)
unlook(M)
. = ..()
. = ..()
+21
View File
@@ -45,8 +45,29 @@ proc/get_deepspace(x,y)
for(var/atom/movable/AM in contents)
if(!AM.lost_in_space())
return FALSE
if(has_buckled_mobs())
for(var/mob/M in buckled_mobs)
if(!M.lost_in_space())
return FALSE
return TRUE
/obj/item/device/uav/lost_in_space()
if(state == 1)
return FALSE
return ..()
/obj/machinery/power/supermatter/lost_in_space()
return FALSE
/obj/singularity/lost_in_space()
return FALSE
/obj/vehicle/lost_in_space()
if(load && !load.lost_in_space())
return FALSE
return ..()
/mob/lost_in_space()
return isnull(client)
@@ -5,12 +5,14 @@
/obj/item/weapon/gun/energy/hooklauncher
name = "gravity whip"
desc = "A large, strange gauntlet."
icon = 'icons/obj/gun2.dmi'
icon_state = "gravwhip"
item_state = "gravwhip"
fire_sound_text = "laser blast"
fire_delay = 15
charge_cost = 300
charge_meter = FALSE
cell_type = /obj/item/weapon/cell/device/weapon
projectile_type = /obj/item/projectile/energy/hook
@@ -29,7 +31,6 @@
cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien
battery_lock = TRUE
charge_cost = 400
charge_meter = FALSE
projectile_type = /obj/item/projectile/energy/hook/ring
+60
View File
@@ -0,0 +1,60 @@
/*
* "Magic" "Guns"
*/
/obj/item/weapon/gun/magic
name = "staff of nothing"
desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years."
icon = 'icons/obj/wizard.dmi'
icon_state = "staffofnothing"
item_icons = list(
slot_l_hand_str = 'icons/mob/items/lefthand_magic.dmi',
slot_r_hand_str = 'icons/mob/items/righthand_magic.dmi',
)
fire_sound = 'sound/weapons/emitter.ogg'
w_class = ITEMSIZE_HUGE
projectile_type = null
var/checks_antimagic = TRUE
var/max_charges = 6
var/charges = 0
var/recharge_rate = 4
var/charge_tick = 0
var/can_charge = TRUE
/obj/item/weapon/gun/magic/consume_next_projectile()
if(checks_antimagic && locate(/obj/item/weapon/nullrod) in usr) return null
if(!ispath(projectile_type)) return null
if(charges <= 0) return null
charges -= 1
return new projectile_type(src)
/obj/item/weapon/gun/magic/Initialize()
. = ..()
charges = max_charges
if(can_charge)
START_PROCESSING(SSobj, src)
/obj/item/weapon/gun/magic/Destroy()
if(can_charge)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/weapon/gun/magic/process()
if (charges >= max_charges)
charge_tick = 0
return
charge_tick++
if(charge_tick < recharge_rate)
return 0
charge_tick = 0
charges++
return 1
/obj/item/weapon/gun/magic/handle_click_empty(mob/user)
if (user)
user.visible_message("*wzhzhzh*", "<span class='danger'>The [name] whizzles quietly.</span>")
else
src.visible_message("*wzhzh*")
playsound(src, 'sound/weapons/empty.ogg', 100, 1)
@@ -0,0 +1,17 @@
/obj/item/weapon/gun/magic/firestaff
name = "flaming staff"
desc = "A long, everburning torch."
icon = 'icons/obj/wizard.dmi'
icon_state = "staffoffire"
item_state = "staff"
fire_sound = 'sound/weapons/emitter.ogg'
w_class = ITEMSIZE_HUGE
checks_antimagic = TRUE
max_charges = 6
charges = 0
recharge_rate = 4
charge_tick = 0
can_charge = TRUE
projectile_type = /obj/item/projectile/energy/fireball
+2
View File
@@ -739,6 +739,8 @@
shot_from = launcher.name
silenced = launcher.silenced
if(user)
firer = user
return launch_projectile(target, target_zone, user, params, angle_override, forced_spread)
+15 -1
View File
@@ -27,13 +27,15 @@
var/list/help_messages = list("slaps", "pokes", "nudges", "bumps", "pinches")
var/done_mob_unique = FALSE // Has the projectile already done something to a mob?
var/datum/beam/chain = null
/obj/item/projectile/energy/hook/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
var/expected_distance = get_dist(target, loc)
range = expected_distance // So the hook hits the ground if no mob is hit.
target_distance = expected_distance
if(firer) // Needed to ensure later checks in impact and on hit function.
launcher_intent = firer.a_intent
firer.Beam(src,icon_state=beam_state,icon='icons/effects/beam.dmi',time=60, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=1)
chain = firer.Beam(src,icon_state=beam_state,icon='icons/effects/beam.dmi',time=60, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=1)
if(launcher_intent)
switch(launcher_intent)
@@ -58,10 +60,22 @@
..() // Does the regular launching stuff.
/obj/item/projectile/energy/hook/after_move()
if(chain)
var/origin_turf = get_turf(firer)
var/target_turf = get_turf(src)
if(!chain.static_beam && (origin_turf != chain.origin_oldloc || target_turf != chain.target_oldloc))
chain.origin_oldloc = origin_turf //so we don't keep checking against their initial positions, leading to endless Reset()+Draw() calls
chain.target_oldloc = target_turf
chain.Reset()
chain.Draw()
return
/obj/item/projectile/energy/hook/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
if(..())
perform_intent_unique(target)
/obj/item/projectile/energy/hook/on_impact(var/atom/A)
perform_intent_unique(get_turf(A))
@@ -0,0 +1,20 @@
/obj/item/projectile/energy/fireball
name = "fireball"
icon_state = "fireball2"
damage = 15
damage_type = BURN
check_armour = "bomb"
armor_penetration = 25 // It's a great ball of fire.
combustion = TRUE
/obj/item/projectile/energy/fireball/on_hit(var/atom/target, var/blocked = 0)
new /obj/effect/explosion(get_turf(target))
explosion(target, -1, 0, 2)
..()
/obj/item/projectile/energy/fireball/on_impact(var/atom/target)
new /obj/effect/explosion(get_turf(target))
explosion(target, -1, 0, 2)
..()
@@ -110,7 +110,7 @@
remove_self(volume)
/datum/reagent/blood/synthblood
name = "Synthetic blood"
name = "synthetic blood"
id = "synthblood"
color = "#999966"
volume_mod = 2
@@ -119,8 +119,16 @@
..()
if(data && !data["blood_type"])
data["blood_type"] = "O-"
if(data && data["species"])
data["species"] = null
return
/datum/reagent/blood/synthblood/dilute
name = "synthetic plasma"
id = "synthblood_dilute"
color = "#cacaaf"
volume_mod = 1.2
// pure concentrated antibodies
/datum/reagent/antibodies
data = list("antibodies"=list())
@@ -128,6 +128,17 @@
temp_range = list(T0C + 100, T0C + 120)
/datum/chemical_reaction/distilling/synthplas
name = "Distilling Synthplas"
id = "distill_synthplas"
result = "synthblood_dilute"
required_reagents = list("protein" = 2, "antibodies" = 1, "bicaridine" = 1)
result_amount = 3
reaction_rate = HALF_LIFE(15)
temp_range = list(T0C + 110, T0C + 130)
// Alcohol
/datum/chemical_reaction/distilling/beer
name = "Distilling Beer"
+11 -1
View File
@@ -19,7 +19,7 @@
var/target_temp = T20C
var/max_temp = T20C + 300
var/max_temp = T0C + 300
var/min_temp = T0C - 10
var/current_temp = T20C
@@ -86,6 +86,16 @@
update_icon()
/obj/machinery/portable_atmospherics/powered/reagent_distillery/RefreshParts()
var/total_laser_rating = 0
for(var/obj/item/weapon/stock_parts/micro_laser/ML in component_parts)
total_laser_rating += ML.rating
max_temp = initial(max_temp) + (50 * (total_laser_rating - 1))
min_temp = max(1, initial(min_temp) - (30 * (total_laser_rating - 1)))
return
/obj/machinery/portable_atmospherics/powered/reagent_distillery/proc/setup_overlay_vars()
overlay_output_beaker = image(icon = src.icon, icon_state = "[base_state]-output")
overlay_input_beaker = image(icon = src.icon, icon_state = "[base_state]-input")
@@ -27,6 +27,7 @@
var/label_text = ""
var/blood_type = null
var/reag_id = "blood"
/obj/item/weapon/reagent_containers/blood/Initialize()
. = ..()
@@ -35,7 +36,7 @@
if(blood_type != null)
label_text = "[blood_type]"
update_iv_label()
reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
reagents.add_reagent(reag_id, 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
update_icon()
/obj/item/weapon/reagent_containers/blood/on_reagent_change()
@@ -95,6 +96,14 @@
/obj/item/weapon/reagent_containers/blood/OMinus
blood_type = "O-"
/obj/item/weapon/reagent_containers/blood/synthplas
blood_type = "O-"
reag_id = "synthblood_dilute"
/obj/item/weapon/reagent_containers/blood/synthblood
blood_type = "O-"
reag_id = "synthblood"
/obj/item/weapon/reagent_containers/blood/empty
name = "Empty BloodPack"
desc = "Seems pretty useless... Maybe if there were a way to fill it?"
@@ -1,157 +1,159 @@
/obj/item/weapon/reagent_containers/borghypo
name = "cyborg hypospray"
desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment."
icon = 'icons/obj/syringe.dmi'
item_state = "hypo"
icon_state = "borghypo"
amount_per_transfer_from_this = 5
volume = 30
possible_transfer_amounts = null
var/mode = 1
var/charge_cost = 50
var/charge_tick = 0
var/recharge_time = 5 //Time it takes for shots to recharge (in seconds)
var/bypass_protection = FALSE // If true, can inject through things like spacesuits and armor.
var/list/reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin")
var/list/reagent_volumes = list()
var/list/reagent_names = list()
/obj/item/weapon/reagent_containers/borghypo/surgeon
reagent_ids = list("tricordrazine", "inaprovaline", "oxycodone", "dexalin" ,"spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/crisis
reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/lost
reagent_ids = list("tricordrazine", "bicaridine", "dexalin", "anti_toxin", "tramadol", "spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/merc
name = "advanced cyborg hypospray"
desc = "An advanced nanite and chemical synthesizer and injection system, designed for heavy-duty medical equipment. This type is capable of safely bypassing \
thick materials that other hyposprays would struggle with."
bypass_protection = TRUE // Because mercs tend to be in spacesuits.
reagent_ids = list("healing_nanites", "hyperzine", "tramadol", "oxycodone", "spaceacillin", "peridaxon", "osteodaxon", "myelamine", "synthblood")
/obj/item/weapon/reagent_containers/borghypo/Initialize()
. = ..()
for(var/T in reagent_ids)
reagent_volumes[T] = volume
var/datum/reagent/R = SSchemistry.chemical_reagents[T]
reagent_names += R.name
START_PROCESSING(SSobj, src)
/obj/item/weapon/reagent_containers/borghypo/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/weapon/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+
if(++charge_tick < recharge_time)
return 0
charge_tick = 0
if(isrobot(loc))
var/mob/living/silicon/robot/R = loc
if(R && R.cell)
for(var/T in reagent_ids)
if(reagent_volumes[T] < volume)
R.cell.use(charge_cost)
reagent_volumes[T] = min(reagent_volumes[T] + 5, volume)
return 1
/obj/item/weapon/reagent_containers/borghypo/attack(var/mob/living/M, var/mob/user)
if(!istype(M))
return
if(!reagent_volumes[reagent_ids[mode]])
to_chat(user, "<span class='warning'>The injector is empty.</span>")
return
var/mob/living/carbon/human/H = M
if(istype(H))
var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
if(!affected)
to_chat(user, "<span class='danger'>\The [H] is missing that limb!</span>")
return
else if(affected.robotic >= ORGAN_ROBOT)
to_chat(user, "<span class='danger'>You cannot inject a robotic limb.</span>")
return
if(M.can_inject(user, 1, ignore_thickness = bypass_protection))
to_chat(user, "<span class='notice'>You inject [M] with the injector.</span>")
to_chat(M, "<span class='notice'>You feel a tiny prick!</span>")
if(M.reagents)
var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
M.reagents.add_reagent(reagent_ids[mode], t)
reagent_volumes[reagent_ids[mode]] -= t
add_attack_logs(user, M, "Borg injected with [reagent_ids[mode]]")
to_chat(user, "<span class='notice'>[t] units injected. [reagent_volumes[reagent_ids[mode]]] units remaining.</span>")
return
/obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob) //Change the mode
var/t = ""
for(var/i = 1 to reagent_ids.len)
if(t)
t += ", "
if(mode == i)
t += "<b>[reagent_names[i]]</b>"
else
t += "<a href='?src=\ref[src];reagent=[reagent_ids[i]]'>[reagent_names[i]]</a>"
t = "Available reagents: [t]."
to_chat(user,t)
return
/obj/item/weapon/reagent_containers/borghypo/Topic(var/href, var/list/href_list)
if(href_list["reagent"])
var/t = reagent_ids.Find(href_list["reagent"])
if(t)
playsound(src, 'sound/effects/pop.ogg', 50, 0)
mode = t
var/datum/reagent/R = SSchemistry.chemical_reagents[reagent_ids[mode]]
to_chat(usr, "<span class='notice'>Synthesizer is now producing '[R.name]'.</span>")
/obj/item/weapon/reagent_containers/borghypo/examine(mob/user)
. = ..()
if(get_dist(user, src) <= 2)
var/datum/reagent/R = SSchemistry.chemical_reagents[reagent_ids[mode]]
. += "<span class='notice'>It is currently producing [R.name] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left.</span>"
/obj/item/weapon/reagent_containers/borghypo/service
name = "cyborg drink synthesizer"
desc = "A portable drink dispencer."
icon = 'icons/obj/drinks.dmi'
icon_state = "shaker"
charge_cost = 20
recharge_time = 3
volume = 60
possible_transfer_amounts = list(5, 10, 20, 30)
reagent_ids = list("ale", "cider", "beer", "berryjuice", "bitters", "coffee", "cognac", "cola", "dr_gibb", "egg", "gin", "gingerale", "hot_coco", "ice", "icetea", "kahlua", "lemonjuice", "lemon_lime", "limejuice", "mead", "milk", "mint", "orangejuice", "rum", "sake", "sodawater", "soymilk", "space_up", "spacemountainwind", "specialwhiskey", "sugar", "tea", "tequilla", "tomatojuice", "tonic", "vermouth", "vodka", "water", "watermelonjuice", "whiskey", "wine")
/obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user)
return
/obj/item/weapon/reagent_containers/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity)
if(!proximity)
return
if(!target.is_open_container() || !target.reagents)
return
if(!reagent_volumes[reagent_ids[mode]])
to_chat(user, "<span class='notice'>[src] is out of this reagent, give it some time to refill.</span>")
return
if(!target.reagents.get_free_space())
to_chat(user, "<span class='notice'>[target] is full.</span>")
return
var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
target.reagents.add_reagent(reagent_ids[mode], t)
reagent_volumes[reagent_ids[mode]] -= t
to_chat(user, "<span class='notice'>You transfer [t] units of the solution to [target].</span>")
return
/obj/item/weapon/reagent_containers/borghypo
name = "cyborg hypospray"
desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment."
icon = 'icons/obj/syringe.dmi'
item_state = "hypo"
icon_state = "borghypo"
amount_per_transfer_from_this = 5
volume = 30
possible_transfer_amounts = null
var/mode = 1
var/charge_cost = 50
var/charge_tick = 0
var/recharge_time = 5 //Time it takes for shots to recharge (in seconds)
var/bypass_protection = FALSE // If true, can inject through things like spacesuits and armor.
var/list/reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin")
var/list/reagent_volumes = list()
var/list/reagent_names = list()
/obj/item/weapon/reagent_containers/borghypo/surgeon
reagent_ids = list("tricordrazine", "inaprovaline", "oxycodone", "dexalin" ,"spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/crisis
reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/lost
reagent_ids = list("tricordrazine", "bicaridine", "dexalin", "anti_toxin", "tramadol", "spaceacillin")
/obj/item/weapon/reagent_containers/borghypo/merc
name = "advanced cyborg hypospray"
desc = "An advanced nanite and chemical synthesizer and injection system, designed for heavy-duty medical equipment. This type is capable of safely bypassing \
thick materials that other hyposprays would struggle with."
bypass_protection = TRUE // Because mercs tend to be in spacesuits.
reagent_ids = list("healing_nanites", "hyperzine", "tramadol", "oxycodone", "spaceacillin", "peridaxon", "osteodaxon", "myelamine", "synthblood")
/obj/item/weapon/reagent_containers/borghypo/Initialize()
. = ..()
for(var/T in reagent_ids)
reagent_volumes[T] = volume
var/datum/reagent/R = SSchemistry.chemical_reagents[T]
reagent_names += R.name
START_PROCESSING(SSobj, src)
/obj/item/weapon/reagent_containers/borghypo/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/weapon/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg+
if(++charge_tick < recharge_time)
return 0
charge_tick = 0
if(isrobot(loc))
var/mob/living/silicon/robot/R = loc
if(R && R.cell)
for(var/T in reagent_ids)
if(reagent_volumes[T] < volume)
R.cell.use(charge_cost)
reagent_volumes[T] = min(reagent_volumes[T] + 5, volume)
return 1
/obj/item/weapon/reagent_containers/borghypo/attack(var/mob/living/M, var/mob/user)
if(!istype(M))
return
if(!reagent_volumes[reagent_ids[mode]])
to_chat(user, "<span class='warning'>The injector is empty.</span>")
return
var/mob/living/carbon/human/H = M
if(istype(H))
var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
if(!affected)
to_chat(user, "<span class='danger'>\The [H] is missing that limb!</span>")
return
/* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity.
else if(affected.robotic >= ORGAN_ROBOT)
to_chat(user, "<span class='danger'>You cannot inject a robotic limb.</span>")
return
*/
if(M.can_inject(user, 1, ignore_thickness = bypass_protection))
to_chat(user, "<span class='notice'>You inject [M] with the injector.</span>")
to_chat(M, "<span class='notice'>You feel a tiny prick!</span>")
if(M.reagents)
var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
M.reagents.add_reagent(reagent_ids[mode], t)
reagent_volumes[reagent_ids[mode]] -= t
add_attack_logs(user, M, "Borg injected with [reagent_ids[mode]]")
to_chat(user, "<span class='notice'>[t] units injected. [reagent_volumes[reagent_ids[mode]]] units remaining.</span>")
return
/obj/item/weapon/reagent_containers/borghypo/attack_self(mob/user as mob) //Change the mode
var/t = ""
for(var/i = 1 to reagent_ids.len)
if(t)
t += ", "
if(mode == i)
t += "<b>[reagent_names[i]]</b>"
else
t += "<a href='?src=\ref[src];reagent=[reagent_ids[i]]'>[reagent_names[i]]</a>"
t = "Available reagents: [t]."
to_chat(user,t)
return
/obj/item/weapon/reagent_containers/borghypo/Topic(var/href, var/list/href_list)
if(href_list["reagent"])
var/t = reagent_ids.Find(href_list["reagent"])
if(t)
playsound(src, 'sound/effects/pop.ogg', 50, 0)
mode = t
var/datum/reagent/R = SSchemistry.chemical_reagents[reagent_ids[mode]]
to_chat(usr, "<span class='notice'>Synthesizer is now producing '[R.name]'.</span>")
/obj/item/weapon/reagent_containers/borghypo/examine(mob/user)
. = ..()
if(get_dist(user, src) <= 2)
var/datum/reagent/R = SSchemistry.chemical_reagents[reagent_ids[mode]]
. += "<span class='notice'>It is currently producing [R.name] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left.</span>"
/obj/item/weapon/reagent_containers/borghypo/service
name = "cyborg drink synthesizer"
desc = "A portable drink dispencer."
icon = 'icons/obj/drinks.dmi'
icon_state = "shaker"
charge_cost = 20
recharge_time = 3
volume = 60
possible_transfer_amounts = list(5, 10, 20, 30)
reagent_ids = list("ale", "cider", "beer", "berryjuice", "bitters", "coffee", "cognac", "cola", "dr_gibb", "egg", "gin", "gingerale", "hot_coco", "ice", "icetea", "kahlua", "lemonjuice", "lemon_lime", "limejuice", "mead", "milk", "mint", "orangejuice", "rum", "sake", "sodawater", "soymilk", "space_up", "spacemountainwind", "specialwhiskey", "sugar", "tea", "tequilla", "tomatojuice", "tonic", "vermouth", "vodka", "water", "watermelonjuice", "whiskey", "wine")
/obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user)
return
/obj/item/weapon/reagent_containers/borghypo/service/afterattack(var/obj/target, var/mob/user, var/proximity)
if(!proximity)
return
if(!target.is_open_container() || !target.reagents)
return
if(!reagent_volumes[reagent_ids[mode]])
to_chat(user, "<span class='notice'>[src] is out of this reagent, give it some time to refill.</span>")
return
if(!target.reagents.get_free_space())
to_chat(user, "<span class='notice'>[target] is full.</span>")
return
var/t = min(amount_per_transfer_from_this, reagent_volumes[reagent_ids[mode]])
target.reagents.add_reagent(reagent_ids[mode], t)
reagent_volumes[reagent_ids[mode]] -= t
to_chat(user, "<span class='notice'>You transfer [t] units of the solution to [target].</span>")
return
@@ -42,9 +42,11 @@
if(!affected)
to_chat(user, "<span class='danger'>\The [H] is missing that limb!</span>")
return
/* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity.
else if(affected.robotic >= ORGAN_ROBOT)
to_chat(user, "<span class='danger'>You cannot inject a robotic limb.</span>")
return
*/
if(!H.stat)
if(H != user)
@@ -169,9 +169,11 @@
if(!affected)
to_chat(user, "<span class='danger'>\The [H] is missing that limb!</span>")
return
/* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity.
else if(affected.robotic >= ORGAN_ROBOT)
to_chat(user, "<span class='danger'>You cannot inject a robotic limb.</span>")
return
*/
var/cycle_time = injtime*0.33 //33% of the time slept between 5u doses
var/warmup_time = 0 //0 for containers
+3
View File
@@ -536,3 +536,6 @@ ENABLE_NIGHT_SHIFTS
# ALLOW_BYOND_LINKS
# ALLOW_DISCORD_LINKS
ALLOW_URL_LINKS
# Control which submaps are loaded for the Dynamic Engine system
ENGINE_MAP Supermatter Engine,Edison's Bane
@@ -0,0 +1,36 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Killian
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- tweak: "You can now inject reagents directly into a synth's 'blood' stream using syringes and hypos (inc. borg hypos). Taking oil/coolant samples is still impossible."
+38
View File
@@ -0,0 +1,38 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Mechoid
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Added Distillery to Chemistry, beside the Grinder."
- rscadd: "Added distilling recipe for Synthetic Plasma, which acts as a blood-restoration of 1.2 units per synthplas. Also orderable in cargo."
- tweak: "Moves wrapper, spacecleaner, and labeller from the grinder table to the Chem locker."
@@ -0,0 +1,37 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: SplinterGP
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Adds new hailer masks with quotes with sound, allowing you to use a hailer on a face mask to attach a security hailer into one."
- soundadd: "Adds new sound effects for hailer face masks."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 34 KiB

+2 -2
View File
@@ -6736,7 +6736,7 @@
"cDl" = (/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/paleblue/border{dir = 8},/obj/effect/floor_decal/borderfloorwhite/corner2{dir = 10},/obj/effect/floor_decal/corner/paleblue/bordercorner2{dir = 10},/turf/simulated/floor/tiled/white,/area/medical/foyer)
"cDm" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled/white,/area/medical/foyer)
"cDn" = (/obj/structure/bed/chair{dir = 8},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/obj/effect/floor_decal/borderfloorwhite/corner2{dir = 5},/obj/effect/floor_decal/corner/paleblue/bordercorner2{dir = 5},/turf/simulated/floor/tiled/white,/area/medical/foyer)
"cDo" = (/obj/structure/table/glass,/obj/item/weapon/packageWrap,/obj/item/weapon/hand_labeler,/obj/item/weapon/reagent_containers/spray/cleaner{desc = "Someone has crossed out the 'Space' from Space Cleaner and written in Chemistry. Scrawled on the back is, 'Okay, whoever filled this with polytrinic acid, it was only funny the first time. It was hard enough replacing the CMO's first cat!'"; name = "Chemistry Cleaner"},/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cDo" = (/obj/structure/table/glass,/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/obj/machinery/portable_atmospherics/powered/reagent_distillery,/obj/item/weapon/reagent_containers/glass/beaker/large,/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cDp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cDq" = (/obj/structure/closet/secure_closet/chemical,/obj/item/weapon/storage/box/pillbottles,/obj/machinery/alarm{dir = 8; pixel_x = 22},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/beige/border{dir = 4},/obj/item/weapon/storage/box/syringes,/obj/item/weapon/tool/screwdriver,/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cDr" = (/obj/structure/bed/chair/wheelchair,/obj/item/device/radio/intercom/department/medbay{dir = 4; pixel_x = -21},/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/paleblue/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage)
@@ -6824,7 +6824,7 @@
"cEV" = (/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/item/stack/material/phoron,/obj/structure/table/glass,/obj/machinery/light,/obj/effect/floor_decal/borderfloorwhite/corner{dir = 8},/obj/effect/floor_decal/corner/beige/bordercorner{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cEW" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/disposalpipe/segment,/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 8},/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 5},/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cEX" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/camera/network/medbay{c_tag = "MED - Chemistry"; dir = 1},/obj/effect/floor_decal/borderfloorwhite/corner,/obj/effect/floor_decal/corner/beige/bordercorner,/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cEY" = (/obj/structure/closet/wardrobe/chemistry_white,/obj/item/device/radio/headset/headset_med,/obj/machinery/power/apc{name = "south bump"; pixel_y = -24},/obj/machinery/light_switch{pixel_x = 11; pixel_y = -24},/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 21},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/item/weapon/storage/box/pillbottles,/obj/effect/floor_decal/borderfloorwhite{dir = 6},/obj/effect/floor_decal/corner/beige/border{dir = 6},/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cEY" = (/obj/structure/closet/wardrobe/chemistry_white,/obj/item/device/radio/headset/headset_med,/obj/machinery/power/apc{name = "south bump"; pixel_y = -24},/obj/machinery/light_switch{pixel_x = 11; pixel_y = -24},/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 21},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/item/weapon/storage/box/pillbottles,/obj/effect/floor_decal/borderfloorwhite{dir = 6},/obj/effect/floor_decal/corner/beige/border{dir = 6},/obj/item/weapon/reagent_containers/spray/cleaner{desc = "Someone has crossed out the 'Space' from Space Cleaner and written in Chemistry. Scrawled on the back is, 'Okay, whoever filled this with polytrinic acid, it was only funny the first time. It was hard enough replacing the CMO's first cat!'"; name = "Chemistry Cleaner"},/obj/item/weapon/hand_labeler,/obj/item/weapon/packageWrap,/turf/simulated/floor/tiled/white,/area/medical/chemistry)
"cEZ" = (/obj/machinery/alarm{dir = 4; pixel_x = -22},/turf/simulated/floor,/area/maintenance/cargo)
"cFa" = (/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 8},/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 5},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage)
"cFb" = (/obj/structure/table/standard,/obj/item/roller,/obj/item/roller{pixel_y = 8},/obj/item/roller{pixel_y = 16},/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/machinery/light_switch{name = "light switch "; pixel_x = 36},/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/structure/disposalpipe/segment,/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage)
+5 -1
View File
@@ -1593,6 +1593,7 @@
#include "code\modules\clothing\masks\boxing.dm"
#include "code\modules\clothing\masks\breath.dm"
#include "code\modules\clothing\masks\gasmask.dm"
#include "code\modules\clothing\masks\hailer.dm"
#include "code\modules\clothing\masks\miscellaneous.dm"
#include "code\modules\clothing\masks\voice.dm"
#include "code\modules\clothing\rings\material.dm"
@@ -2629,6 +2630,7 @@
#include "code\modules\projectiles\brokenguns\projectile.dm"
#include "code\modules\projectiles\guns\energy.dm"
#include "code\modules\projectiles\guns\launcher.dm"
#include "code\modules\projectiles\guns\magic.dm"
#include "code\modules\projectiles\guns\modular_guns.dm"
#include "code\modules\projectiles\guns\projectile.dm"
#include "code\modules\projectiles\guns\vox.dm"
@@ -2645,6 +2647,7 @@
#include "code\modules\projectiles\guns\launcher\pneumatic.dm"
#include "code\modules\projectiles\guns\launcher\rocket.dm"
#include "code\modules\projectiles\guns\launcher\syringe_gun.dm"
#include "code\modules\projectiles\guns\magic\fireball.dm"
#include "code\modules\projectiles\guns\magnetic\bore.dm"
#include "code\modules\projectiles\guns\magnetic\gasthrower.dm"
#include "code\modules\projectiles\guns\magnetic\magnetic.dm"
@@ -2670,6 +2673,7 @@
#include "code\modules\projectiles\projectile\explosive.dm"
#include "code\modules\projectiles\projectile\force.dm"
#include "code\modules\projectiles\projectile\hook.dm"
#include "code\modules\projectiles\projectile\magic.dm"
#include "code\modules\projectiles\projectile\magnetic.dm"
#include "code\modules\projectiles\projectile\pellets.dm"
#include "code\modules\projectiles\projectile\scatter.dm"
@@ -2729,7 +2733,7 @@
#include "code\modules\reagents\hoses\hose.dm"
#include "code\modules\reagents\hoses\hose_connector.dm"
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\borghydro.dm"
#include "code\modules\reagents\reagent_containers\borghypo.dm"
#include "code\modules\reagents\reagent_containers\dropper.dm"
#include "code\modules\reagents\reagent_containers\glass.dm"
#include "code\modules\reagents\reagent_containers\hypospray.dm"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -369,7 +369,7 @@ rules:
# max-depth: error
## Enforce a maximum line length
max-len: [error, {
code: 80,
code: 120, # Bump to 140 if this is still too in the way
## Ignore imports
ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
ignoreUrls: true,
+2 -2
View File
@@ -77,7 +77,7 @@ input. The input's `action` and `params` are passed to the proc.
```dm
/obj/machinery/my_machine/tgui_act(action, params)
if(..())
return
return TRUE
if(action == "change_color")
var/new_color = params["color"]
if(!(color in allowed_coors))
@@ -305,7 +305,7 @@ upon code review):
/obj/copypasta/tgui_act(action, params)
if(..())
return
return TRUE
switch(action)
if("copypasta")
var/newvar = params["var"]
+4 -3
View File
@@ -91,7 +91,7 @@ export const toTitleCase = str => {
return str;
}
// Handle string
const WORDS_UPPER = ['Id', 'Tv'];
const WORDS_UPPER = ['Id', 'Tv', 'Rcd'];
const WORDS_LOWER = [
'A', 'An', 'And', 'As', 'At', 'But', 'By', 'For', 'For', 'From', 'In',
'Into', 'Near', 'Nor', 'Of', 'On', 'Onto', 'Or', 'The', 'To', 'With',
@@ -105,7 +105,7 @@ export const toTitleCase = str => {
}
for (let word of WORDS_UPPER) {
const regex = new RegExp('\\b' + word + '\\b', 'g');
currentStr = currentStr.replace(regex, str => str.toLowerCase());
currentStr = currentStr.replace(regex, str => str.toUpperCase());
}
return currentStr;
};
@@ -120,7 +120,7 @@ export const decodeHtmlEntities = str => {
if (!str) {
return str;
}
const translate_re = /&(nbsp|amp|quot|lt|gt|apos);/g;
const translate_re = /&(nbsp|amp|quot|lt|gt|apos|trade);/g;
const translate = {
nbsp: ' ',
amp: '&',
@@ -128,6 +128,7 @@ export const decodeHtmlEntities = str => {
lt: '<',
gt: '>',
apos: '\'',
trade: '™',
};
return str
// Newline tags
+20
View File
@@ -73,7 +73,10 @@ const mapColorPropTo = attrName => (style, value) => {
const styleMapperByPropName = {
// Direct mapping
display: mapRawPropTo('display'),
position: mapRawPropTo('position'),
float: mapRawPropTo('float'),
clear: mapRawPropTo('clear'),
overflow: mapRawPropTo('overflow'),
overflowX: mapRawPropTo('overflow-x'),
overflowY: mapRawPropTo('overflow-y'),
@@ -99,6 +102,8 @@ const styleMapperByPropName = {
opacity: mapRawPropTo('opacity'),
textAlign: mapRawPropTo('text-align'),
verticalAlign: mapRawPropTo('vertical-align'),
textTransform: mapRawPropTo('text-transform'),
wordWrap: mapRawPropTo('word-wrap'),
// Boolean props
inline: mapBooleanPropTo('display', 'inline-block'),
bold: mapBooleanPropTo('font-weight', 'bold'),
@@ -136,6 +141,18 @@ const styleMapperByPropName = {
color: mapColorPropTo('color'),
textColor: mapColorPropTo('color'),
backgroundColor: mapColorPropTo('background-color'),
// Flex props
order: mapRawPropTo('order'),
flexDirection: mapRawPropTo('flex-direction'),
flexGrow: mapRawPropTo('flex-grow'),
flexShrink: mapRawPropTo('flex-shrink'),
flexWrap: mapRawPropTo('flex-wrap'),
flexFlow: mapRawPropTo('flex-flow'),
flexBasis: mapRawPropTo('flex-basis'),
flex: mapRawPropTo('flex'),
alignItems: mapRawPropTo('align-items'),
justifyContent: mapRawPropTo('justify-content'),
alignSelf: mapRawPropTo('align-self'),
// Utility props
fillPositionedParent: (style, value) => {
if (value) {
@@ -151,6 +168,9 @@ const styleMapperByPropName = {
export const computeBoxProps = props => {
const computedProps = {};
const computedStyles = {};
if (props.double) {
computedStyles["transform"] = "scale(2);";
}
// Compute props
for (let propName of Object.keys(props)) {
if (propName === 'style') {
+8 -2
View File
@@ -25,10 +25,13 @@ export const Button = props => {
selected,
tooltip,
tooltipPosition,
tooltipScale,
ellipsis,
content,
iconRotation,
iconSpin,
iconColor,
iconSize,
children,
onclick,
onClick,
@@ -89,14 +92,17 @@ export const Button = props => {
<Icon
name={icon}
rotation={iconRotation}
spin={iconSpin} />
spin={iconSpin}
color={iconColor}
fontSize={iconSize} />
)}
{content}
{children}
{tooltip && (
<Tooltip
content={tooltip}
position={tooltipPosition} />
position={tooltipPosition}
scale={tooltipScale} />
)}
</Box>
);
@@ -170,6 +170,7 @@ export class DraggableControl extends Component {
onDrag,
children,
// Input props
forcedInputWidth,
height,
lineHeight,
fontSize,
@@ -206,6 +207,7 @@ export class DraggableControl extends Component {
style={{
display: !editing ? 'none' : undefined,
height: height,
width: forcedInputWidth,
'line-height': lineHeight,
'font-size': fontSize,
}}
+14 -10
View File
@@ -52,16 +52,18 @@ export class Dropdown extends Component {
{option}
</div>
));
ops.unshift((
<div
key={placeholder}
className="Dropdown__menuentry"
onClick={() => {
this.setSelected(null);
}}>
-- {placeholder} --
</div>
));
if (placeholder) {
ops.unshift((
<div
key={placeholder}
className="Dropdown__menuentry"
onClick={() => {
this.setSelected(null);
}}>
-- {placeholder} --
</div>
));
}
return ops;
}
@@ -73,6 +75,7 @@ export class Dropdown extends Component {
noscroll,
nochevron,
width,
maxHeight,
onClick,
selected,
disabled,
@@ -92,6 +95,7 @@ export class Dropdown extends Component {
tabIndex="-1"
style={{
'width': width,
'max-height': maxHeight,
}}
className={classes([
noscroll && 'Dropdown__menu-noscroll' || 'Dropdown__menu',
+4
View File
@@ -13,9 +13,11 @@ export const computeFlexProps = props => {
direction,
wrap,
align,
alignContent,
justify,
inline,
spacing = 0,
spacingPrecise = 0,
...rest
} = props;
return {
@@ -28,6 +30,7 @@ export const computeFlexProps = props => {
),
inline && 'Flex--inline',
spacing > 0 && 'Flex--spacing--' + spacing,
spacingPrecise > 0 && 'Flex--spacingPrecise--' + spacingPrecise,
className,
]),
style: {
@@ -35,6 +38,7 @@ export const computeFlexProps = props => {
'flex-direction': direction,
'flex-wrap': wrap,
'align-items': align,
'align-content': alignContent,
'justify-content': justify,
},
...rest,
+6
View File
@@ -76,6 +76,11 @@ export class Input extends Component {
const input = this.inputRef.current;
if (input) {
input.value = toInputValue(nextValue);
if (this.props.autofocus) {
input.focus();
input.selectionStart = 0;
input.selectionEnd = input.value.length;
}
}
}
@@ -104,6 +109,7 @@ export class Input extends Component {
value,
maxLength,
placeholder,
autofocus,
...boxProps
} = props;
// Box props
+7 -1
View File
@@ -21,6 +21,7 @@ export const Knob = props => {
const {
// Draggable props (passthrough)
animated,
forcedInputWidth,
format,
maxValue,
minValue,
@@ -40,6 +41,7 @@ export const Knob = props => {
size,
bipolar,
children,
popUpPosition,
...rest
} = props;
return (
@@ -47,6 +49,7 @@ export const Knob = props => {
dragMatrix={[0, -1]}
{...{
animated,
forcedInputWidth,
format,
maxValue,
minValue,
@@ -107,7 +110,10 @@ export const Knob = props => {
</div>
</div>
{dragging && (
<div className="Knob__popupValue">
<div className={classes([
'Knob__popupValue',
popUpPosition && 'Knob__popupValue--' + popUpPosition,
])}>
{displayElement}
</div>
)}
@@ -20,6 +20,7 @@ export const LabeledListItem = props => {
labelColor = 'label',
color,
textAlign,
verticalAlign,
buttons,
content,
children,
@@ -33,6 +34,7 @@ export const LabeledListItem = props => {
<Box
as="td"
color={labelColor}
verticalAlign={verticalAlign}
className={classes([
'LabeledList__cell',
'LabeledList__label',
@@ -43,6 +45,7 @@ export const LabeledListItem = props => {
as="td"
color={color}
textAlign={textAlign}
verticalAlign={verticalAlign}
className={classes([
'LabeledList__cell',
'LabeledList__content',
+12 -1
View File
@@ -6,10 +6,21 @@ export const Modal = props => {
const {
className,
children,
onEnter,
...rest
} = props;
let handleKeyDown;
if (onEnter) {
handleKeyDown = e => {
let key = e.which || e.keyCode;
if (key === 13) {
onEnter(e);
}
};
}
return (
<Dimmer>
<Dimmer
onKeyDown={handleKeyDown}>
<div
className={classes([
'Modal',
+28 -28
View File
@@ -2,16 +2,15 @@ import { Box, Icon, Tooltip } from '.';
import { Component } from 'inferno';
import { useBackend } from "../backend";
import { resolveAsset } from '../assets';
import { logger } from '../logging';
export class NanoMap extends Component {
constructor(props) {
super(props);
// Auto center based on window size
const Xcenter = (window.innerWidth / 2) - 256;
this.state = {
offsetX: Xcenter,
offsetX: 0,
offsetY: 0,
transform: 'none',
dragging: false,
@@ -42,8 +41,8 @@ export class NanoMap extends Component {
const newOffsetX = e.screenX - state.originX;
const newOffsetY = e.screenY - state.originY;
if (prevState.dragging) {
state.offsetX += newOffsetX;
state.offsetY += newOffsetY;
state.offsetX += (newOffsetX / this.props.zoom);
state.offsetY += (newOffsetY / this.props.zoom);
state.originX = e.screenX;
state.originY = e.screenY;
} else {
@@ -71,11 +70,12 @@ export class NanoMap extends Component {
const { offsetX, offsetY } = this.state;
const { children, zoom, reset } = this.props;
let matrix
= `matrix(${zoom}, 0, 0, ${zoom}, ${offsetX * zoom}, ${offsetY * zoom})`;
const newStyle = {
width: '512px',
height: '512px',
"margin-top": offsetY + 'px',
"margin-left": offsetX + 'px',
width: '560px',
height: '560px',
"overflow": "hidden",
"position": "relative",
"padding": "0px",
@@ -83,8 +83,7 @@ export class NanoMap extends Component {
"url("+config.map+"_nanomap_z"+config.mapZLevel+".png)",
"background-size": "cover",
"text-align": "center",
"transform-origin": "center center",
"transform": "scale(" + zoom + ")",
"transform": matrix,
};
return (
@@ -110,25 +109,26 @@ const NanoMapMarker = (props, context) => {
icon,
tooltip,
color,
onClick,
} = props;
const rx = -256 * (zoom - 1) + x * (2 * zoom) - 1.5 * zoom - 3;
const ry = 512 * zoom - (y * 2 * zoom) + zoom - 1.5;
const rx = (x * 4) - 5;
const ry = (y * 4) - 4;
return (
<div style={"transform: scale(" + 1 / zoom + ")"}>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
top={ry + 'px'}
left={rx + 'px'} >
<Icon
name={icon}
color={color}
fontSize="6px"
/>
<Tooltip content={tooltip} />
</Box>
</div>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
bottom={ry + 'px'}
left={rx + 'px'}
onMouseDown={onClick} >
<Icon
name={icon}
color={color}
fontSize="4px"
/>
<Tooltip content={tooltip} scale={zoom} />
</Box>
);
};
+11 -1
View File
@@ -14,7 +14,11 @@ export const Section = props => {
level = 1,
buttons,
fill,
stretchContents,
noTopPadding,
children,
scrollable,
flexGrow,
...rest
} = props;
const hasTitle = !isFalsy(title) || !isFalsy(buttons);
@@ -25,6 +29,8 @@ export const Section = props => {
'Section',
'Section--level--' + level,
fill && 'Section--fill',
scrollable && 'Section--scrollable',
flexGrow && 'Section--flex',
className,
...computeBoxClassName(rest),
])}
@@ -40,7 +46,11 @@ export const Section = props => {
</div>
)}
{hasContent && (
<div className="Section__content">
<div className={classes([
"Section__content",
!!stretchContents && "Section__content--stretchContents",
!!noTopPadding && "Section__content--noTopPadding",
])}>
{children}
</div>
)}
+2
View File
@@ -4,6 +4,7 @@ export const Tooltip = props => {
const {
content,
position = 'bottom',
scale,
} = props;
// Empirically calculated length of the string,
// at which tooltip text starts to overflow.
@@ -14,6 +15,7 @@ export const Tooltip = props => {
'Tooltip',
long && 'Tooltip--long',
position && 'Tooltip--' + position,
scale && 'Tooltip--scale--' + Math.floor(scale),
])}
data-tooltip={content} />
);
+1 -1
View File
@@ -26,4 +26,4 @@ export { Section } from './Section';
export { Slider } from './Slider';
export { Table } from './Table';
export { Tabs } from './Tabs';
export { Tooltip } from './Tooltip';
export { Tooltip } from './Tooltip';
+94 -44
View File
@@ -4,6 +4,10 @@ export const UI_UPDATE = 1;
export const UI_DISABLED = 0;
export const UI_CLOSE = -1;
// Atmospheric helpers
/** 0.0 Degrees Celsius in Kelvin */
export const T0C = 273.15;
// All game related colors are stored here
export const COLORS = {
// Department colors
@@ -48,77 +52,105 @@ export const CSS_COLORS = [
'label',
];
// If you ever add a new radio channel, you can either manually update this, or
// go use /client/verb/generate_tgui_radio_constants() in communications.dm.
export const RADIO_CHANNELS = [
{
name: 'Syndicate',
freq: 1213,
color: '#a52a2a',
"name": "Mercenary",
"freq": 1213,
"color": "#6D3F40",
},
{
name: 'Red Team',
freq: 1215,
color: '#ff4444',
"name": "Raider",
"freq": 1277,
"color": "#6D3F40",
},
{
name: 'Blue Team',
freq: 1217,
color: '#3434fd',
"name": "Special Ops",
"freq": 1341,
"color": "#5C5C8A",
},
{
name: 'CentCom',
freq: 1337,
color: '#2681a5',
"name": "AI Private",
"freq": 1343,
"color": "#FF00FF",
},
{
name: 'Supply',
freq: 1347,
color: '#b88646',
"name": "Response Team",
"freq": 1345,
"color": "#5C5C8A",
},
{
name: 'Service',
freq: 1349,
color: '#6ca729',
"name": "Supply",
"freq": 1347,
"color": "#5F4519",
},
{
name: 'Science',
freq: 1351,
color: '#c68cfa',
"name": "Service",
"freq": 1349,
"color": "#6eaa2c",
},
{
name: 'Command',
freq: 1353,
color: '#5177ff',
"name": "Science",
"freq": 1351,
"color": "#993399",
},
{
name: 'Medical',
freq: 1355,
color: '#57b8f0',
"name": "Command",
"freq": 1353,
"color": "#193A7A",
},
{
name: 'Engineering',
freq: 1357,
color: '#f37746',
"name": "Medical",
"freq": 1355,
"color": "#008160",
},
{
name: 'Security',
freq: 1359,
color: '#dd3535',
"name": "Engineering",
"freq": 1357,
"color": "#A66300",
},
{
name: 'AI Private',
freq: 1447,
color: '#d65d95',
"name": "Security",
"freq": 1359,
"color": "#A30000",
},
{
name: 'Common',
freq: 1459,
color: '#1ecc43',
"name": "Explorer",
"freq": 1361,
"color": "#555555",
},
{
"name": "Talon",
"freq": 1363,
"color": "#555555",
},
{
"name": "Common",
"freq": 1459,
"color": "#008000",
},
{
"name": "Entertainment",
"freq": 1461,
"color": "#339966",
},
{
"name": "Security(I)",
"freq": 1475,
"color": "#008000",
},
{
"name": "Medical(I)",
"freq": 1485,
"color": "#008000",
},
];
const GASES = [
{
'id': 'o2',
'id': 'oxygen',
'name': 'Oxygen',
'label': 'O₂',
'color': 'blue',
@@ -130,15 +162,15 @@ const GASES = [
'color': 'red',
},
{
'id': 'co2',
'id': 'carbon dioxide',
'name': 'Carbon Dioxide',
'label': 'CO₂',
'color': 'grey',
},
{
'id': 'plasma',
'name': 'Plasma',
'label': 'Plasma',
'id': 'phoron',
'name': 'Phoron',
'label': 'Phoron',
'color': 'pink',
},
{
@@ -201,6 +233,24 @@ const GASES = [
'label': 'H₂',
'color': 'white',
},
{
'id': 'other',
'name': 'Other',
'label': 'Other',
'color': 'white',
},
{
'id': 'pressure',
'name': 'Pressure',
'label': 'Pressure',
'color': 'average',
},
{
'id': 'temperature',
'name': 'Temperature',
'label': 'Temperature',
'color': 'yellow',
},
];
export const getGasLabel = (gasId, fallbackValue) => {
+20
View File
@@ -94,3 +94,23 @@ export const formatMoney = (value, precision = 0) => {
}
return result;
};
export const formatCommaNumber = value => {
if (!Number.isFinite(value)) {
return value;
}
// From http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
let parts = value.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
};
// Function from https://stackoverflow.com/a/34841026. CC BY-SA 4.0.
export const formatTime = seconds => {
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor(seconds / 60) % 60;
return [hours, minutes, seconds % 60]
.map(v => v < 10 ? "0" + v : v)
.filter((v, i) => v !== "00" || i > 0)
.join(":");
};
+4
View File
@@ -17,6 +17,10 @@ export const KEY_CTRL = 17;
export const KEY_ALT = 18;
export const KEY_ESCAPE = 27;
export const KEY_SPACE = 32;
export const KEY_ARROWLEFT = 37;
export const KEY_ARROWUP = 38;
export const KEY_ARROWRIGHT = 39;
export const KEY_ARROWDOWN = 40;
export const KEY_0 = 48;
export const KEY_1 = 49;
export const KEY_2 = 50;
+4
View File
@@ -43,6 +43,10 @@ let reactRoot;
let initialRender = true;
const renderLayout = () => {
let loadingRoot = document.getElementById('tgui-loading');
if (loadingRoot) {
loadingRoot.style.display = 'none';
}
perf.mark('render/start');
const state = store.getState();
const { suspended, assets } = selectBackend(state);
+122
View File
@@ -0,0 +1,122 @@
import { useBackend } from "../backend";
import { Button, ProgressBar, LabeledList, Box, Section } from "../components";
import { Window } from "../layouts";
export const AICard = (props, context) => {
const { act, data } = useBackend(context);
const {
has_ai,
integrity,
backup_capacitor,
flushing,
has_laws,
laws,
wireless,
radio,
} = data;
if (has_ai === 0) {
return (
<Window
width={600}
height={470}
resizable>
<Window.Content>
<Section title="Stored AI">
<Box>
<h3>No AI detected.</h3>
</Box>
</Section>
</Window.Content>
</Window>
);
} else {
let integrityColor = null; // Handles changing color of the integrity bar
if (integrity >= 75) { integrityColor = 'green'; }
else if (integrity >= 25) { integrityColor = 'yellow'; }
else { integrityColor = 'red'; }
let powerColor = null;
if (backup_capacitor >= 75) { powerColor = 'green'; }
if (backup_capacitor >= 25) { powerColor = 'yellow'; }
else { powerColor = 'red'; }
return (
<Window
width={600}
height={470}
resizable>
<Window.Content scrollable>
<Section title="Stored AI">
<Box bold display="inline-block">
<h3>{name}</h3>
</Box>
<Box>
<LabeledList>
<LabeledList.Item label="Integrity">
<ProgressBar
color={integrityColor}
value={integrity/100} />
</LabeledList.Item>
<LabeledList.Item label="Power">
<ProgressBar
color={powerColor}
value={backup_capacitor/100} />
</LabeledList.Item>
</LabeledList>
</Box>
<Box color="red">
<h2>{flushing === 1 ? "Wipe of AI in progress..." : ""}</h2>
</Box>
</Section>
<Section title="Laws">
{!!has_laws && (
<Box>
{laws.map((value, key) => (
<Box key={key} display="inline-block">
{value}
</Box>
))}
</Box>
) || ( // Else, no laws.
<Box color="red">
<h3>No laws detected.</h3>
</Box>
)}
</Section>
<Section title="Actions">
<LabeledList>
<LabeledList.Item label="Wireless Activity">
<Button
icon={wireless ? "check" : "times"}
content={wireless ? "Enabled" : "Disabled"}
color={wireless ? "green" : "red"}
onClick={() => act("wireless")} />
</LabeledList.Item>
<LabeledList.Item label="Subspace Transceiver">
<Button
icon={radio ? "check" : "times"}
content={radio ? "Enabled" : "Disabled"}
color={radio ? "green" : "red"}
onClick={() => act("radio")} />
</LabeledList.Item>
<LabeledList.Item label="AI Power">
<Button.Confirm
icon="radiation"
confirmIcon="radiation"
disabled={flushing || integrity === 0}
confirmColor="red"
content="Shutdown"
onClick={() => act("wipe")} />
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
}
};
+288
View File
@@ -0,0 +1,288 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Box, Button, Dimmer, Icon, LabeledList, NoticeBox, ProgressBar, Section, Flex } from '../components';
import { Window } from '../layouts';
import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox';
import { FullscreenNotice } from './common/FullscreenNotice';
export const APC = (props, context) => {
const { act, data } = useBackend(context);
let body = <ApcContent />;
if (data.gridCheck) {
body = <GridCheck />;
} else if (data.failTime) {
body = <ApcFailure />;
}
return (
<Window
width={450}
height={475}
resizable>
<Window.Content scrollable>
{body}
</Window.Content>
</Window>
);
};
const powerStatusMap = {
2: {
color: 'good',
externalPowerText: 'External Power',
chargingText: 'Fully Charged',
},
1: {
color: 'average',
externalPowerText: 'Low External Power',
chargingText: 'Charging',
},
0: {
color: 'bad',
externalPowerText: 'No External Power',
chargingText: 'Not Charging',
},
};
const malfMap = {
1: {
icon: 'terminal',
content: 'Override Programming',
action: 'hack',
},
// 2: {
// icon: 'caret-square-down',
// content: 'Shunt Core Process',
// action: 'occupy',
// },
// 3: {
// icon: 'caret-square-left',
// content: 'Return to Main Core',
// action: 'deoccupy',
// },
// 4: {
// icon: 'caret-square-down',
// content: 'Shunt Core Process',
// action: 'occupy',
// },
};
const ApcContent = (props, context) => {
const { act, data } = useBackend(context);
const locked = data.locked && !data.siliconUser;
const normallyLocked = data.normallyLocked;
const externalPowerStatus = powerStatusMap[data.externalPower]
|| powerStatusMap[0];
const chargingStatus = powerStatusMap[data.chargingStatus]
|| powerStatusMap[0];
const channelArray = data.powerChannels || [];
// const malfStatus = malfMap[data.malfStatus] || null;
const adjustedCellChange = data.powerCellStatus / 100;
return (
<Fragment>
<InterfaceLockNoticeBox deny={data.emagged} denialMessage={(
<Fragment>
<Box color="bad" fontSize="1.5rem">Fault in ID authenticator.</Box>
<Box color="bad">Please contact maintenance for service.</Box>
</Fragment>
)} />
<Section title="Power Status">
<LabeledList>
<LabeledList.Item
label="Main Breaker"
color={externalPowerStatus.color}
buttons={(
<Button
icon={data.isOperating ? 'power-off' : 'times'}
content={data.isOperating ? 'On' : 'Off'}
selected={data.isOperating && !locked}
color={data.isOperating ? "" : "bad"}
disabled={locked}
onClick={() => act('breaker')} />
)}>
[ {externalPowerStatus.externalPowerText} ]
</LabeledList.Item>
<LabeledList.Item label="Power Cell">
<ProgressBar
color="good"
value={adjustedCellChange} />
</LabeledList.Item>
<LabeledList.Item
label="Charge Mode"
color={chargingStatus.color}
buttons={(
<Button
icon={data.chargeMode ? 'sync' : 'times'}
content={data.chargeMode ? 'Auto' : 'Off'}
selected={data.chargeMode}
disabled={locked}
onClick={() => act('charge')} />
)}>
[ {chargingStatus.chargingText} ]
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Power Channels">
<LabeledList>
{channelArray.map(channel => {
const { topicParams } = channel;
return (
<LabeledList.Item
key={channel.title}
label={channel.title}
buttons={(
<Fragment>
<Box inline mx={2}
color={channel.status >= 2 ? 'good' : 'bad'}>
{channel.status >= 2 ? 'On' : 'Off'}
</Box>
<Button
icon="sync"
content="Auto"
selected={!locked && (
channel.status === 1 || channel.status === 3
)}
disabled={locked}
onClick={() => act('channel', topicParams.auto)} />
<Button
icon="power-off"
content="On"
selected={!locked && channel.status === 2}
disabled={locked}
onClick={() => act('channel', topicParams.on)} />
<Button
icon="times"
content="Off"
selected={!locked && channel.status === 0}
disabled={locked}
onClick={() => act('channel', topicParams.off)} />
</Fragment>
)}>
{channel.powerLoad} W
</LabeledList.Item>
);
})}
<LabeledList.Item label="Total Load">
{data.totalCharging ? (
<b>{data.totalLoad} W (+ {data.totalCharging} W charging)</b>
) : (
<b>{data.totalLoad} W</b>
)}
</LabeledList.Item>
</LabeledList>
</Section>
<Section
title="Misc"
buttons={!!data.siliconUser && (
<Button
icon="lightbulb-o"
content="Overload"
onClick={() => act('overload')} />
)}>
<LabeledList>
<LabeledList.Item
label="Cover Lock"
buttons={(
<Button
icon={data.coverLocked ? 'lock' : 'unlock'}
content={data.coverLocked ? 'Engaged' : 'Disengaged'}
selected={data.coverLocked}
disabled={locked}
onClick={() => act('cover')} />
)} />
<LabeledList.Item
label="Night Shift Lighting"
buttons={(
<Fragment>
<Button
icon="lightbulb-o"
content="Disabled"
selected={data.nightshiftSetting === 2}
onClick={() => act('nightshift', {
nightshift: 2,
})} />
<Button
icon="lightbulb-o"
content="Automatic"
selected={data.nightshiftSetting === 1}
onClick={() => act('nightshift', {
nightshift: 1,
})} />
<Button
icon="lightbulb-o"
content="Enabled"
selected={data.nightshiftSetting === 3}
onClick={() => act('nightshift', {
nightshift: 3,
})} />
</Fragment>
)} />
<LabeledList.Item
label="Emergency Lighting"
buttons={(
<Button
icon="lightbulb-o"
content={data.emergencyLights ? 'Enabled' : 'Disabled'}
selected={data.emergencyLights}
onClick={() => act('emergency_lighting')} />
)} />
</LabeledList>
</Section>
</Fragment>
);
};
const GridCheck = (props, context) => {
return (
<FullscreenNotice title="System Failure">
<Box fontSize="1.5rem" bold>
<Icon
name="exclamation-triangle"
verticalAlign="middle"
size={3}
mr="1rem"
/>
</Box>
<Box fontSize="1.5rem" bold>
Power surge detected, grid check in effect...
</Box>
</FullscreenNotice>
);
};
const ApcFailure = (props, context) => {
const { data, act } = useBackend(context);
let rebootOptions = (
<Button
icon="repeat"
content="Restart Now"
color="good"
onClick={() => act('reboot')}
/>
);
if (data.locked && !data.siliconUser) {
rebootOptions = (
<Box color="bad">Swipe an ID card for manual reboot.</Box>
);
}
return (
<Dimmer textAlign="center">
<Box color="bad"><h1>SYSTEM FAILURE</h1></Box>
<Box color="average">
<h2>
I/O regulators malfunction detected! Waiting for system reboot...
</h2>
</Box>
<Box color="good">Automatic reboot in {data.failTime} seconds...</Box>
<Box mt={4}>
{rebootOptions}
</Box>
</Dimmer>
);
};
+193
View File
@@ -0,0 +1,193 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
import { Window } from '../layouts';
const dangerMap = {
2: {
color: 'good',
localStatusText: 'Optimal',
},
1: {
color: 'average',
localStatusText: 'Caution',
},
0: {
color: 'bad',
localStatusText: 'Offline',
},
};
export const AiAirlock = (props, context) => {
const { act, data } = useBackend(context);
const statusMain = dangerMap[data.power.main] || dangerMap[0];
const statusBackup = dangerMap[data.power.backup] || dangerMap[0];
const statusElectrify = dangerMap[data.shock] || dangerMap[0];
return (
<Window
width={500}
height={390}>
<Window.Content>
<Section title="Power Status">
<LabeledList>
<LabeledList.Item
label="Main"
color={statusMain.color}
buttons={(
<Button
icon="lightbulb-o"
disabled={!data.power.main}
content="Disrupt"
onClick={() => act('disrupt-main')} />
)}>
{data.power.main ? 'Online' : 'Offline'}
{' '}
{(!data.wires.main_1 || !data.wires.main_2)
&& '[Wires have been cut!]'
|| (data.power.main_timeleft > 0
&& `[${data.power.main_timeleft}s]`)}
</LabeledList.Item>
<LabeledList.Item
label="Backup"
color={statusBackup.color}
buttons={(
<Button
icon="lightbulb-o"
disabled={!data.power.backup}
content="Disrupt"
onClick={() => act('disrupt-backup')} />
)}>
{data.power.backup ? 'Online' : 'Offline'}
{' '}
{(!data.wires.backup_1 || !data.wires.backup_2)
&& '[Wires have been cut!]'
|| (data.power.backup_timeleft > 0
&& `[${data.power.backup_timeleft}s]`)}
</LabeledList.Item>
<LabeledList.Item
label="Electrify"
color={statusElectrify.color}
buttons={(
<Fragment>
<Button
icon="wrench"
disabled={!(data.wires.shock && data.shock === 0)}
content="Restore"
onClick={() => act('shock-restore')} />
<Button
icon="bolt"
disabled={!data.wires.shock}
content="Temporary"
onClick={() => act('shock-temp')} />
<Button
icon="bolt"
disabled={!data.wires.shock}
content="Permanent"
onClick={() => act('shock-perm')} />
</Fragment>
)}>
{data.shock === 2 ? 'Safe' : 'Electrified'}
{' '}
{!data.wires.shock
&& '[Wires have been cut!]'
|| (data.shock_timeleft > 0
&& `[${data.shock_timeleft}s]`)
|| (data.shock_timeleft === -1
&& '[Permanent]')}
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Access and Door Control">
<LabeledList>
<LabeledList.Item
label="ID Scan"
color="bad"
buttons={(
<Button
icon={data.id_scanner ? 'power-off' : 'times'}
content={data.id_scanner ? 'Enabled' : 'Disabled'}
selected={data.id_scanner}
disabled={!data.wires.id_scanner}
onClick={() => act('idscan-toggle')} />
)}>
{!data.wires.id_scanner && '[Wires have been cut!]'}
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item
label="Door Bolts"
color="bad"
buttons={(
<Button
icon={data.locked ? 'lock' : 'unlock'}
content={data.locked ? 'Lowered' : 'Raised'}
selected={data.locked}
disabled={!data.wires.bolts}
onClick={() => act('bolt-toggle')} />
)}>
{!data.wires.bolts && '[Wires have been cut!]'}
</LabeledList.Item>
<LabeledList.Item
label="Door Bolt Lights"
color="bad"
buttons={(
<Button
icon={data.lights ? 'power-off' : 'times'}
content={data.lights ? 'Enabled' : 'Disabled'}
selected={data.lights}
disabled={!data.wires.lights}
onClick={() => act('light-toggle')} />
)}>
{!data.wires.lights && '[Wires have been cut!]'}
</LabeledList.Item>
<LabeledList.Item
label="Door Force Sensors"
color="bad"
buttons={(
<Button
icon={data.safe ? 'power-off' : 'times'}
content={data.safe ? 'Enabled' : 'Disabled'}
selected={data.safe}
disabled={!data.wires.safe}
onClick={() => act('safe-toggle')} />
)}>
{!data.wires.safe && '[Wires have been cut!]'}
</LabeledList.Item>
<LabeledList.Item
label="Door Timing Safety"
color="bad"
buttons={(
<Button
icon={data.speed ? 'power-off' : 'times'}
content={data.speed ? 'Enabled' : 'Disabled'}
selected={data.speed}
disabled={!data.wires.timing}
onClick={() => act('speed-toggle')} />
)}>
{!data.wires.timing && '[Wires have been cut!]'}
</LabeledList.Item>
<LabeledList.Divider />
<LabeledList.Item
label="Door Control"
color="bad"
buttons={(
<Button
icon={data.opened ? 'sign-out-alt' : 'sign-in-alt'}
content={data.opened ? 'Open' : 'Closed'}
selected={data.opened}
disabled={(data.locked || data.welded)}
onClick={() => act('open-close')} />
)}>
{!!(data.locked || data.welded) && (
<span>
[Door is {data.locked ? 'bolted' : ''}
{(data.locked && data.welded) ? ' and ' : ''}
{data.welded ? 'welded' : ''}!]
</span>
)}
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,90 @@
import { round } from 'common/math';
import { useBackend } from "../backend";
import { Box, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
import { Window } from "../layouts";
import { formatSiUnit, formatPower } from "../format";
import { FullscreenNotice } from './common/FullscreenNotice';
export const AiSupermatter = (props, context) => {
const { data } = useBackend(context);
const {
integrity_percentage,
ambient_temp,
ambient_pressure,
detonating,
} = data;
let body = <AiSupermatterContent />;
if (detonating) {
body = <AiSupermatterDetonation />;
}
return (
<Window
width={500}
height={300}>
<Window.Content>
{body}
</Window.Content>
</Window>
);
};
const AiSupermatterDetonation = (props, context) => (
<FullscreenNotice title="DETONATION IMMINENT">
<Box fontSize="1.5rem" bold color="bad">
<Icon
color="bad"
name="exclamation-triangle"
verticalAlign="middle"
size={3}
mr="1rem"
/>
<Box color="bad">CRYSTAL DELAMINATING</Box>
<Box color="bad">Evacuate area immediately</Box>
</Box>
</FullscreenNotice>
);
const AiSupermatterContent = (props, context) => {
const { data } = useBackend(context);
const {
integrity_percentage,
ambient_temp,
ambient_pressure,
} = data;
return (
<Section title="Status">
<LabeledList>
<LabeledList.Item label="Crystal Integrity">
<ProgressBar
value={integrity_percentage}
maxValue={100}
ranges={{
good: [90, Infinity],
average: [25, 90],
bad: [-Infinity, 25],
}} />
</LabeledList.Item>
<LabeledList.Item label="Environment Temperature">
<ProgressBar
value={ambient_temp}
maxValue={10000}
ranges={{
bad: [5000, Infinity],
average: [4000, 5000],
good: [-Infinity, 4000],
}}>
{ambient_temp} K
</ProgressBar>
</LabeledList.Item>
<LabeledList.Item label="Environment Pressure">
{ambient_pressure} kPa
</LabeledList.Item>
</LabeledList>
</Section>
);
};
+325
View File
@@ -0,0 +1,325 @@
import { toFixed } from 'common/math';
import { decodeHtmlEntities } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from '../backend';
import { Box, Button, LabeledList, NumberInput, Section } from '../components';
import { getGasLabel, getGasColor } from '../constants';
import { Window } from '../layouts';
import { InterfaceLockNoticeBox } from './common/InterfaceLockNoticeBox';
import { Vent, Scrubber } from './common/AtmosControls';
export const AirAlarm = (props, context) => {
const { act, data } = useBackend(context);
const locked = data.locked && !data.siliconUser && !data.remoteUser;
return (
<Window
width={440}
height={650}
resizable>
<Window.Content scrollable>
<InterfaceLockNoticeBox />
<AirAlarmStatus />
<AirAlarmUnlockedControl />
{!locked && (
<AirAlarmControl />
)}
</Window.Content>
</Window>
);
};
const AirAlarmStatus = (props, context) => {
const { data } = useBackend(context);
const entries = (data.environment_data || [])
.filter(entry => entry.value >= 0.01);
const dangerMap = {
0: {
color: 'good',
localStatusText: 'Optimal',
},
1: {
color: 'average',
localStatusText: 'Caution',
},
2: {
color: 'bad',
localStatusText: 'Danger (Internals Required)',
},
};
const localStatus = dangerMap[data.danger_level] || dangerMap[0];
return (
<Section title="Air Status">
<LabeledList>
{entries.length > 0 && (
<Fragment>
{entries.map(entry => {
const status = dangerMap[entry.danger_level] || dangerMap[0];
return (
<LabeledList.Item
key={entry.name}
label={getGasLabel(entry.name)}
color={status.color}>
{toFixed(entry.value, 2)}{entry.unit}
</LabeledList.Item>
);
})}
<LabeledList.Item
label="Local status"
color={localStatus.color}>
{localStatus.localStatusText}
</LabeledList.Item>
<LabeledList.Item
label="Area status"
color={data.atmos_alarm || data.fire_alarm ? 'bad' : 'good'}>
{data.atmos_alarm && 'Atmosphere Alarm'
|| data.fire_alarm && 'Fire Alarm'
|| 'Nominal'}
</LabeledList.Item>
</Fragment>
) || (
<LabeledList.Item
label="Warning"
color="bad">
Cannot obtain air sample for analysis.
</LabeledList.Item>
)}
{!!data.emagged && (
<LabeledList.Item
label="Warning"
color="bad">
Safety measures offline. Device may exhibit abnormal behavior.
</LabeledList.Item>
)}
</LabeledList>
</Section>
);
};
const AirAlarmUnlockedControl = (props, context) => {
const { act, data } = useBackend(context);
const {
target_temperature,
rcon,
} = data;
return (
<Section
title="Comfort Settings">
<LabeledList>
<LabeledList.Item label="Remote Control">
<Button
selected={rcon === 1}
content="Off"
onClick={() => act('rcon', { 'rcon': 1 })} />
<Button
selected={rcon === 2}
content="Auto"
onClick={() => act('rcon', { 'rcon': 2 })} />
<Button
selected={rcon === 3}
content="On"
onClick={() => act('rcon', { 'rcon': 3 })} />
</LabeledList.Item>
<LabeledList.Item label="Thermostat">
<Button
content={target_temperature}
onClick={() => act('temperature')} />
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const AIR_ALARM_ROUTES = {
home: {
title: 'Air Controls',
component: () => AirAlarmControlHome,
},
vents: {
title: 'Vent Controls',
component: () => AirAlarmControlVents,
},
scrubbers: {
title: 'Scrubber Controls',
component: () => AirAlarmControlScrubbers,
},
modes: {
title: 'Operating Mode',
component: () => AirAlarmControlModes,
},
thresholds: {
title: 'Alarm Thresholds',
component: () => AirAlarmControlThresholds,
},
};
const AirAlarmControl = (props, context) => {
const [screen, setScreen] = useLocalState(context, 'screen');
const route = AIR_ALARM_ROUTES[screen] || AIR_ALARM_ROUTES.home;
const Component = route.component();
return (
<Section
title={route.title}
buttons={screen && (
<Button
icon="arrow-left"
content="Back"
onClick={() => setScreen()} />
)}>
<Component />
</Section>
);
};
// Home screen
// --------------------------------------------------------
const AirAlarmControlHome = (props, context) => {
const { act, data } = useBackend(context);
const [screen, setScreen] = useLocalState(context, 'screen');
const {
mode,
atmos_alarm,
} = data;
return (
<Fragment>
<Button
icon={atmos_alarm
? 'exclamation-triangle'
: 'exclamation'}
color={atmos_alarm && 'caution'}
content="Area Atmosphere Alarm"
onClick={() => act(atmos_alarm ? 'reset' : 'alarm')} />
<Box mt={1} />
<Button
icon={mode === 3
? 'exclamation-triangle'
: 'exclamation'}
color={mode === 3 && 'danger'}
content="Panic Siphon"
onClick={() => act('mode', {
mode: mode === 3 ? 1 : 3,
})} />
<Box mt={2} />
<Button
icon="sign-out-alt"
content="Vent Controls"
onClick={() => setScreen('vents')} />
<Box mt={1} />
<Button
icon="filter"
content="Scrubber Controls"
onClick={() => setScreen('scrubbers')} />
<Box mt={1} />
<Button
icon="cog"
content="Operating Mode"
onClick={() => setScreen('modes')} />
<Box mt={1} />
<Button
icon="chart-bar"
content="Alarm Thresholds"
onClick={() => setScreen('thresholds')} />
</Fragment>
);
};
// Vents
// --------------------------------------------------------
const AirAlarmControlVents = (props, context) => {
const { data } = useBackend(context);
const { vents } = data;
if (!vents || vents.length === 0) {
return 'Nothing to show';
}
return vents.map(vent => (
<Vent
key={vent.id_tag}
vent={vent} />
));
};
// Scrubbers
// --------------------------------------------------------
const AirAlarmControlScrubbers = (props, context) => {
const { data } = useBackend(context);
const { scrubbers } = data;
if (!scrubbers || scrubbers.length === 0) {
return 'Nothing to show';
}
return scrubbers.map(scrubber => (
<Scrubber
key={scrubber.id_tag}
scrubber={scrubber} />
));
};
// Modes
// --------------------------------------------------------
const AirAlarmControlModes = (props, context) => {
const { act, data } = useBackend(context);
const { modes } = data;
if (!modes || modes.length === 0) {
return 'Nothing to show';
}
return modes.map(mode => (
<Fragment key={mode.mode}>
<Button
icon={mode.selected ? 'check-square-o' : 'square-o'}
selected={mode.selected}
color={mode.selected && mode.danger && 'danger'}
content={mode.name}
onClick={() => act('mode', { mode: mode.mode })} />
<Box mt={1} />
</Fragment>
));
};
// Thresholds
// --------------------------------------------------------
const AirAlarmControlThresholds = (props, context) => {
const { act, data } = useBackend(context);
const { thresholds } = data;
return (
<table
className="LabeledList"
style={{ width: '100%' }}>
<thead>
<tr>
<td />
<td className="color-bad">min2</td>
<td className="color-average">min1</td>
<td className="color-average">max1</td>
<td className="color-bad">max2</td>
</tr>
</thead>
<tbody>
{thresholds.map(threshold => (
<tr key={threshold.name}>
<td className="LabeledList__label">
<span className={"color-" + getGasColor(threshold.name)}>
{getGasLabel(threshold.name)}
</span>
</td>
{threshold.settings.map(setting => (
<td key={setting.val}>
<Button
content={toFixed(setting.selected, 2)}
onClick={() => act('threshold', {
env: setting.env,
var: setting.val,
})} />
</td>
))}
</tr>
))}
</tbody>
</table>
);
};
+111
View File
@@ -0,0 +1,111 @@
import { useBackend } from '../backend';
import { Box, Button, NoticeBox, LabeledList, ProgressBar, Section, Slider, Table } from '../components';
import { formatPower } from '../format';
import { Window } from '../layouts';
import { round } from 'common/math';
import { capitalize } from 'common/string';
export const AlgaeFarm = (props, context) => {
const { act, data } = useBackend(context);
const {
usePower,
materials,
last_flow_rate,
last_power_draw,
inputDir,
outputDir,
input,
output,
errorText,
} = data;
return (
<Window
width={500}
height={300}
resizable>
<Window.Content>
{errorText && (
<NoticeBox warning>
<Box display="inline-block" verticalAlign="middle">
{errorText}
</Box>
</NoticeBox>
)}
<Section
title="Status"
buttons={
<Button
icon="power-off"
content="Processing"
selected={usePower === 2}
onClick={() => act("toggle")} />
}>
<LabeledList>
<LabeledList.Item label="Flow Rate">
{last_flow_rate} L/s
</LabeledList.Item>
<LabeledList.Item label="Power Draw">
{last_power_draw} W
</LabeledList.Item>
<LabeledList.Divider size={1} />
{materials.map(material => (
<LabeledList.Item
key={material.name}
label={capitalize(material.display)}>
<ProgressBar
width="80%"
value={material.qty}
maxValue={material.max}>
{material.qty}/{material.max}
</ProgressBar>
<Button
ml={1}
content="Eject"
onClick={() => act("ejectMaterial", {
mat: material.name,
})} />
</LabeledList.Item>
))}
</LabeledList>
<Table mt={1}>
<Table.Row>
<Table.Cell>
<Section title={"Gas Input (" + inputDir + ")"}>
{input ? (
<LabeledList>
<LabeledList.Item label="Total Pressure">
{input.pressure} kPa
</LabeledList.Item>
<LabeledList.Item label={input.name}>
{input.percent}% ({input.moles} moles)
</LabeledList.Item>
</LabeledList>
) : (
<Box color="bad">No connection detected.</Box>
)}
</Section>
</Table.Cell>
<Table.Cell>
<Section title={"Gas Output (" + outputDir + ")"}>
{output ? (
<LabeledList>
<LabeledList.Item label="Total Pressure">
{output.pressure} kPa
</LabeledList.Item>
<LabeledList.Item label={output.name}>
{output.percent}% ({output.moles} moles)
</LabeledList.Item>
</LabeledList>
) : (
<Box color="bad">No connection detected.</Box>
)}
</Section>
</Table.Cell>
</Table.Row>
</Table>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,292 @@
import { filter, sortBy } from 'common/collections';
import { capitalize, decodeHtmlEntities } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from "../backend";
import { Box, Button, ByondUi, Flex, Icon, LabeledList, ProgressBar, Section, Tabs, ColorBox } from "../components";
import { Window } from "../layouts";
export const AppearanceChanger = (props, context) => {
const { act, config, data } = useBackend(context);
const {
name,
specimen,
gender,
gender_id,
hair_style,
facial_hair_style,
change_race,
change_gender,
change_eye_color,
change_skin_tone,
change_skin_color,
change_hair_color,
change_facial_hair_color,
change_hair,
change_facial_hair,
mapRef,
} = data;
const {
title,
} = config;
const change_color = change_eye_color
|| change_skin_tone
|| change_skin_color
|| change_hair_color
|| change_facial_hair_color;
let firstAccesibleTab = -1;
if (change_race) {
firstAccesibleTab = 0;
} else if (change_gender) {
firstAccesibleTab = 1;
} else if (change_color) {
firstAccesibleTab = 2;
} else if (change_hair) {
firstAccesibleTab = 4;
} else if (change_facial_hair) {
firstAccesibleTab = 5;
}
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', firstAccesibleTab);
return (
<Window width={700} height={650} title={decodeHtmlEntities(title)}>
<Window.Content>
<Section title="Reflection">
<Flex>
<Flex.Item grow={1}>
<LabeledList>
<LabeledList.Item label="Name">
{name}
</LabeledList.Item>
<LabeledList.Item label="Species" color={!change_race ? "grey" : null}>
{specimen}
</LabeledList.Item>
<LabeledList.Item label="Biological Sex" color={!change_gender ? "grey" : null}>
{capitalize(gender)}
</LabeledList.Item>
<LabeledList.Item label="Gender Identity" color={!change_color ? "grey" : null}>
{capitalize(gender_id)}
</LabeledList.Item>
<LabeledList.Item label="Hair Style" color={!change_hair ? "grey" : null}>
{capitalize(hair_style)}
</LabeledList.Item>
<LabeledList.Item label="Facial Hair Style" color={!change_facial_hair ? "grey" : null}>
{capitalize(facial_hair_style)}
</LabeledList.Item>
</LabeledList>
</Flex.Item>
<Flex.Item>
<ByondUi
style={{
width: '256px',
height: '256px',
}}
params={{
id: mapRef,
type: 'map',
}} />
</Flex.Item>
</Flex>
</Section>
<Tabs>
{change_race ? (
<Tabs.Tab
selected={tabIndex === 0}
onClick={() => setTabIndex(0)}>
Race
</Tabs.Tab>
) : null}
{change_gender ? (
<Tabs.Tab
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}>
Gender & Sex
</Tabs.Tab>
) : null}
{change_color ? (
<Tabs.Tab
selected={tabIndex === 2}
onClick={() => setTabIndex(2)}>
Colors
</Tabs.Tab>
) : null}
{change_hair ? (
<Tabs.Tab
selected={tabIndex === 3}
onClick={() => setTabIndex(3)}>
Hair
</Tabs.Tab>
) : null}
{change_facial_hair ? (
<Tabs.Tab
selected={tabIndex === 4}
onClick={() => setTabIndex(4)}>
Facial Hair
</Tabs.Tab>
) : null}
</Tabs>
<Box height="43%">
{(change_race && tabIndex === 0) ? <AppearanceChangerSpecies /> : null}
{(change_gender && tabIndex === 1) ? <AppearanceChangerGender /> : null}
{(change_color && tabIndex === 2) ? <AppearanceChangerColors /> : null}
{(change_hair && tabIndex === 3) ? <AppearanceChangerHair /> : null}
{(change_facial_hair && tabIndex === 4) ? <AppearanceChangerFacialHair /> : null}
</Box>
</Window.Content>
</Window>
);
};
const AppearanceChangerSpecies = (props, context) => {
const { act, data } = useBackend(context);
const {
species,
specimen,
} = data;
const sortedSpecies = sortBy(val => val.specimen)(species || []);
return (
<Section title="Species" fill scrollable>
{sortedSpecies.map(spec => (
<Button
key={spec.specimen}
content={spec.specimen}
selected={specimen === spec.specimen}
onClick={() => act("race", { race: spec.specimen })} />
))}
</Section>
);
};
const AppearanceChangerGender = (props, context) => {
const { act, data } = useBackend(context);
const {
gender,
gender_id,
genders,
id_genders,
} = data;
return (
<Section title="Gender & Sex" fill scrollable>
<LabeledList>
<LabeledList.Item label="Biological Sex">
{genders.map(g => (
<Button
key={g.gender_key}
selected={g.gender_key === gender}
content={g.gender_name}
onClick={() => act("gender", { "gender": g.gender_key })} />
))}
</LabeledList.Item>
<LabeledList.Item label="Gender Identity">
{id_genders.map(g => (
<Button
key={g.gender_key}
selected={g.gender_key === gender_id}
content={g.gender_name}
onClick={() => act("gender_id", { "gender_id": g.gender_key })} />
))}
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const AppearanceChangerColors = (props, context) => {
const { act, data } = useBackend(context);
const {
change_eye_color,
change_skin_tone,
change_skin_color,
change_hair_color,
change_facial_hair_color,
eye_color,
skin_color,
hair_color,
facial_hair_color,
} = data;
return (
<Section title="Colors" fill scrollable>
{change_eye_color ? (
<Box>
<ColorBox color={eye_color} mr={1} />
<Button content="Change Eye Color" onClick={() => act("eye_color")} />
</Box>
) : null}
{change_skin_tone ? (
<Box>
<Button content="Change Skin Tone" onClick={() => act("skin_tone")} />
</Box>
) : null}
{change_skin_color ? (
<Box>
<ColorBox color={skin_color} mr={1} />
<Button content="Change Skin Color" onClick={() => act("skin_color")} />
</Box>
) : null}
{change_hair_color ? (
<Box>
<ColorBox color={hair_color} mr={1} />
<Button content="Change Hair Color" onClick={() => act("hair_color")} />
</Box>
) : null}
{change_facial_hair_color ? (
<Box>
<ColorBox color={facial_hair_color} mr={1} />
<Button content="Change Facial Hair Color" onClick={() => act("facial_hair_color")} />
</Box>
) : null}
</Section>
);
};
const AppearanceChangerHair = (props, context) => {
const { act, data } = useBackend(context);
const {
hair_style,
hair_styles,
} = data;
return (
<Section title="Hair" fill scrollable>
{hair_styles.map(hair => (
<Button
key={hair.hairstyle}
onClick={() => act("hair", { hair: hair.hairstyle })}
selected={hair.hairstyle === hair_style}
content={hair.hairstyle} />
))}
</Section>
);
};
const AppearanceChangerFacialHair = (props, context) => {
const { act, data } = useBackend(context);
const {
facial_hair_style,
facial_hair_styles,
} = data;
return (
<Section title="Facial Hair" fill scrollable>
{facial_hair_styles.map(hair => (
<Button
key={hair.facialhairstyle}
onClick={() => act("facial_hair", { facial_hair: hair.facialhairstyle })}
selected={hair.facialhairstyle === facial_hair_style}
content={hair.facialhairstyle} />
))}
</Section>
);
};
@@ -0,0 +1,121 @@
import { Flex, Button, Box, LabeledList, Section } from "../components";
import { useBackend, useLocalState } from "../backend";
import { Window } from '../layouts';
import { toTitleCase } from 'common/string';
export const AreaScrubberControl = (props, context) => {
const { act, data } = useBackend(context);
const [
showArea,
setShowArea,
] = useLocalState(context, "showArea", false);
const {
scrubbers,
} = data;
if (!scrubbers) {
return (
<Section title="Error">
<Box color="bad">No Scrubbers Detected.</Box>
<Button
fluid
icon="search"
content="Scan"
onClick={() => act("scan")} />
</Section>
);
}
return (
<Window
width={600}
height={400}
resizable>
<Window.Content scrollable>
<Section>
<Flex wrap="wrap">
<Flex.Item m="2px" basis="49%">
<Button
textAlign="center"
fluid
icon="search"
content="Scan"
onClick={() => act("scan")} />
</Flex.Item>
<Flex.Item m="2px" basis="49%" grow={1}>
<Button
textAlign="center"
fluid
icon="layer-group"
content="Show Areas"
selected={showArea}
onClick={() => setShowArea(!showArea)} />
</Flex.Item>
<Flex.Item m="2px" basis="49%">
<Button
textAlign="center"
fluid
icon="toggle-on"
content="All On"
onClick={() => act("allon")} />
</Flex.Item>
<Flex.Item m="2px" basis="49%" grow={1}>
<Button
textAlign="center"
fluid
icon="toggle-off"
content="All Off"
onClick={() => act("alloff")} />
</Flex.Item>
</Flex>
<Flex wrap="wrap">
{scrubbers.map(scrubber => (
<Flex.Item m="2px" key={scrubber.id} basis="32%">
<BigScrubber scrubber={scrubber} showArea={showArea} />
</Flex.Item>
))}
</Flex>
</Section>
</Window.Content>
</Window>
);
};
const BigScrubber = (props, context) => {
const { act } = useBackend(context);
const {
scrubber,
showArea,
} = props;
return (
<Section title={scrubber.name}>
<Button
fluid
icon="power-off"
content={scrubber.on ? "Enabled" : "Disabled"}
selected={scrubber.on}
onClick={() => act("toggle", { id: scrubber.id })} />
<LabeledList>
<LabeledList.Item label="Pressure">
{scrubber.pressure} kPa
</LabeledList.Item>
<LabeledList.Item label="Flow Rate">
{scrubber.flow_rate} L/s
</LabeledList.Item>
<LabeledList.Item label="Load">
{scrubber.load} W
</LabeledList.Item>
{showArea && (
<LabeledList.Item label="Area">
{toTitleCase(scrubber.area)}
</LabeledList.Item>
)}
</LabeledList>
</Section>
);
};
@@ -0,0 +1,41 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
import { Window } from "../layouts";
export const AssemblyInfrared = (props, context) => {
const { act, data } = useBackend(context);
const {
on,
visible,
} = data;
return (
<Window>
<Window.Content>
<Section title="Infrared Unit">
<LabeledList>
<LabeledList.Item label="Laser">
<Button
icon="power-off"
fluid
selected={on}
onClick={() => act("state")}>
{on ? "On" : "Off"}
</Button>
</LabeledList.Item>
<LabeledList.Item label="Visibility">
<Button
icon="eye"
fluid
selected={visible}
onClick={() => act("visible")}>
{visible ? "Able to be seen" : "Invisible"}
</Button>
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,65 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, NumberInput, Section } from "../components";
import { Window } from "../layouts";
import { formatTime } from '../format';
export const AssemblyProx = (props, context) => {
const { act, data } = useBackend(context);
const {
timing,
time,
range,
maxRange,
scanning,
} = data;
return (
<Window>
<Window.Content>
<Section title="Timing Unit">
<LabeledList>
<LabeledList.Item label="Timer" buttons={
<Button
icon="stopwatch"
selected={timing}
onClick={() => act("timing")}>
{timing ? "Counting Down" : "Disabled"}
</Button>
}>
<NumberInput
animated
fluid
value={time / 10}
minValue={0}
maxValue={600}
format={val => formatTime(round(val))}
onDrag={(e, val) => act("set_time", { time: val })} />
</LabeledList.Item>
</LabeledList>
</Section>
<Section title="Prox Unit">
<LabeledList>
<LabeledList.Item label="Range">
<NumberInput
minValue={1}
value={range}
maxValue={maxRange}
onDrag={(e, val) => act("range", { range: val })} />
</LabeledList.Item>
<LabeledList.Item label="Armed">
<Button
mr={1}
icon={scanning ? "lock" : "lock-open"}
selected={scanning}
onClick={() => act("scanning")}>
{scanning ? "ARMED" : "Unarmed"}
</Button>
Movement sensor is active when armed!
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,41 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, NumberInput, Section } from "../components";
import { Window } from "../layouts";
import { formatTime } from '../format';
export const AssemblyTimer = (props, context) => {
const { act, data } = useBackend(context);
const {
timing,
time,
} = data;
return (
<Window>
<Window.Content>
<Section title="Timing Unit">
<LabeledList>
<LabeledList.Item label="Timer" buttons={
<Button
icon="stopwatch"
selected={timing}
onClick={() => act("timing")}>
{timing ? "Counting Down" : "Disabled"}
</Button>
}>
<NumberInput
animated
fluid
value={time / 10}
minValue={0}
maxValue={600}
format={val => formatTime(round(val))}
onDrag={(e, val) => act("set_time", { time: val })} />
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,50 @@
import { useBackend } from '../backend';
import { Button, Section } from '../components';
import { Window } from '../layouts';
export const AtmosAlertConsole = (props, context) => {
const { act, data } = useBackend(context);
const priorityAlerts = data.priority_alarms || [];
const minorAlerts = data.minor_alarms || [];
return (
<Window
width={350}
height={300}
resizable>
<Window.Content scrollable>
<Section title="Alarms">
<ul>
{priorityAlerts.length === 0 && (
<li className="color-good">
No Priority Alerts
</li>
)}
{priorityAlerts.map(alert => (
<li key={alert.name}>
<Button
icon="times"
content={alert.name}
color="bad"
onClick={() => act('clear', { ref: alert.ref })} />
</li>
))}
{minorAlerts.length === 0 && (
<li className="color-good">
No Minor Alerts
</li>
)}
{minorAlerts.map(alert => (
<li key={alert.name}>
<Button
icon="times"
content={alert.name}
color="average"
onClick={() => act('clear', { ref: alert.ref })} />
</li>
))}
</ul>
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,121 @@
import { sortBy } from 'common/collections';
import { Window } from '../layouts';
import { Fragment } from 'inferno';
import { Button, Box, NumberInput, Tabs, Icon, Section, NanoMap } from '../components';
import { useBackend, useLocalState } from '../backend';
import { createLogger } from '../logging';
const logger = createLogger("fuck");
export const AtmosControl = (props, context) => {
return (
<Window
width={600}
height={440}
resizable>
<Window.Content scrollable>
<AtmosControlContent />
</Window.Content>
</Window>
);
};
export const AtmosControlContent = (props, context) => {
const { act, data, config } = useBackend(context);
let sortedAlarms = sortBy(
alarm => alarm.name
)(data.alarms || []);
// sortedAlarms = sortedAlarms.slice(1, 3);
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
const [mapZoom, setZoom] = useLocalState(context, 'mapZoom', 1);
let body;
// Alarms View
if (tabIndex === 0) {
body = (
<Section title="Alarms">
{sortedAlarms.map(alarm => (
<Button
key={alarm.name}
content={alarm.name}
color={alarm.danger === 2
? 'bad'
: alarm.danger === 1
? 'average'
: ''}
onClick={() => act('alarm', { 'alarm': alarm.ref })} />
))}
</Section>
);
} else if (tabIndex === 1) {
// Please note, if you ever change the zoom values,
// you MUST update styles/components/Tooltip.scss
// and change the @for scss to match.
body = (
<Box textAlign="center">
Zoom Level:
<NumberInput
animated
width="40px"
step={0.5}
stepPixelSize="5"
value={mapZoom}
minValue={1}
maxValue={8}
onChange={(e, value) => setZoom(value)} />
Z-Level:
{data.map_levels
.sort((a, b) => Number(a) - Number(b))
.map(level => (
<Button
key={level}
selected={~~level === ~~config.mapZLevel}
content={level}
onClick={() => {
act("setZLevel", { "mapZLevel": level });
}} />
))}
<NanoMap zoom={mapZoom}>
{sortedAlarms
.filter(x =>
(~~x.z === ~~config.mapZLevel)
).map(cm => (
<NanoMap.Marker
key={cm.ref}
x={cm.x}
y={cm.y}
zoom={mapZoom}
icon="bell"
tooltip={cm.name}
color={cm.danger ? 'red' : 'green'}
onClick={() => act("alarm", { "alarm": cm.ref })} />
))}
</NanoMap>
</Box>
);
}
return (
<Fragment>
<Tabs>
<Tabs.Tab
key="AlarmView"
selected={0 === tabIndex}
onClick={() => setTabIndex(0)}>
<Icon name="table" /> Alarm View
</Tabs.Tab>
<Tabs.Tab
key="MapView"
selected={1 === tabIndex}
onClick={() => setTabIndex(1)}>
<Icon name="map-marked-alt" /> Map View
</Tabs.Tab>
</Tabs>
<Box m={2}>
{body}
</Box>
</Fragment>
);
};
@@ -0,0 +1,65 @@
import { useBackend } from '../backend';
import { Button, LabeledList, NumberInput, Section, AnimatedNumber, Box } from '../components';
import { getGasLabel } from '../constants';
import { Window } from '../layouts';
export const AtmosFilter = (props, context) => {
const { act, data } = useBackend(context);
const filterTypes = data.filter_types || [];
return (
<Window
width={390}
height={187}
resizable>
<Window.Content>
<Section>
<LabeledList>
<LabeledList.Item label="Power">
<Button
icon={data.on ? 'power-off' : 'times'}
content={data.on ? 'On' : 'Off'}
selected={data.on}
onClick={() => act('power')} />
</LabeledList.Item>
<LabeledList.Item label="Transfer Rate">
<Box inline mr={1}>
<AnimatedNumber
value={data.last_flow_rate}
format={val => val + " L/s"} />
</Box>
<NumberInput
animated
value={parseFloat(data.rate)}
width="63px"
unit="L/s"
minValue={0}
maxValue={200}
onDrag={(e, value) => act('rate', {
rate: value,
})} />
<Button
ml={1}
icon="plus"
content="Max"
disabled={data.rate === data.max_rate}
onClick={() => act('rate', {
rate: 'max',
})} />
</LabeledList.Item>
<LabeledList.Item label="Filter">
{filterTypes.map(filter => (
<Button
key={filter.name}
selected={filter.selected}
content={filter.name}
onClick={() => act('filter', {
filterset: filter.f_type,
})} />
))}
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};

Some files were not shown because too many files have changed in this diff Show More