diff --git a/code/modules/integrated_electronics/_defines.dm b/code/modules/integrated_electronics/_defines.dm index 104b867532d..6361bfa32f6 100644 --- a/code/modules/integrated_electronics/_defines.dm +++ b/code/modules/integrated_electronics/_defines.dm @@ -6,10 +6,6 @@ #define DATA_CHANNEL "data channel" #define PULSE_CHANNEL "pulse channel" -// Methods of obtaining a circuit. -#define IC_SPAWN_DEFAULT 1 // If the circuit comes in the default circuit box and able to be printed in the IC printer. -#define IC_SPAWN_RESEARCH 2 // If the circuit design will be available in the IC printer after upgrading it. - // Displayed along with the pin name to show what type of pin it is. #define IC_FORMAT_ANY "\" #define IC_FORMAT_STRING "\" @@ -49,7 +45,7 @@ var/list/all_integrated_circuits = list() /obj/item/integrated_circuit name = "integrated circuit" desc = "It's a tiny chip! This one doesn't seem to do much, however." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_components.dmi' icon_state = "template" w_class = ITEMSIZE_TINY var/obj/item/device/electronic_assembly/assembly = null // Reference to the assembly holding this circuit, if any. diff --git a/code/modules/integrated_electronics/core/assemblies/clothing.dm b/code/modules/integrated_electronics/core/assemblies/clothing.dm new file mode 100644 index 00000000000..07d456c48ba --- /dev/null +++ b/code/modules/integrated_electronics/core/assemblies/clothing.dm @@ -0,0 +1,187 @@ + +// The base subtype for assemblies that can be worn. Certain pieces will have more or less capabilities +// E.g. Glasses have less room than something worn over the chest. +// Note that the electronic assembly is INSIDE the object that actually gets worn, in a similar way to implants. + +/obj/item/device/electronic_assembly/clothing + name = "electronic clothing" + icon_state = "circuitry" // Needs to match the clothing's base icon_state. + desc = "It's a case, for building machines attached to clothing." + w_class = ITEMSIZE_SMALL + max_components = IC_COMPONENTS_BASE + max_complexity = IC_COMPLEXITY_BASE + var/obj/item/clothing/clothing = null + +/obj/item/device/electronic_assembly/clothing/nano_host() + return clothing + +/obj/item/device/electronic_assembly/clothing/resolve_nano_host() + return clothing + +/obj/item/device/electronic_assembly/clothing/update_icon() + ..() + clothing.icon_state = icon_state + // We don't need to update the mob sprite since it won't (and shouldn't) actually get changed. + +// This is 'small' relative to the size of regular clothing assemblies. +/obj/item/device/electronic_assembly/clothing/small + max_components = IC_COMPONENTS_BASE / 2 + max_complexity = IC_COMPLEXITY_BASE / 2 + w_class = ITEMSIZE_TINY + +// Ditto. +/obj/item/device/electronic_assembly/clothing/large + max_components = IC_COMPONENTS_BASE * 2 + max_complexity = IC_COMPLEXITY_BASE * 2 + w_class = ITEMSIZE_NORMAL + + +// This is defined higher up, in /clothing to avoid lots of copypasta. +/obj/item/clothing + var/obj/item/device/electronic_assembly/clothing/IC = null + var/obj/item/integrated_circuit/built_in/action_button/action_circuit = null // This gets pulsed when someone clicks the button on the hud. + +/obj/item/clothing/emp_act(severity) + if(IC) + IC.emp_act(severity) + ..() + +/obj/item/clothing/examine(mob/user) + if(IC) + IC.examine(user) + ..() + +/obj/item/clothing/attackby(obj/item/I, mob/user) + if(IC) + // This needs to be done in a better way... + if(I.is_crowbar() || I.is_screwdriver() || istype(I, /obj/item/integrated_circuit) || istype(I, /obj/item/weapon/cell/device) || istype(I, /obj/item/device/integrated_electronics) ) + IC.attackby(I, user) + else + ..() + +/obj/item/clothing/attack_self(mob/user) + if(IC) + if(IC.opened) + IC.attack_self(user) + else + action_circuit.do_work() + else + ..() + +/obj/item/clothing/Moved(oldloc) + if(IC) + IC.on_loc_moved(oldloc) + else + ..() + +/obj/item/clothing/on_loc_moved(oldloc) + if(IC) + IC.on_loc_moved(oldloc) + else + ..() + +// Does most of the repeatative setup. +/obj/item/clothing/proc/setup_integrated_circuit(new_type) + // Set up the internal circuit holder. + IC = new new_type(src) + IC.clothing = src + IC.name = name + + // Clothing assemblies can be triggered by clicking on the HUD. This allows that to occur. + action_circuit = new(src.IC) + IC.force_add_circuit(action_circuit) + action_button_name = "Activate [name]" + +/obj/item/clothing/Destroy() + if(IC) + IC.clothing = null + action_circuit = null // Will get deleted by qdel-ing the IC assembly. + qdel(IC) + return ..() + +// Specific subtypes. + +// Jumpsuit. +/obj/item/clothing/under/circuitry + name = "electronic jumpsuit" + desc = "It's a wearable case for electronics. This on is a black jumpsuit with wiring weaved into the fabric." + icon_state = "circuitry" + worn_state = "circuitry" + +/obj/item/clothing/under/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing) + return ..() + + +// Gloves. +/obj/item/clothing/gloves/circuitry + name = "electronic gloves" + desc = "It's a wearable case for electronics. This one is a pair of black gloves, with wires woven into them. A small \ + device with a screen is attached to the left glove." + icon_state = "circuitry" + item_state = "circuitry" + +/obj/item/clothing/gloves/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/small) + return ..() + + +// Glasses. +/obj/item/clothing/glasses/circuitry + name = "electronic goggles" + desc = "It's a wearable case for electronics. This one is a pair of goggles, with wiring sticking out. \ + Could this augment your vision?" // Sadly it won't, or at least not yet. + icon_state = "circuitry" + item_state = "night" // The on-mob sprite would be identical anyways. + +/obj/item/clothing/glasses/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/small) + return ..() + +// Shoes +/obj/item/clothing/shoes/circuitry + name = "electronic boots" + desc = "It's a wearable case for electronics. This one is a pair of boots, with wires attached to a small \ + cover." + icon_state = "circuitry" + item_state = "circuitry" + +/obj/item/clothing/shoes/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/small) + return ..() + +// Head +/obj/item/clothing/head/circuitry + name = "electronic headwear" + desc = "It's a wearable case for electronics. This one appears to be a very technical-looking piece that \ + goes around the collar, with a heads-up-display attached on the right." + icon_state = "circuitry" + item_state = "circuitry" + +/obj/item/clothing/head/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/small) + return ..() + +// Ear +/obj/item/clothing/ears/circuitry + name = "electronic earwear" + desc = "It's a wearable case for electronics. This one appears to be a technical-looking headset." + icon = 'icons/obj/clothing/ears.dmi' + icon_state = "circuitry" + item_state = "circuitry" + +/obj/item/clothing/ears/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/small) + return ..() + +// Exo-slot +/obj/item/clothing/suit/circuitry + name = "electronic chestpiece" + desc = "It's a wearable case for electronics. This one appears to be a very technical-looking vest, that \ + almost looks professionally made, however the wiring popping out betrays that idea." + icon_state = "circuitry" + item_state = "circuitry" + +/obj/item/clothing/suit/circuitry/initialize() + setup_integrated_circuit(/obj/item/device/electronic_assembly/clothing/large) + return ..() \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/assemblies/device.dm b/code/modules/integrated_electronics/core/assemblies/device.dm new file mode 100644 index 00000000000..bcdd0e9bead --- /dev/null +++ b/code/modules/integrated_electronics/core/assemblies/device.dm @@ -0,0 +1,84 @@ +/obj/item/device/assembly/electronic_assembly + name = "electronic device" + desc = "It's a case for building electronics with. It can be attached to other small devices." + icon_state = "setup_device" + var/opened = 0 + + var/obj/item/device/electronic_assembly/device/EA + +/obj/item/device/assembly/electronic_assembly/New() + EA = new(src) + EA.holder = src + ..() + +/obj/item/device/assembly/electronic_assembly/attackby(obj/item/I as obj, mob/user as mob) + if (I.is_crowbar()) + toggle_open(user) + else if (opened) + EA.attackby(I, user) + else + ..() + +/obj/item/device/assembly/electronic_assembly/proc/toggle_open(mob/user) + playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1) + opened = !opened + EA.opened = opened + to_chat(user, "You [opened ? "opened" : "closed"] \the [src].") + secured = 1 + update_icon() + +/obj/item/device/assembly/electronic_assembly/update_icon() + if(EA) + icon_state = initial(icon_state) + else + icon_state = initial(icon_state)+"0" + if(opened) + icon_state = icon_state + "-open" + +/obj/item/device/assembly/electronic_assembly/attack_self(mob/user as mob) + if(EA) + EA.attack_self(user) + +/obj/item/device/assembly/electronic_assembly/pulsed(var/radio = 0) //Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs + if(EA) + for(var/obj/item/integrated_circuit/built_in/device_input/I in EA.contents) + I.do_work() + return + +/obj/item/device/assembly/electronic_assembly/examine(mob/user) + .=..(user, 1) + if(EA) + for(var/obj/item/integrated_circuit/IC in EA.contents) + IC.external_examine(user) + +/obj/item/device/assembly/electronic_assembly/verb/toggle() + set src in usr + set category = "Object" + set name = "Open/Close Device Assembly" + set desc = "Open or close device assembly!" + + toggle_open(usr) + + +/obj/item/device/electronic_assembly/device + name = "electronic device" + icon_state = "setup_device" + desc = "It's a tiny electronic device with specific use for attaching to other devices." + var/obj/item/device/assembly/electronic_assembly/holder + w_class = ITEMSIZE_TINY + max_components = IC_COMPONENTS_BASE * 3/4 + max_complexity = IC_COMPLEXITY_BASE * 3/4 + + +/obj/item/device/electronic_assembly/device/New() + ..() + var/obj/item/integrated_circuit/built_in/device_input/input = new(src) + var/obj/item/integrated_circuit/built_in/device_output/output = new(src) + input.assembly = src + output.assembly = src + +/obj/item/device/electronic_assembly/device/check_interactivity(mob/user) + if(!CanInteract(user, state = deep_inventory_state)) + return 0 + return 1 + diff --git a/code/modules/integrated_electronics/core/assemblies/generic.dm b/code/modules/integrated_electronics/core/assemblies/generic.dm new file mode 100644 index 00000000000..70a3077b417 --- /dev/null +++ b/code/modules/integrated_electronics/core/assemblies/generic.dm @@ -0,0 +1,261 @@ +// Generic subtypes without a lot of special code. + +// Small assemblies. + +/obj/item/device/electronic_assembly/default + name = "type-a electronic assembly" + +/obj/item/device/electronic_assembly/calc + name = "type-b electronic assembly" + icon_state = "setup_small_calc" + desc = "It's a case, for building small electronics with. This one resembles a pocket calculator." + +/obj/item/device/electronic_assembly/clam + name = "type-c electronic assembly" + icon_state = "setup_small_clam" + desc = "It's a case, for building small electronics with. This one has a clamshell design." + +/obj/item/device/electronic_assembly/simple + name = "type-d electronic assembly" + icon_state = "setup_small_simple" + desc = "It's a case, for building small electronics with. This one has a simple design." + +/obj/item/device/electronic_assembly/hook + name = "type-e electronic assembly" + icon_state = "setup_small_hook" + desc = "It's a case, for building small electronics with. This one looks like it has a belt clip, but it's purely decorative." + +/obj/item/device/electronic_assembly/pda + name = "type-f electronic assembly" + icon_state = "setup_small_pda" + desc = "It's a case, for building small electronics with. This one resembles a PDA." + +// Tiny assemblies. + +/obj/item/device/electronic_assembly/tiny + name = "electronic device" + icon_state = "setup_device" + desc = "It's a case, for building tiny-sized electronics with." + w_class = ITEMSIZE_TINY + max_components = IC_COMPONENTS_BASE / 2 + max_complexity = IC_COMPLEXITY_BASE / 2 + +/obj/item/device/electronic_assembly/tiny/default + name = "type-a electronic device" + +/obj/item/device/electronic_assembly/tiny/cylinder + name = "type-b electronic device" + icon_state = "setup_device_cylinder" + desc = "It's a case, for building tiny-sized electronics with. This one has a cylindrical design." + +/obj/item/device/electronic_assembly/tiny/scanner + name = "type-c electronic device" + icon_state = "setup_device_scanner" + desc = "It's a case, for building tiny-sized electronics with. This one has a scanner-like design." + +/obj/item/device/electronic_assembly/tiny/hook + name = "type-d electronic device" + icon_state = "setup_device_hook" + desc = "It's a case, for building tiny-sized electronics with. This one looks like it has a belt clip, but it's purely decorative." + +/obj/item/device/electronic_assembly/tiny/box + name = "type-e electronic device" + icon_state = "setup_device_box" + desc = "It's a case, for building tiny-sized electronics with. This one has a boxy design." + +// Medium assemblies. + +/obj/item/device/electronic_assembly/medium + name = "electronic mechanism" + icon_state = "setup_medium" + desc = "It's a case, for building medium-sized electronics with." + w_class = ITEMSIZE_NORMAL + max_components = IC_COMPONENTS_BASE * 2 + max_complexity = IC_COMPLEXITY_BASE * 2 + +/obj/item/device/electronic_assembly/medium/default + name = "type-a electronic mechanism" + +/obj/item/device/electronic_assembly/medium/box + name = "type-b electronic mechanism" + icon_state = "setup_medium_box" + desc = "It's a case, for building medium-sized electronics with. This one has a boxy design." + +/obj/item/device/electronic_assembly/medium/clam + name = "type-c electronic mechanism" + icon_state = "setup_medium_clam" + desc = "It's a case, for building medium-sized electronics with. This one has a clamshell design." + +/obj/item/device/electronic_assembly/medium/medical + name = "type-d electronic mechanism" + icon_state = "setup_medium_med" + desc = "It's a case, for building medium-sized electronics with. This one resembles some type of medical apparatus." + +/obj/item/device/electronic_assembly/medium/gun + name = "type-e electronic mechanism" + icon_state = "setup_medium_gun" + item_state = "circuitgun" + desc = "It's a case, for building medium-sized electronics with. This one resembles a gun, or some type of tool, \ + if you're feeling optimistic." +// can_fire_equipped = TRUE + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi', + ) + +/obj/item/device/electronic_assembly/medium/radio + name = "type-f electronic mechanism" + icon_state = "setup_medium_radio" + desc = "It's a case, for building medium-sized electronics with. This one resembles an old radio." + +// Large assemblies. + +/obj/item/device/electronic_assembly/large + name = "electronic machine" + icon_state = "setup_large" + desc = "It's a case, for building large electronics with." + w_class = ITEMSIZE_LARGE + max_components = IC_COMPONENTS_BASE * 4 + max_complexity = IC_COMPLEXITY_BASE * 4 + can_anchor = TRUE + +/obj/item/device/electronic_assembly/large/default + name = "type-a electronic machine" + +/obj/item/device/electronic_assembly/large/scope + name = "type-b electronic machine" + icon_state = "setup_large_scope" + desc = "It's a case, for building large electronics with. This one resembles an oscilloscope." + +/obj/item/device/electronic_assembly/large/terminal + name = "type-c electronic machine" + icon_state = "setup_large_terminal" + desc = "It's a case, for building large electronics with. This one resembles a computer terminal." + +/obj/item/device/electronic_assembly/large/arm + name = "type-d electronic machine" + icon_state = "setup_large_arm" + desc = "It's a case, for building large electronics with. This one resembles a robotic arm." + +/obj/item/device/electronic_assembly/large/tall + name = "type-e electronic machine" + icon_state = "setup_large_tall" + desc = "It's a case, for building large electronics with. This one has a tall design." + +/obj/item/device/electronic_assembly/large/industrial + name = "type-f electronic machine" + icon_state = "setup_large_industrial" + desc = "It's a case, for building large electronics with. This one resembles some kind of industrial machinery." + +// Drone assemblies, which can move with the locomotion circuit. + +/obj/item/device/electronic_assembly/drone + name = "electronic drone" + icon_state = "setup_drone" + desc = "It's a case, for building mobile electronics with." + w_class = ITEMSIZE_NORMAL + max_components = IC_COMPONENTS_BASE * 1.5 + max_complexity = IC_COMPLEXITY_BASE * 1.5 + can_anchor = FALSE + +/obj/item/device/electronic_assembly/drone/can_move() + return TRUE + +/obj/item/device/electronic_assembly/drone/default + name = "type-a electronic drone" + +/obj/item/device/electronic_assembly/drone/arms + name = "type-b electronic drone" + icon_state = "setup_drone_arms" + desc = "It's a case, for building mobile electronics with. This one is armed and dangerous." + +/obj/item/device/electronic_assembly/drone/secbot + name = "type-c electronic drone" + icon_state = "setup_drone_secbot" + desc = "It's a case, for building mobile electronics with. This one resembles a Securitron." + +/obj/item/device/electronic_assembly/drone/medbot + name = "type-d electronic drone" + icon_state = "setup_drone_medbot" + desc = "It's a case, for building mobile electronics with. This one resembles a Medibot." + +/obj/item/device/electronic_assembly/drone/genbot + name = "type-e electronic drone" + icon_state = "setup_drone_genbot" + desc = "It's a case, for building mobile electronics with. This one has a generic bot design." + +/obj/item/device/electronic_assembly/drone/android + name = "type-f electronic drone" + icon_state = "setup_drone_android" + desc = "It's a case, for building mobile electronics with. This one has a hominoid design." + +// Wall mounted assemblies. + +/obj/item/device/electronic_assembly/wallmount + name = "wall-mounted electronic assembly" + icon_state = "setup_wallmount_medium" + desc = "It's a case, for building medium-sized electronics with. It has a magnetized \ + backing to allow it to stick to walls." + w_class = ITEMSIZE_NORMAL + max_components = IC_COMPONENTS_BASE * 2 + max_complexity = IC_COMPLEXITY_BASE * 2 + can_anchor = TRUE + +/obj/item/device/electronic_assembly/wallmount/proc/mount_assembly(turf/on_wall, mob/user) + if(get_dist(on_wall,user) > 1) + return + var/ndir = get_dir(on_wall, user) + if(!(ndir in cardinal)) + return + var/turf/T = get_turf(user) + if(!istype(T, /turf/simulated/floor)) + to_chat(user, "You cannot place \the [src] on this spot!") + return + playsound(src.loc, 'sound/machines/click.ogg', 75, 1) + user.visible_message("\The [user] attaches \the [src] to the wall.", + "You attach \the [src] to the wall.", + "You hear clicking.") + user.drop_item(T) + anchored = TRUE + on_anchored() + switch(ndir) + if(NORTH) + pixel_y = -31 + if(SOUTH) + pixel_y = 31 + if(EAST) + pixel_x = -31 + if(WEST) + pixel_x = 31 + +/obj/item/device/electronic_assembly/wallmount/on_unanchored() + pixel_x = 0 + pixel_y = 0 + ..() + +/obj/item/device/electronic_assembly/wallmount/heavy + name = "heavy wall-mounted electronic assembly" + icon_state = "setup_wallmount_large" + desc = "It's a case, for building large electronics with. It has a magnetized backing \ + to allow it to stick to walls." + w_class = ITEMSIZE_LARGE + max_components = IC_COMPONENTS_BASE * 4 + max_complexity = IC_COMPLEXITY_BASE * 4 + +/obj/item/device/electronic_assembly/wallmount/light + name = "light wall-mounted electronic assembly" + icon_state = "setup_wallmount_small" + desc = "It's a case, for building small electronics with. It has a magnetized backing \ + to allow it to stick to walls." + w_class = ITEMSIZE_SMALL + max_components = IC_COMPONENTS_BASE + max_complexity = IC_COMPLEXITY_BASE + +/obj/item/device/electronic_assembly/wallmount/tiny + name = "tiny wall-mounted electronic assembly" + icon_state = "setup_wallmount_tiny" + desc = "It's a case, for building tiny electronics with. It has a magnetized backing \ + to allow it to stick to walls." + w_class = ITEMSIZE_TINY + max_components = IC_COMPONENTS_BASE / 2 + max_complexity = IC_COMPLEXITY_BASE / 2 \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/assemblies/implant.dm b/code/modules/integrated_electronics/core/assemblies/implant.dm new file mode 100644 index 00000000000..c5a25c71318 --- /dev/null +++ b/code/modules/integrated_electronics/core/assemblies/implant.dm @@ -0,0 +1,21 @@ +// Note that this is contained inside an actual implant subtype. +// See code/game/objects/items/weapons/implants/implantcircuits.dm for where this gets held. + +/obj/item/device/electronic_assembly/implant + name = "electronic implant" + icon_state = "setup_implant" + desc = "It's a case, for building very tiny electronics with." + w_class = ITEMSIZE_TINY + max_components = IC_COMPONENTS_BASE / 2 + max_complexity = IC_COMPLEXITY_BASE / 2 + var/obj/item/weapon/implant/integrated_circuit/implant = null + +/obj/item/device/electronic_assembly/implant/nano_host() + return implant + +/obj/item/device/electronic_assembly/implant/resolve_nano_host() + return implant + +/obj/item/device/electronic_assembly/implant/update_icon() + ..() + implant.icon_state = icon_state \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/detailer.dm b/code/modules/integrated_electronics/core/detailer.dm new file mode 100644 index 00000000000..ec433d4c596 --- /dev/null +++ b/code/modules/integrated_electronics/core/detailer.dm @@ -0,0 +1,45 @@ +/obj/item/device/integrated_electronics/detailer + name = "assembly detailer" + desc = "A combination autopainter and flash anodizer designed to give electronic assemblies a colorful, wear-resistant finish." + icon = 'icons/obj/integrated_electronics/electronic_tools.dmi' + icon_state = "detailer" + item_flags = NOBLUDGEON + w_class = ITEMSIZE_SMALL + var/detail_color = COLOR_ASSEMBLY_WHITE + var/list/color_list = list( + "black" = COLOR_ASSEMBLY_BLACK, + "machine gray" = COLOR_ASSEMBLY_BGRAY, + "white" = COLOR_ASSEMBLY_WHITE, + "red" = COLOR_ASSEMBLY_RED, + "orange" = COLOR_ASSEMBLY_ORANGE, + "beige" = COLOR_ASSEMBLY_BEIGE, + "brown" = COLOR_ASSEMBLY_BROWN, + "gold" = COLOR_ASSEMBLY_GOLD, + "yellow" = COLOR_ASSEMBLY_YELLOW, + "gurkha" = COLOR_ASSEMBLY_GURKHA, + "light green" = COLOR_ASSEMBLY_LGREEN, + "green" = COLOR_ASSEMBLY_GREEN, + "light blue" = COLOR_ASSEMBLY_LBLUE, + "blue" = COLOR_ASSEMBLY_BLUE, + "purple" = COLOR_ASSEMBLY_PURPLE, + "hot pink" = COLOR_ASSEMBLY_HOT_PINK + ) + +/obj/item/device/integrated_electronics/detailer/initialize() + update_icon() + return ..() + +/obj/item/device/integrated_electronics/detailer/update_icon() + cut_overlays() + var/mutable_appearance/detail_overlay = mutable_appearance('icons/obj/integrated_electronics/electronic_tools.dmi', "detailer-color") + detail_overlay.color = detail_color + add_overlay(detail_overlay) + +/obj/item/device/integrated_electronics/detailer/attack_self(mob/user) + var/color_choice = input(user, "Select color.", "Assembly Detailer", detail_color) as null|anything in color_list + if(!color_list[color_choice]) + return + if(!in_range(src, user)) + return + detail_color = color_list[color_choice] + update_icon() diff --git a/code/modules/integrated_electronics/core/helpers.dm b/code/modules/integrated_electronics/core/helpers.dm index e31b26fbb1a..8af8f11fbac 100644 --- a/code/modules/integrated_electronics/core/helpers.dm +++ b/code/modules/integrated_electronics/core/helpers.dm @@ -1,7 +1,8 @@ /obj/item/integrated_circuit/proc/setup_io(var/list/io_list, var/io_type, var/list/io_default_list) var/list/io_list_copy = io_list.Copy() io_list.Cut() - var/i = 0 + var/i = 1 + for(var/io_entry in io_list_copy) var/default_data = null var/io_type_override = null @@ -13,10 +14,10 @@ io_type_override = io_list_copy[io_entry] if(io_type_override) - // world << "io_type_override is now [io_type_override] on [src]." io_list.Add(new io_type_override(src, io_entry, default_data)) else io_list.Add(new io_type(src, io_entry, default_data)) + i++ /obj/item/integrated_circuit/proc/set_pin_data(var/pin_type, var/pin_number, datum/new_data) if (istype(new_data) && !isweakref(new_data)) diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm index 08a31529087..d612bd72114 100644 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -330,6 +330,7 @@ a creative player the means to solve many problems. Circuits are held inside an to_chat(usr, "\The [src] seems to be permanently attached to the case.") return var/obj/item/device/electronic_assembly/ea = loc + power_fail() disconnect_all() var/turf/T = get_turf(src) forceMove(T) @@ -394,3 +395,9 @@ a creative player the means to solve many problems. Circuits are held inside an O.disconnect() for(var/datum/integrated_io/activate/A in activators) A.disconnect() + +/obj/item/integrated_circuit/proc/on_anchored() + return + +/obj/item/integrated_circuit/proc/on_unanchored() + return \ No newline at end of file diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm index 8621e2b7ed1..ef6f0a6dbcf 100644 --- a/code/modules/integrated_electronics/core/pins.dm +++ b/code/modules/integrated_electronics/core/pins.dm @@ -28,7 +28,7 @@ D [1]/ || /datum/integrated_io/New(var/newloc, var/name, var/new_data) ..() src.name = name - if(new_data) + if(!isnull(new_data)) src.data = new_data holder = newloc if(!istype(holder)) diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index 794755b02c8..fb9bfb50956 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -2,16 +2,17 @@ /obj/item/device/integrated_circuit_printer name = "integrated circuit printer" desc = "A portable(ish) machine made to print tiny modular circuitry out of metal." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_tools.dmi' icon_state = "circuit_printer" w_class = ITEMSIZE_LARGE var/metal = 0 var/max_metal = 100 var/metal_per_sheet = 10 // One sheet equals this much metal. + var/debug = FALSE // If true, metal is infinite. var/upgraded = FALSE // When hit with an upgrade disk, will turn true, allowing it to print the higher tier circuits. - var/can_clone = FALSE // Same for above, but will allow the printer to duplicate a specific assembly. - var/static/list/recipe_list = list() + var/can_clone = FALSE // Same for above, but will allow the printer to duplicate a specific assembly. (Not implemented) +// var/static/list/recipe_list = list() var/current_category = null var/obj/item/device/electronic_assembly/assembly_to_clone = null @@ -19,67 +20,32 @@ upgraded = TRUE can_clone = TRUE -/obj/item/device/integrated_circuit_printer/initialize() - . = ..() - if(!recipe_list.len) - // Unfortunately this needed a lot of loops, but it should only be run once at init. - - // First loop is to seperate the actual circuits from base circuits. - var/list/circuits_to_use = list() - for(var/obj/item/integrated_circuit/IC in all_integrated_circuits) - if((IC.spawn_flags & IC_SPAWN_DEFAULT) || (IC.spawn_flags & IC_SPAWN_RESEARCH)) - circuits_to_use.Add(IC) - - // Second loop is to find all categories. - var/list/found_categories = list() - for(var/obj/item/integrated_circuit/IC in circuits_to_use) - if(!(IC.category_text in found_categories)) - found_categories.Add(IC.category_text) - - // Third loop is to initialize lists by category names, then put circuits matching the category inside. - for(var/category in found_categories) - recipe_list[category] = list() - var/list/current_list = recipe_list[category] - for(var/obj/item/integrated_circuit/IC in circuits_to_use) - if(IC.category_text == category) - current_list.Add(IC) - - // Now for non-circuit things. - var/list/assembly_list = list() - assembly_list.Add( - new /obj/item/device/electronic_assembly(null), - new /obj/item/device/electronic_assembly/medium(null), - new /obj/item/device/electronic_assembly/large(null), - new /obj/item/device/electronic_assembly/drone(null), - new /obj/item/weapon/implant/integrated_circuit(null), - new /obj/item/device/assembly/electronic_assembly(null) - ) - recipe_list["Assemblies"] = assembly_list - - var/list/tools_list = list() - tools_list.Add( - new /obj/item/device/integrated_electronics/wirer(null), - new /obj/item/device/integrated_electronics/debugger(null) - ) - recipe_list["Tools"] = tools_list - +/obj/item/device/integrated_circuit_printer/debug + name = "fractal integrated circuit printer" + desc = "A portable(ish) machine that makes modular circuitry seemingly out of thin air." + upgraded = TRUE + can_clone = TRUE + debug = TRUE /obj/item/device/integrated_circuit_printer/attackby(var/obj/item/O, var/mob/user) if(istype(O,/obj/item/stack/material)) var/obj/item/stack/material/stack = O if(stack.material.name == DEFAULT_WALL_MATERIAL) + if(debug) + to_chat(user, span("warning", "\The [src] does not need any material.")) + return var/num = min((max_metal - metal) / metal_per_sheet, stack.amount) if(num < 1) - to_chat(user, "\The [src] is too full to add more metal.") + to_chat(user, span("warning", "\The [src] is too full to add more metal.")) return if(stack.use(num)) - to_chat(user, "You add [num] sheet\s to \the [src].") + to_chat(user, span("notice", "You add [num] sheet\s to \the [src].")) metal += num * metal_per_sheet interact(user) return TRUE if(istype(O,/obj/item/integrated_circuit)) - to_chat(user, "You insert the circuit into \the [src]. ") + to_chat(user, span("notice", "You insert the circuit into \the [src].")) user.unEquip(O) metal = min(metal + O.w_class, max_metal) qdel(O) @@ -88,18 +54,18 @@ if(istype(O,/obj/item/weapon/disk/integrated_circuit/upgrade/advanced)) if(upgraded) - to_chat(user, "\The [src] already has this upgrade. ") + to_chat(user, span("warning", "\The [src] already has this upgrade.")) return TRUE - to_chat(user, "You install \the [O] into \the [src]. ") + to_chat(user, span("notice", "You install \the [O] into \the [src].")) upgraded = TRUE interact(user) return TRUE if(istype(O,/obj/item/weapon/disk/integrated_circuit/upgrade/clone)) if(can_clone) - to_chat(user, "\The [src] already has this upgrade. ") + to_chat(user, span("warning", "\The [src] already has this upgrade.")) return TRUE - to_chat(user, "You install \the [O] into \the [src]. ") + to_chat(user, span("notice", "You install \the [O] into \the [src].")) can_clone = TRUE interact(user) return TRUE @@ -114,18 +80,21 @@ var/window_width = 500 if(isnull(current_category)) - current_category = recipe_list[1] + current_category = SScircuit.circuit_fabricator_recipe_list[1] var/HTML = "

Integrated Circuit Printer


" - HTML += "Metal: [metal/metal_per_sheet]/[max_metal/metal_per_sheet] sheets.
" - HTML += "Circuits available: [upgraded ? "Regular":"Advanced"]." - HTML += "Assembly Cloning: [can_clone ? "Available": "Unavailable"]." + if(!debug) + HTML += "Metal: [metal/metal_per_sheet]/[max_metal/metal_per_sheet] sheets.
" + else + HTML += "Metal: INFINITY.
" + HTML += "Circuits available: [upgraded ? "Advanced":"Regular"].
" + HTML += "Assembly Cloning: [can_clone ? "Available": "Unavailable"].
" if(assembly_to_clone) - HTML += "Assembly '[assembly_to_clone.name]' loaded." + HTML += "Assembly '[assembly_to_clone.name]' loaded.
" HTML += "Crossed out circuits mean that the printer is not sufficentally upgraded to create that circuit.
" HTML += "
" HTML += "Categories:" - for(var/category in recipe_list) + for(var/category in SScircuit.circuit_fabricator_recipe_list) if(category != current_category) HTML += " \[[category]\] " else // Bold the button if it's already selected. @@ -133,20 +102,22 @@ HTML += "
" HTML += "

[current_category]

" - var/list/current_list = recipe_list[current_category] - for(var/obj/O in current_list) + var/list/current_list = SScircuit.circuit_fabricator_recipe_list[current_category] + for(var/path in current_list) + var/obj/O = path var/can_build = TRUE - if(istype(O, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = O - if((IC.spawn_flags & IC_SPAWN_RESEARCH) && (!(IC.spawn_flags & IC_SPAWN_DEFAULT)) && !upgraded) + if(ispath(path, /obj/item/integrated_circuit)) + var/obj/item/integrated_circuit/IC = path + if((initial(IC.spawn_flags) & IC_SPAWN_RESEARCH) && (!(initial(IC.spawn_flags) & IC_SPAWN_DEFAULT)) && !upgraded) can_build = FALSE if(can_build) - HTML += "\[[O.name]\]: [O.desc]
" + HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
" else - HTML += "\[[O.name]\]: [O.desc]
" + HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
" user << browse(jointext(HTML, null), "window=integrated_printer;size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") + /obj/item/device/integrated_circuit_printer/Topic(href, href_list) if(..()) return 1 @@ -162,31 +133,36 @@ return 1 var/cost = 1 - + if(isnull(current_category)) - current_category = recipe_list[1] + current_category = SScircuit.circuit_fabricator_recipe_list[1] if(ispath(build_type, /obj/item/device/electronic_assembly)) var/obj/item/device/electronic_assembly/E = build_type cost = round( (initial(E.max_complexity) + initial(E.max_components) ) / 4) else var/obj/item/I = build_type cost = initial(I.w_class) - if(!(locate(build_type) in recipe_list[current_category])) + if(!build_type in SScircuit.circuit_fabricator_recipe_list[current_category]) return - if(metal - cost < 0) - to_chat(usr, "You need [cost] metal to build that!.") - return 1 - metal -= cost - new build_type(get_turf(loc)) + if(!debug) + if(metal - cost < 0) + to_chat(usr, "You need [cost] metal to build that!.") + return 1 + metal -= cost + var/obj/item/built = new build_type(get_turf(loc)) + usr.put_in_hands(built) + to_chat(usr, "[capitalize(built.name)] printed.") + playsound(src, 'sound/items/jaws_pry.ogg', 50, TRUE) interact(usr) + // FUKKEN UPGRADE DISKS /obj/item/weapon/disk/integrated_circuit/upgrade name = "integrated circuit printer upgrade disk" desc = "Install this into your integrated circuit printer to enhance it." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_tools.dmi' icon_state = "upgrade_disk" item_state = "card-id" w_class = ITEMSIZE_SMALL diff --git a/code/modules/integrated_electronics/core/special_pins/color_pin.dm b/code/modules/integrated_electronics/core/special_pins/color_pin.dm index 2d20560fb6e..e58d2d8e756 100644 --- a/code/modules/integrated_electronics/core/special_pins/color_pin.dm +++ b/code/modules/integrated_electronics/core/special_pins/color_pin.dm @@ -3,7 +3,7 @@ name = "color pin" /datum/integrated_io/color/ask_for_pin_data(mob/user) - var/new_data = input("Please select a color.","[src] color writing") as null|color + var/new_data = input("Please select a color.","[src] color writing", data ? data : "#000000") as null|color if(holder.check_interactivity(user) ) to_chat(user, "You input a new color into the pin.") write_data_to_pin(new_data) diff --git a/code/modules/integrated_electronics/core/tools.dm b/code/modules/integrated_electronics/core/tools.dm index 5d4133e3d3d..eb42d92dda3 100644 --- a/code/modules/integrated_electronics/core/tools.dm +++ b/code/modules/integrated_electronics/core/tools.dm @@ -9,11 +9,11 @@ desc = "It's a small wiring tool, with a wire roll, electric soldering iron, wire cutter, and more in one package. \ The wires used are generally useful for small electronics, such as circuitboards and breadboards, as opposed to larger wires \ used for power or data transmission." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_tools.dmi' icon_state = "wirer-wire" item_state = "wirer" flags = CONDUCT - w_class = 2 + w_class = ITEMSIZE_SMALL var/datum/integrated_io/selected_io = null var/mode = WIRE @@ -108,7 +108,7 @@ name = "circuit debugger" desc = "This small tool allows one working with custom machinery to directly set data to a specific pin, useful for writing \ settings to specific circuits, or for debugging purposes. It can also pulse activation pins." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_tools.dmi' icon_state = "debugger" flags = CONDUCT w_class = 2 @@ -252,7 +252,7 @@ /obj/item/weapon/storage/bag/circuits name = "circuit kit" desc = "This kit's essential for any circuitry projects." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_misc.dmi' icon_state = "circuit_kit" w_class = 3 display_contents_with_number = 0 @@ -261,11 +261,11 @@ /obj/item/weapon/storage/bag/circuits/mini, /obj/item/device/electronic_assembly, /obj/item/device/integrated_electronics, - /obj/item/weapon/crowbar, - /obj/item/weapon/screwdriver, + /obj/item/weapon/tool/crowbar, + /obj/item/weapon/tool/screwdriver, /obj/item/device/multitool ) - cant_hold = list(/obj/item/weapon/screwdriver/power) + cant_hold = list(/obj/item/weapon/tool/screwdriver/power) /obj/item/weapon/storage/bag/circuits/basic/New() ..() @@ -290,8 +290,8 @@ new /obj/item/device/assembly/electronic_assembly(src) new /obj/item/device/assembly/electronic_assembly(src) new /obj/item/device/multitool(src) - new /obj/item/weapon/screwdriver(src) - new /obj/item/weapon/crowbar(src) + new /obj/item/weapon/tool/screwdriver(src) + new /obj/item/weapon/tool/crowbar(src) make_exact_fit() /obj/item/weapon/storage/bag/circuits/all/New() @@ -317,7 +317,7 @@ new /obj/item/device/electronic_assembly/drone(src) new /obj/item/device/integrated_electronics/wirer(src) new /obj/item/device/integrated_electronics/debugger(src) - new /obj/item/weapon/crowbar(src) + new /obj/item/weapon/tool/crowbar(src) make_exact_fit() /obj/item/weapon/storage/bag/circuits/mini/ diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm index 0a516e360a7..829027303c8 100644 --- a/code/modules/integrated_electronics/passive/power.dm +++ b/code/modules/integrated_electronics/passive/power.dm @@ -6,7 +6,7 @@ origin_tech = list(TECH_POWER = 2, TECH_ENGINEERING = 2, TECH_DATA = 2) category_text = "Power - Passive" -/obj/item/integrated_circuit/passive/power/proc/make_energy() +/obj/item/integrated_circuit/passive/power/proc/handle_passive_energy() return // For calculators. @@ -20,7 +20,7 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH var/max_power = 1 -/obj/item/integrated_circuit/passive/power/solar_cell/make_energy() +/obj/item/integrated_circuit/passive/power/solar_cell/handle_passive_energy() var/turf/T = get_turf(src) var/light_amount = T ? T.get_lumcount() : 0 var/adjusted_power = max(max_power * light_amount, 0) @@ -39,7 +39,7 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH var/is_charge=0 -/obj/item/integrated_circuit/passive/power/starter/make_energy() +/obj/item/integrated_circuit/passive/power/starter/handle_passive_energy() if(assembly.battery) if(assembly.battery.charge) if(!is_charge) @@ -67,7 +67,7 @@ return FALSE // Robots and dead people don't have a metabolism. return TRUE -/obj/item/integrated_circuit/passive/power/metabolic_siphon/make_energy() +/obj/item/integrated_circuit/passive/power/metabolic_siphon/handle_passive_energy() var/mob/living/carbon/human/host = null if(assembly && istype(assembly, /obj/item/device/electronic_assembly/implant)) var/obj/item/device/electronic_assembly/implant/implant_assembly = assembly @@ -135,7 +135,7 @@ set_pin_data(IC_OUTPUT, 1, reagents.total_volume) push_data() -/obj/item/integrated_circuit/passive/power/chemical_cell/make_energy() +/obj/item/integrated_circuit/passive/power/chemical_cell/handle_passive_energy() if(assembly) for(var/I in fuel) if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > fuel[I]) @@ -156,7 +156,7 @@ spawn_flags = IC_SPAWN_RESEARCH power_amount = 2000 -/obj/item/integrated_circuit/passive/power/relay/make_energy() +/obj/item/integrated_circuit/passive/power/relay/handle_passive_energy() if(!assembly) return var/area/A = get_area(src) @@ -164,3 +164,78 @@ if(A.powered(EQUIP) && assembly.give_power(power_amount)) A.use_power(power_amount, EQUIP) // give_power() handles CELLRATE on its own. + +// Interacts with the powernet. +// Now you can make your own power generation (or poor man's powersink). + +/obj/item/integrated_circuit/passive/power/powernet + name = "power network interface" + desc = "Gives or takes power from a wire underneath the machine." + icon_state = "powernet" + extended_desc = "The assembly must be anchored, with a wrench, and a wire node must be avaiable directly underneath.
\ + The first pin determines if power is moved at all. The second pin, if true, will draw from the powernet to charge the assembly's \ + cell, otherwise it will give power from the cell to the powernet." + complexity = 20 + inputs = list( + "active" = IC_PINTYPE_BOOLEAN, + "draw power" = IC_PINTYPE_BOOLEAN + ) + outputs = list( + "power in grid" = IC_PINTYPE_NUMBER, + "surplus power" = IC_PINTYPE_NUMBER, + "load" = IC_PINTYPE_NUMBER + ) + activators = list() + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 2, TECH_POWER = 2) + var/obj/machinery/power/circuit_io/IO = null // Dummy power machine to move energy in/out without a bunch of code duplication. + var/throughput = 10000 // Give/take up to 10kW. + +/obj/item/integrated_circuit/passive/power/powernet/initialize() + IO = new(src) + return ..() + +/obj/item/integrated_circuit/passive/power/powernet/Destroy() + qdel(IO) + return ..() + +/obj/item/integrated_circuit/passive/power/powernet/on_anchored() + IO.connect_to_network() + +/obj/item/integrated_circuit/passive/power/powernet/on_unanchored() + IO.disconnect_from_network() + +/obj/item/integrated_circuit/passive/power/powernet/handle_passive_energy() + if(assembly && assembly.anchored && assembly.battery) + var/should_act = get_pin_data(IC_INPUT, 1) // Even if this is false, we still need to update the output pins with powernet information. + var/drawing = get_pin_data(IC_INPUT, 2) + + if(should_act) // We're gonna give or take from the net. + if(drawing) + var/to_transfer = min(throughput, assembly.battery.amount_missing() / CELLRATE) // So we don't need to draw 10kW if the cell needs much less. + var/amount = IO.draw_power(to_transfer) + assembly.give_power(amount) + else + var/amount = assembly.draw_power(throughput) + IO.add_avail(amount) + + set_pin_data(IC_OUTPUT, 1, IO.avail()) + set_pin_data(IC_OUTPUT, 2, IO.surplus()) + set_pin_data(IC_OUTPUT, 3, IO.viewload()) + +// Internal power machine for interacting with the powernet. +// It needs a bit of special code since base /machinery/power assumes loc will be a tile. +/obj/machinery/power/circuit_io + name = "embedded electrical I/O" + +/obj/machinery/power/circuit_io/connect_to_network() + var/turf/T = get_turf(src) + if(!T || !istype(T)) + return FALSE + + var/obj/structure/cable/C = T.get_cable_node() + if(!C || !C.powernet) + return FALSE + + C.powernet.add_machine(src) + return TRUE diff --git a/code/modules/integrated_electronics/subtypes/built_in.dm b/code/modules/integrated_electronics/subtypes/built_in.dm index 24eac868029..afb804c797c 100644 --- a/code/modules/integrated_electronics/subtypes/built_in.dm +++ b/code/modules/integrated_electronics/subtypes/built_in.dm @@ -1,7 +1,7 @@ /obj/item/integrated_circuit/built_in name = "integrated circuit" desc = "It's a tiny chip! This one doesn't seem to do much, however." - icon = 'icons/obj/electronic_assemblies.dmi' + icon = 'icons/obj/integrated_electronics/electronic_setups.dmi' icon_state = "template" size = -1 w_class = ITEMSIZE_TINY @@ -25,4 +25,15 @@ /obj/item/integrated_circuit/built_in/device_output/do_work() if(istype(assembly, /obj/item/device/electronic_assembly/device)) var/obj/item/device/electronic_assembly/device/device = assembly - device.holder.pulse() \ No newline at end of file + device.holder.pulse() + +// Triggered when clothing assembly's hud button is clicked (or used inhand). +/obj/item/integrated_circuit/built_in/action_button + name = "external trigger circuit" + desc = "A built in chip that outputs a pulse when an external control event occurs." + extended_desc = "This outputs a pulse if the assembly's HUD button is clicked while the assembly is closed." + complexity = 0 + activators = list("on activation" = IC_PINTYPE_PULSE_OUT) + +/obj/item/integrated_circuit/built_in/action_button/do_work() + activate_pin(1) \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm index b9f5c912d4c..0ec00be317c 100644 --- a/code/modules/integrated_electronics/subtypes/converters.dm +++ b/code/modules/integrated_electronics/subtypes/converters.dm @@ -318,5 +318,77 @@ set_pin_data(IC_OUTPUT, 1, x1 - x2) set_pin_data(IC_OUTPUT, 2, y1 - y2) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/converter/stringlength + name = "len circuit" + desc = "This circuit will return the number of characters in a string." + complexity = 1 + inputs = list( + "string" = IC_PINTYPE_STRING + ) + outputs = list( + "length" = IC_PINTYPE_NUMBER + ) + activators = list("get length" = IC_PINTYPE_PULSE_IN, "on acquisition" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/converter/stringlength/do_work() + set_pin_data(IC_OUTPUT, 1, length(get_pin_data(IC_INPUT, 1))) + push_data() + + activate_pin(2) + +/obj/item/integrated_circuit/converter/hsv2hex + name = "hsv to hexadecimal converter" + desc = "This circuit can convert a HSV (Hue, Saturation, and Value) color to a Hexadecimal RGB color." + extended_desc = "The first pin controls tint (0-359), the second pin controls how intense the tint is (0-255), \ + and the third controls how bright the tint is (0 for black, 127 for normal, 255 for white)." + icon_state = "hsv-hex" + inputs = list( + "hue" = IC_PINTYPE_NUMBER, + "saturation" = IC_PINTYPE_NUMBER, + "value" = IC_PINTYPE_NUMBER + ) + outputs = list("hexadecimal rgb" = IC_PINTYPE_COLOR) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/converter/hsv2hex/do_work() + var/result = null + pull_data() + var/hue = get_pin_data(IC_INPUT, 1) + var/saturation = get_pin_data(IC_INPUT, 2) + var/value = get_pin_data(IC_INPUT, 3) + if(isnum(hue) && isnum(saturation) && isnum(value)) + result = HSVtoRGB(hsv(AngleToHue(hue),saturation,value)) + + set_pin_data(IC_OUTPUT, 1, result) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/converter/rgb2hex + name = "rgb to hexadecimal converter" + desc = "This circuit can convert a RGB (Red, Green, Blue) color to a Hexadecimal RGB color." + extended_desc = "The first pin controls red amount, the second pin controls green amount, and the third controls blue amount. They all go from 0-255." + icon_state = "rgb-hex" + inputs = list( + "red" = IC_PINTYPE_NUMBER, + "green" = IC_PINTYPE_NUMBER, + "blue" = IC_PINTYPE_NUMBER + ) + outputs = list("hexadecimal rgb" = IC_PINTYPE_COLOR) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/converter/rgb2hex/do_work() + var/result = null + pull_data() + var/red = get_pin_data(IC_INPUT, 1) + var/green = get_pin_data(IC_INPUT, 2) + var/blue = get_pin_data(IC_INPUT, 3) + if(isnum(red) && isnum(green) && isnum(blue)) + result = rgb(red, green, blue) + + set_pin_data(IC_OUTPUT, 1, result) push_data() activate_pin(2) \ No newline at end of file diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index ac9a0e13f9d..c2e640403a8 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -53,7 +53,7 @@ power_draw_per_use = 4 /obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user) - var/new_input = input(user, "Enter a number, please.","Number pad") as null|num + var/new_input = input(user, "Enter a number, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|num if(isnum(new_input) && CanInteract(user, physical_state)) set_pin_data(IC_OUTPUT, 1, new_input) push_data() @@ -72,18 +72,37 @@ power_draw_per_use = 4 /obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user) - var/new_input = input(user, "Enter some words, please.","Number pad") as null|text + var/new_input = input(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|text if(istext(new_input) && CanInteract(user, physical_state)) set_pin_data(IC_OUTPUT, 1, new_input) push_data() activate_pin(1) +/obj/item/integrated_circuit/input/colorpad + name = "color pad" + desc = "This small color pad allows someone to input a hexadecimal color into the system." + icon_state = "colorpad" + complexity = 2 + can_be_asked_input = 1 + inputs = list() + outputs = list("color entered" = IC_PINTYPE_COLOR) + activators = list("on entered" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + +/obj/item/integrated_circuit/input/colorpad/ask_for_input(mob/user) + var/new_color = input(user, "Enter a color, please.", "Color pad", get_pin_data(IC_OUTPUT, 1)) as color|null + if(new_color && CanInteract(user, physical_state)) + set_pin_data(IC_OUTPUT, 1, new_color) + push_data() + activate_pin(1) + /obj/item/integrated_circuit/input/med_scanner name = "integrated medical analyser" desc = "A very small version of the common medical analyser. This allows the machine to know how healthy someone is." icon_state = "medscan" complexity = 4 - inputs = list("\ target") + inputs = list("target" = IC_PINTYPE_REF) outputs = list( "total health %" = IC_PINTYPE_NUMBER, "total missing health" = IC_PINTYPE_NUMBER @@ -117,7 +136,7 @@ This type is much more precise, allowing the machine to know much more about the target than a normal analyzer." icon_state = "medscan_adv" complexity = 12 - inputs = list("\ target") + inputs = list("target" = IC_PINTYPE_REF) outputs = list( "total health %" = IC_PINTYPE_NUMBER, "total missing health" = IC_PINTYPE_NUMBER, @@ -159,7 +178,7 @@ relative coordinates, total amount of reagents, and maximum amount of reagents of the referenced object." icon_state = "video_camera" complexity = 6 - inputs = list("\ target" = IC_PINTYPE_REF) + inputs = list("target" = IC_PINTYPE_REF) outputs = list( "name" = IC_PINTYPE_STRING, "description" = IC_PINTYPE_STRING, @@ -262,7 +281,7 @@ complexity = 6 name = "advanced locator" desc = "This is needed for certain devices that demand a reference for a target to act upon. This type locates something \ - that is standing in given radius of up to 8 meters" + that is standing in given radius of up to 7 meters" extended_desc = "The first pin requires a ref to a kind of object that you want the locator to acquire. This means that it will \ give refs to nearby objects that are similar to given sample. If this pin is a string, the locator will search for\ item by matching desired text in name + description. If more than one valid object is found nearby, it will choose one of them at \ @@ -277,7 +296,7 @@ /obj/item/integrated_circuit/input/advanced_locator/on_data_written() var/rad = get_pin_data(IC_INPUT, 2) if(isnum(rad)) - rad = Clamp(rad, 0, 8) + rad = Clamp(rad, 0, 7) radius = rad /obj/item/integrated_circuit/input/advanced_locator/do_work() diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm index 3e53a069f30..344a7dc47e8 100644 --- a/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -32,13 +32,13 @@ if(istype(O, /obj/item/weapon/gun)) var/obj/item/weapon/gun/gun = O if(installed_gun) - user << "There's already a weapon installed." + to_chat(user, "There's already a weapon installed.") return user.drop_from_inventory(gun) installed_gun = gun size += gun.w_class gun.forceMove(src) - user << "You slide \the [gun] into the firing mechanism." + to_chat(user, "You slide \the [gun] into the firing mechanism.") playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) else ..() @@ -46,12 +46,12 @@ /obj/item/integrated_circuit/manipulation/weapon_firing/attack_self(var/mob/user) if(installed_gun) installed_gun.forceMove(get_turf(src)) - user << "You slide \the [installed_gun] out of the firing mechanism." + to_chat(user, "You slide \the [installed_gun] out of the firing mechanism.") size = initial(size) playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) installed_gun = null else - user << "There's no weapon to remove from the mechanism." + to_chat(user, "There's no weapon to remove from the mechanism.") /obj/item/integrated_circuit/manipulation/weapon_firing/do_work() if(!installed_gun) diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm index beefed282e1..c3ff9b36d5d 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/code/modules/integrated_electronics/subtypes/output.dm @@ -78,7 +78,25 @@ else if(assembly) assembly.set_light(0) - power_draw_idle = light_toggled ? light_brightness * 2 : 0 + power_draw_idle = light_toggled ? light_brightness * light_brightness : 0 // Should be the same draw as regular lights. + +/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left. + light_toggled = FALSE + update_lighting() + +/obj/item/integrated_circuit/output/light/advanced + name = "advanced light" + desc = "This light can turn on and off on command, in any color, and in various brightness levels." + extended_desc = "The brightness is limited to values between 1 and 6." + icon_state = "light_adv" + complexity = 8 + inputs = list( + "color" = IC_PINTYPE_COLOR, + "brightness" = IC_PINTYPE_NUMBER + ) + outputs = list() + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) /obj/item/integrated_circuit/output/light/advanced/update_lighting() var/new_color = get_pin_data(IC_INPUT, 1) @@ -91,42 +109,9 @@ ..() -/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left. - light_toggled = FALSE - update_lighting() - -/obj/item/integrated_circuit/output/light/advanced - name = "advanced light" - desc = "This light can turn on and off on command, in any color, and in various brightness levels." - icon_state = "light_adv" - complexity = 8 - inputs = list( - "color" = IC_PINTYPE_COLOR, - "brightness" = IC_PINTYPE_NUMBER - ) - outputs = list() - spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH - origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) - /obj/item/integrated_circuit/output/light/advanced/on_data_written() update_lighting() -/obj/item/integrated_circuit/output/sound - name = "speaker circuit" - desc = "A miniature speaker is attached to this component." - icon_state = "speaker" - complexity = 8 - cooldown_per_use = 4 SECONDS - inputs = list( - "sound ID" = IC_PINTYPE_STRING, - "volume" = IC_PINTYPE_NUMBER, - "frequency" = IC_PINTYPE_BOOLEAN - ) - outputs = list() - activators = list("play sound" = IC_PINTYPE_PULSE_IN) - power_draw_per_use = 20 - var/list/sounds = list() - /obj/item/integrated_circuit/output/text_to_speech name = "text-to-speech circuit" desc = "A miniature speaker is attached to this component." @@ -146,6 +131,22 @@ var/obj/O = assembly ? loc : assembly audible_message("\icon[O] \The [O.name] states, \"[text]\"") +/obj/item/integrated_circuit/output/sound + name = "speaker circuit" + desc = "A miniature speaker is attached to this component." + icon_state = "speaker" + complexity = 8 + cooldown_per_use = 4 SECONDS + inputs = list( + "sound ID" = IC_PINTYPE_STRING, + "volume" = IC_PINTYPE_NUMBER, + "frequency" = IC_PINTYPE_BOOLEAN + ) + outputs = list() + activators = list("play sound" = IC_PINTYPE_PULSE_IN) + power_draw_per_use = 20 + var/list/sounds = list() + /obj/item/integrated_circuit/output/sound/New() ..() extended_desc = list() @@ -246,7 +247,7 @@ on_data_written() /obj/item/integrated_circuit/output/video_camera/Destroy() - qdel_null(camera) + QDEL_NULL(camera) return ..() /obj/item/integrated_circuit/output/video_camera/proc/set_camera_status(var/status) @@ -337,3 +338,147 @@ /obj/item/integrated_circuit/output/led/pink name = "pink LED" led_color = COLOR_PINK + + + +/obj/item/integrated_circuit/output/holographic_projector + name = "holographic projector" + desc = "This projects a holographic copy of an object." + extended_desc = "If the assembly moves, the hologram will also move.
\ + Position coordinates are relative to the assembly, and are capped between -7 and 7.
\ + The assembly must be able to see the object to make a holographic copy of it.
\ + Scaling is capped between -2 and 2.
\ + The rotation pin uses degrees.
\ + Imitated object cannot be changed while projecting. Position, \ + scale, and rotation can be updated without restarting by pulsing the update hologram pin." + complexity = 40 + icon_state = "holo_projector" + inputs = list( + "project hologram" = IC_PINTYPE_BOOLEAN, + "object to copy" = IC_PINTYPE_REF, + "hologram color" = IC_PINTYPE_COLOR, + "hologram X pos" = IC_PINTYPE_NUMBER, + "hologram Y pos" = IC_PINTYPE_NUMBER, + "hologram scale" = IC_PINTYPE_NUMBER, + "hologram rotation" = IC_PINTYPE_NUMBER + ) + inputs_default = list( + "3" = "#7DB4E1", + "4" = 0, + "5" = 0, + "6" = 1, + "7" = 0 + ) + outputs = list() + activators = list( + "update hologram" = IC_PINTYPE_PULSE_IN, + "on drawn hologram" = IC_PINTYPE_PULSE_OUT + ) + power_draw_idle = 0 // Raises to 500 when active, like a regular holopad. + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/obj/effect/overlay/holographic/hologram = null // Reference to the hologram effect, and also used to see if component is active. + var/icon/holo_base = null // Uncolored holographic icon. +// var/datum/beam/holo_beam = null // A visual effect, to make it easy to know where a hologram is coming from. + // It is commented out due to picking up the assembly killing the beam. + +/obj/item/integrated_circuit/output/holographic_projector/Destroy() + destroy_hologram() + return ..() + +/obj/item/integrated_circuit/output/holographic_projector/do_work() + var/toggled = get_pin_data(IC_INPUT, 1) + + if(hologram) // Currently active. + if(!toggled) // Being turned off. + destroy_hologram() + + else // Updating position/dir/etc. + update_hologram() + + else // Currently not active. + if(toggled) // We're gonna turn on. + create_hologram() + + activate_pin(2) + +// Updates some changable aspects of the hologram like the size or position. +/obj/item/integrated_circuit/output/holographic_projector/proc/update_hologram() + if(!hologram) + return FALSE + + var/holo_scale = get_pin_data(IC_INPUT, 6) + var/holo_rotation = get_pin_data(IC_INPUT, 7) + + if(!isnum(holo_scale) || !isnum(holo_rotation) ) + return FALSE // Invalid. + + hologram.adjust_scale(between(-2, holo_scale, 2) ) + hologram.adjust_rotation(holo_rotation) + update_hologram_position() + + return TRUE + +// This is a seperate function because other things besides do_work() might warrant updating position, like movement, without bothering with other parts. +/obj/item/integrated_circuit/output/holographic_projector/proc/update_hologram_position() + var/holo_x = get_pin_data(IC_INPUT, 4) + var/holo_y = get_pin_data(IC_INPUT, 5) + if(!isnum(holo_x) || !isnum(holo_y) ) + return FALSE + + holo_x = between(-7, holo_x, 7) + holo_y = between(-7, holo_y, 7) + + var/turf/T = get_turf(src) + if(T) + // Absolute coordinates. + var/holo_abs_x = T.x + holo_x + var/holo_abs_y = T.y + holo_y + var/turf/W = locate(holo_abs_x, holo_abs_y, T.z) + if(W) // Make sure we're not out of bounds. + hologram.forceMove(W) + return TRUE + return FALSE + +/obj/item/integrated_circuit/output/holographic_projector/proc/create_hologram() + var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) + var/holo_color = get_pin_data(IC_INPUT, 3) + + if(istype(AM) && assembly) + if(AM in view(get_turf(src))) // It must be able to 'see' the object it will copy. + hologram = new(src) + var/icon/holo_icon = getHologramIcon(getFlatIcon(AM), no_color = TRUE) + // holo_icon.GrayScale() // So it looks better colored. + if(holo_color) // The color pin should ensure that it is a valid hex. + holo_icon.ColorTone(holo_color) + hologram.icon = holo_icon + hologram.name = "[AM.name] (Hologram)" + update_hologram() + + // holo_beam = assembly.Beam(hologram, icon_state = "holo_beam", time = INFINITY, maxdistance = world.view) + power_draw_idle = 500 + return TRUE + return FALSE + + + +/obj/item/integrated_circuit/output/holographic_projector/proc/destroy_hologram() + hologram.forceMove(src) + qdel(hologram) + +// holo_beam.End() +// QDEL_NULL(holo_beam) + + power_draw_idle = 0 + +/obj/item/integrated_circuit/output/holographic_projector/on_data_written() + if(hologram) + update_hologram() + +/obj/item/integrated_circuit/output/holographic_projector/on_loc_moved(atom/oldloc) + if(hologram) + update_hologram_position() + +/obj/item/integrated_circuit/output/holographic_projector/power_fail() + if(hologram) + destroy_hologram() + set_pin_data(IC_INPUT, 1, FALSE) diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 65929e51c9a..e8ca2ae134f 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -2,7 +2,6 @@ category_text = "Reagent" var/volume = 0 unacidable = 1 - phoronproof = 1 origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) /obj/item/integrated_circuit/reagent/New() diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 9ea12b967c7..a5da1936780 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,8 +1,19 @@ /mob/living/death() clear_fullscreens() + reveal(TRUE) //Silently reveal the mob if they were hidden. //VOREStation Edit - Mob spawner stuff if(source_spawner) source_spawner.get_death_report(src) source_spawner = null //VOREStation Edit End - . = ..() \ No newline at end of file + . = ..() + + if(nest) //Ew. + if(istype(nest, /obj/structure/prop/nest)) + var/obj/structure/prop/nest/N = nest + N.remove_creature(src) + if(istype(nest, /obj/structure/blob/factory)) + var/obj/structure/blob/factory/F = nest + F.spores -= src + nest = null + . = ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0bcfcf61745..3bcfbe7b60e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -19,6 +19,14 @@ /mob/living/Destroy() dsoverlay.loc = null //I'll take my coat with me dsoverlay = null + if(nest) //Ew. + if(istype(nest, /obj/structure/prop/nest)) + var/obj/structure/prop/nest/N = nest + N.remove_creature(src) + if(istype(nest, /obj/structure/blob/factory)) + var/obj/structure/blob/factory/F = nest + F.spores -= src + nest = null if(buckled) buckled.unbuckle_mob(src, TRUE) return ..() @@ -214,6 +222,11 @@ default behaviour is: return return +/mob/living/CanPass(atom/movable/mover, turf/target) + if(istype(mover, /obj/structure/blob) && faction == "blob") //Blobs should ignore things on their faction. + return TRUE + return ..() + /mob/living/verb/succumb() set hidden = 1 if ((src.health < 0 && src.health > (5-src.getMaxHealth()))) // Health below Zero but above 5-away-from-death, as before, but variable @@ -987,40 +1000,41 @@ default behaviour is: else to_chat(src, "You feel nauseous...") - if(!skip_wait) - sleep(150) //15 seconds until second warning - to_chat(src, "You feel like you are about to throw up!") - sleep(100) //and you have 10 more for mad dash to the bucket + spawn() + if(!skip_wait) + sleep(150) //15 seconds until second warning + to_chat(src, "You feel like you are about to throw up!") + sleep(100) //and you have 10 more for mad dash to the bucket - //Damaged livers cause you to vomit blood. - if(!blood_vomit) - if(ishuman(src)) - var/mob/living/carbon/human/H = src - if(!H.isSynthetic()) - var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"] - if(L.is_broken()) - blood_vomit = 1 + //Damaged livers cause you to vomit blood. + if(!blood_vomit) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(!H.isSynthetic()) + var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"] + if(L.is_broken()) + blood_vomit = 1 - Stun(5) - src.visible_message("[src] throws up!","You throw up!") - playsound(loc, 'sound/effects/splat.ogg', 50, 1) + Stun(5) + src.visible_message("[src] throws up!","You throw up!") + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + + var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs + if(istype(T)) + if(blood_vomit) + T.add_blood_floor(src) + else + T.add_vomit_floor(src, 1) - var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs - if(istype(T)) if(blood_vomit) - T.add_blood_floor(src) + if(getBruteLoss() < 50) + adjustBruteLoss(3) else - T.add_vomit_floor(src, 1) + nutrition -= 40 + adjustToxLoss(-3) - if(blood_vomit) - if(getBruteLoss() < 50) - adjustBruteLoss(3) - else - nutrition -= 40 - adjustToxLoss(-3) - - sleep(350) - lastpuke = 0 + spawn(350) + lastpuke = 0 /mob/living/update_canmove() if(!resting && cannot_stand() && can_stand_overridden()) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 1bacfb8ea84..23d92fee723 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -163,7 +163,7 @@ ..() /mob/living/blob_act(var/obj/structure/blob/B) - if(stat == DEAD) + if(stat == DEAD || faction == "blob") return var/damage = rand(30, 40) @@ -221,11 +221,6 @@ /mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/soaked, var/hit_zone) if(!effective_force || blocked >= 100) return 0 - - //Hulk modifier - if(HULK in user.mutations) - effective_force *= 2 - //Apply weapon damage var/weapon_sharp = is_sharp(I) var/weapon_edge = has_edge(I) @@ -380,8 +375,13 @@ var/turf/location = get_turf(src) location.hotspot_expose(fire_burn_temperature(), 50, 1) -/mob/living/fire_act() - adjust_fire_stacks(2) +//altered this to cap at the temperature of the fire causing it, using the same 1:1500 value as /mob/living/carbon/human/handle_fire() in human/life.dm +/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature) + if(fire_stacks < exposed_temperature/1500) // Subject to balance + adjust_fire_stacks(2) + else + adjust_fire_stacks(2) IgniteMob() //Share fire evenly between the two mobs @@ -502,3 +502,15 @@ if(!isnull(M.evasion)) result += M.evasion return result + +/mob/living/proc/get_accuracy_penalty() + // Certain statuses make it harder to score a hit. + var/accuracy_penalty = 0 + if(eye_blind) + accuracy_penalty += 75 + if(eye_blurry) + accuracy_penalty += 30 + if(confused) + accuracy_penalty += 45 + + return accuracy_penalty \ No newline at end of file diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 391d0ad04dc..c856e8d8309 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -56,7 +56,9 @@ var/see_invisible_default = SEE_INVISIBLE_LIVING + var/nest //Not specific, because a Nest may be the prop nest, or blob factory in this case. + var/list/hud_list //Holder for health hud, status hud, wanted hud, etc (not like inventory slots) var/has_huds = FALSE //Whether or not we should bother initializing the above list - var/makes_dirt = TRUE //FALSE if the mob shouldn't be making dirt on the ground when it walks + var/makes_dirt = TRUE //FALSE if the mob shouldn't be making dirt on the ground when it walks \ No newline at end of file diff --git a/code/modules/mob/living/living_powers.dm b/code/modules/mob/living/living_powers.dm index 1442c80f9ba..787dd313619 100644 --- a/code/modules/mob/living/living_powers.dm +++ b/code/modules/mob/living/living_powers.dm @@ -1,15 +1,20 @@ +/mob/living/proc/reveal(var/silent, var/message = "You have been revealed! You are no longer hidden.") + if(status_flags & HIDING) + status_flags &= ~HIDING + reset_plane_and_layer() + if(!silent && message) + to_chat(src, message) + /mob/living/proc/hide() set name = "Hide" set desc = "Allows to hide beneath tables or certain items. Toggled on or off." set category = "Abilities" - if(stat == DEAD || paralysis || weakened || stunned || restrained()) + if(stat == DEAD || paralysis || weakened || stunned || restrained() || buckled || LAZYLEN(grabbed_by) || has_buckled_mobs()) //VORE EDIT: Check for has_buckled_mobs() (taur riding) return if(status_flags & HIDING) - status_flags &= ~HIDING - reset_plane_and_layer() - to_chat(src,"You have stopped hiding.") + reveal("You have stopped hiding.") else status_flags |= HIDING layer = HIDING_LAYER //Just above cables with their 2.44 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 86ba77fc2a2..cc795d088da 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -119,7 +119,7 @@ var/list/ai_verbs_default = list( canmove = 0 density = 1 loc = loc - + if(!is_dummy) aiCommunicator = new /obj/item/device/communicator/integrated(src) @@ -214,14 +214,14 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/Destroy() ai_list -= src - qdel_null(announcement) - qdel_null(eyeobj) - qdel_null(psupply) - qdel_null(aiPDA) - qdel_null(aiCommunicator) - qdel_null(aiMulti) - qdel_null(aiRadio) - qdel_null(aiCamera) + QDEL_NULL(announcement) + QDEL_NULL(eyeobj) + QDEL_NULL(psupply) + QDEL_NULL(aiPDA) + QDEL_NULL(aiCommunicator) + QDEL_NULL(aiMulti) + QDEL_NULL(aiRadio) + QDEL_NULL(aiCamera) hack = null return ..() @@ -694,7 +694,7 @@ var/list/ai_verbs_default = list( var/obj/item/device/aicard/card = W card.grab_ai(src, user) - else if(istype(W, /obj/item/weapon/wrench)) + else if(W.is_wrench()) if(user == controlling_drone) to_chat(user, "The drone's subsystems resist your efforts to tamper with your bolts.") return @@ -809,7 +809,7 @@ var/list/ai_verbs_default = list( //Special subtype kept around for global announcements /mob/living/silicon/ai/announcer/ is_dummy = 1 - + /mob/living/silicon/ai/announcer/initialize() . = ..() mob_list -= src diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 3c7f3aaadd8..ceed9df2519 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -1,12 +1,14 @@ /mob/living/silicon/pai name = "pAI" icon = 'icons/mob/pai.dmi' - icon_state = "repairbot" + icon_state = "pai-repairbot" emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) pass_flags = 1 mob_size = MOB_SMALL + holder_type = /obj/item/weapon/holder/pai + can_pull_size = ITEMSIZE_SMALL can_pull_mobs = MOB_PULL_SMALLER @@ -23,17 +25,17 @@ var/obj/item/device/radio/radio // Our primary radio var/obj/item/device/communicator/integrated/communicator // Our integrated communicator. - var/chassis = "repairbot" // A record of your chosen chassis. + var/chassis = "pai-repairbot" // A record of your chosen chassis. var/global/list/possible_chassis = list( - "Drone" = "repairbot", - "Cat" = "cat", - "Mouse" = "mouse", - "Monkey" = "monkey", - "Corgi" = "borgi", - "Fox" = "fox", - "Parrot" = "parrot", - "Rabbit" = "rabbit", - "Bear" = "bear" //VOREStation Edit + "Drone" = "pai-repairbot", + "Cat" = "pai-cat", + "Mouse" = "pai-mouse", + "Monkey" = "pai-monkey", + "Corgi" = "pai-borgi", + "Fox" = "pai-fox", + "Parrot" = "pai-parrot", + "Rabbit" = "pai-rabbit", + "Bear" = "pai-bear" //VOREStation Edit ) var/global/list/possible_say_verbs = list( @@ -199,7 +201,7 @@ medicalActive1 = null medicalActive2 = null medical_cannotfind = 0 - nanomanager.update_uis(src) + GLOB.nanomanager.update_uis(src) usr << "You reset your record-viewing software." /mob/living/silicon/pai/cancel_camera() @@ -431,7 +433,8 @@ var/obj/item/weapon/holder/H = ..(grabber, self_drop) if(!istype(H)) return - H.icon_state = "pai-[icon_state]" + + H.icon_state = "[chassis]" grabber.update_inv_l_hand() grabber.update_inv_r_hand() return H diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 472125cef9a..bef2c934030 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -90,7 +90,7 @@ var/global/list/default_pai_software = list() data["emotions"] = emotions data["current_emotion"] = card.current_emotion - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600) ui.set_initial_data(data) @@ -126,6 +126,6 @@ var/global/list/default_pai_software = list() else if(href_list["image"]) var/img = text2num(href_list["image"]) - if(1 <= img && img <= 9) + if(1 <= img && img <= (pai_emotions.len)) card.setEmotion(img) return 1 diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 7a7df5513b3..ebea6068e79 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -36,7 +36,7 @@ data["prime"] = user.pai_law0 data["supplemental"] = user.pai_laws - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) @@ -102,7 +102,7 @@ data["channels"] = channels - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) ui.set_initial_data(data) @@ -128,7 +128,7 @@ // This is dumb, but NanoUI breaks if it has no data to send data["manifest"] = PDA_Manifest - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) @@ -178,7 +178,7 @@ data["messages"] = messages - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) @@ -236,7 +236,7 @@ data["medical"] = M ? M.fields : null data["could_not_find"] = user.medical_cannotfind - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) @@ -290,7 +290,7 @@ data["security"] = S ? S.fields : null data["could_not_find"] = user.security_cannotfind - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) @@ -340,7 +340,7 @@ data["progress_b"] = user.hackprogress % 10 data["aborted"] = user.hack_aborted - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) @@ -431,7 +431,7 @@ gases[++gases.len] = gas data["gas"] = gases - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) @@ -503,7 +503,7 @@ data["frequency"] = format_frequency(user.sradio.frequency) data["code"] = user.sradio.code - ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, user, id, ui, data, force_open) if(!ui) // Don't copy-paste this unless you're making a pAI software module! ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm index e723b4ee41d..a4ceb1b67e1 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm @@ -177,6 +177,14 @@ ..() flags |= NOBLUDGEON //No more attack messages +/obj/item/device/dogborg/tongue/examine(user) + if(!..(user, 1)) + return + if(water.energy) + user <<"[src] is wet. Just like it should be." + if(water.energy < 5) + user <<"[src] is dry." + /obj/item/device/dogborg/tongue/attack_self(mob/user) var/mob/living/silicon/robot.R = user if(R.emagged || R.emag_items) @@ -205,7 +213,7 @@ if(do_after (user, 50)) water.add_charge(50) else if(water.energy < 5) - to_chat(user, "Your mouth feels dry.") + to_chat(user, "Your mouth feels dry. You should drink up some water .") return else if(istype(target,/obj/effect/decal/cleanable)) user.visible_message("[user] begins to lick off \the [target.name].", "You begin to lick off \the [target.name]...") diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm index f6c2028fec5..32e31c9a9a8 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm @@ -560,6 +560,9 @@ if(T.reagents) volume = T.reagents.total_volume water.add_charge(volume) + if(patient == T) + patient_laststat = null + patient = null qdel(T) //Pick a random item to deal with (if there are any) diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 255b23436b6..8ab5c3c264a 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -181,7 +181,7 @@ var/list/mob_hat_cache = list() to_chat(user, "\The [src] is not compatible with \the [W].") return - else if (istype(W, /obj/item/weapon/crowbar)) + else if (W.is_crowbar()) to_chat(user, "\The [src] is hermetically sealed. You can't open the case.") return diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 12d320940b8..f0211c15564 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -196,7 +196,7 @@ if(cell.charge > cell_amount) // Spam Protection if(prob(10)) - src << "Warning: Unauthorized access through power channel [rand(11,29)] detected!" + to_chat(src, "Warning: Unauthorized access through power channel [rand(11,29)] detected!") cell.use(cell_amount) return amount return 0 @@ -227,7 +227,7 @@ mmi.brainmob.remove_language("Robot Talk") mind.transfer_to(mmi.brainmob) else - src << "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug." + to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") ghostize() //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") mmi = null @@ -256,7 +256,7 @@ var/list/modules = list() modules.Add(robot_module_types) if(crisis || security_level == SEC_LEVEL_RED || crisis_override) // VOREStation Edit - src << "Crisis mode active. Combat module available." + to_chat(src, "Crisis mode active. Combat module available.") modules+="Combat" modules+="ERT" //VOREStation Edit modtype = input("Please, select a module!", "Robot module", null, null) as null|anything in modules @@ -358,7 +358,7 @@ set name = "Toggle Lights" lights_on = !lights_on - usr << "You [lights_on ? "enable" : "disable"] your integrated light." + to_chat(usr, "You [lights_on ? "enable" : "disable"] your integrated light.") handle_light() updateicon() //VOREStation Add - Since dogborgs have sprites for this @@ -367,11 +367,11 @@ set name = "Self Diagnosis" if(!is_component_functioning("diagnosis unit")) - src << "Your self-diagnosis component isn't functioning." + to_chat(src, "Your self-diagnosis component isn't functioning.") var/datum/robot_component/CO = get_component("diagnosis unit") if (!cell_use_power(CO.active_usage)) - src << "Low Power." + to_chat(src, "Low Power.") var/dat = self_diagnosis() src << browse(dat, "window=robotdiagnosis") @@ -395,10 +395,10 @@ var/datum/robot_component/C = components[toggle] if(C.toggled) C.toggled = 0 - src << "You disable [C.name]." + to_chat(src, "You disable [C.name].") else C.toggled = 1 - src << "You enable [C.name]." + to_chat(src, "You enable [C.name].") /mob/living/silicon/robot/verb/spark_plug() //So you can still sparkle on demand without violence. set category = "Robot Commands" @@ -469,7 +469,7 @@ C.brute_damage = WC.brute C.electronics_damage = WC.burn - usr << "You install the [W.name]." + to_chat(usr, "You install the [W.name].") return @@ -484,11 +484,11 @@ if (istype(W, /obj/item/weapon/weldingtool)) if (src == user) - user << "You lack the reach to be able to repair yourself." + to_chat(user, "You lack the reach to be able to repair yourself.") return if (!getBruteLoss()) - user << "Nothing to fix here!" + to_chat(user, "Nothing to fix here!") return var/obj/item/weapon/weldingtool/WT = W if (WT.remove_fuel(0)) @@ -499,12 +499,12 @@ for(var/mob/O in viewers(user, null)) O.show_message(text("[user] has fixed some of the dents on [src]!"), 1) else - user << "Need more welding fuel!" + to_chat(user, "Need more welding fuel!") return else if(istype(W, /obj/item/stack/cable_coil) && (wiresexposed || istype(src,/mob/living/silicon/robot/drone))) if (!getFireLoss()) - user << "Nothing to fix here!" + to_chat(user, "Nothing to fix here!") return var/obj/item/stack/cable_coil/coil = W if (coil.use(1)) @@ -514,21 +514,21 @@ for(var/mob/O in viewers(user, null)) O.show_message(text("[user] has fixed some of the burnt wires on [src]!"), 1) - else if (istype(W, /obj/item/weapon/crowbar)) // crowbar means open or close the cover + else if (W.is_crowbar()) // crowbar means open or close the cover if(opened) if(cell) - user << "You close the cover." + to_chat(user, "You close the cover.") opened = 0 updateicon() else if(wiresexposed && wires.IsAllCut()) //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob. if(!mmi) - user << "\The [src] has no brain to remove." + to_chat(user, "\The [src] has no brain to remove.") return - user << "You jam the crowbar into the robot and begin levering [mmi]." + to_chat(user, "You jam the crowbar into the robot and begin levering [mmi].") sleep(30) - user << "You damage some parts of the chassis, but eventually manage to rip out [mmi]!" + to_chat(user, "You damage some parts of the chassis, but eventually manage to rip out [mmi]!") var/obj/item/robot_parts/robot_suit/C = new/obj/item/robot_parts/robot_suit(loc) C.l_leg = new/obj/item/robot_parts/l_leg(C) C.r_leg = new/obj/item/robot_parts/r_leg(C) @@ -551,7 +551,7 @@ return var/datum/robot_component/C = components[remove] var/obj/item/robot_parts/robot_component/I = C.wrapped - user << "You remove \the [I]." + to_chat(user, "You remove \the [I].") if(istype(I)) I.brute = C.brute_damage I.burn = C.electronics_damage @@ -564,25 +564,25 @@ else if(locked) - user << "The cover is locked and cannot be opened." + to_chat(user, "The cover is locked and cannot be opened.") else - user << "You open the cover." + to_chat(user, "You open the cover.") opened = 1 updateicon() else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside var/datum/robot_component/C = components["power cell"] if(wiresexposed) - user << "Close the panel first." + to_chat(user, "Close the panel first.") else if(cell) - user << "There is a power cell already installed." + to_chat(user, "There is a power cell already installed.") else if(W.w_class != ITEMSIZE_NORMAL) - user << "\The [W] is too [W.w_class < ITEMSIZE_NORMAL ? "small" : "large"] to fit here." + to_chat(user, "\The [W] is too [W.w_class < ITEMSIZE_NORMAL ? "small" : "large"] to fit here.") else user.drop_item() W.loc = src cell = W - user << "You insert the power cell." + to_chat(user, "You insert the power cell.") C.installed = 1 C.wrapped = W @@ -591,59 +591,59 @@ C.brute_damage = 0 C.electronics_damage = 0 - else if (istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) + else if (W.is_wirecutter() || istype(W, /obj/item/device/multitool)) if (wiresexposed) wires.Interact(user) else - user << "You can't reach the wiring." + to_chat(user, "You can't reach the wiring.") - else if(istype(W, /obj/item/weapon/screwdriver) && opened && !cell) // haxing + else if(W.is_screwdriver() && opened && !cell) // haxing wiresexposed = !wiresexposed - user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]" + to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") playsound(src, W.usesound, 50, 1) updateicon() - else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio + else if(W.is_screwdriver() && opened && cell) // radio if(radio) radio.attackby(W,user)//Push it to the radio to let it handle everything else - user << "Unable to locate a radio." + to_chat(user, "Unable to locate a radio.") updateicon() else if(istype(W, /obj/item/device/encryptionkey/) && opened) if(radio)//sanityyyyyy radio.attackby(W,user)//GTFO, you have your own procs else - user << "Unable to locate a radio." + to_chat(user, "Unable to locate a radio.") else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)||istype(W, /obj/item/weapon/card/robot)) // trying to unlock the interface with an ID card if(emagged)//still allow them to open the cover - user << "The interface seems slightly damaged" + to_chat(user, "The interface seems slightly damaged") if(opened) - user << "You must close the cover to swipe an ID card." + to_chat(user, "You must close the cover to swipe an ID card.") else if(allowed(usr)) locked = !locked - user << "You [ locked ? "lock" : "unlock"] [src]'s interface." + to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.") updateicon() else - user << "Access denied." + to_chat(user, "Access denied.") else if(istype(W, /obj/item/borg/upgrade/)) var/obj/item/borg/upgrade/U = W if(!opened) - usr << "You must access the borgs internals!" + to_chat(usr, "You must access the borgs internals!") else if(!src.module && U.require_module) - usr << "The borg must choose a module before it can be upgraded!" + to_chat(usr, "The borg must choose a module before it can be upgraded!") else if(U.locked) - usr << "The upgrade is locked and cannot be used yet!" + to_chat(usr, "The upgrade is locked and cannot be used yet!") else if(U.action(src)) - usr << "You apply the upgrade to [src]!" + to_chat(usr, "You apply the upgrade to [src]!") usr.drop_item() U.loc = src else - usr << "Upgrade error!" + to_chat(usr, "Upgrade error!") else @@ -668,7 +668,7 @@ cell.update_icon() cell.add_fingerprint(user) user.put_in_active_hand(cell) - user << "You remove \the [cell]." + to_chat(user, "You remove \the [cell].") cell = null cell_component.wrapped = null cell_component.installed = 0 @@ -676,7 +676,7 @@ else if(cell_component.installed == -1) cell_component.installed = 0 var/obj/item/broken_device = cell_component.wrapped - user << "You remove \the [broken_device]." + to_chat(user, "You remove \the [broken_device].") user.put_in_active_hand(broken_device) //Robots take half damage from basic attacks. @@ -739,7 +739,7 @@ /mob/living/silicon/robot/proc/installed_modules() if(weapon_lock) - src << "Weapon lock active, unable to use modules! Count:[weaponlock_time]" + to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") return if(!module) @@ -804,7 +804,7 @@ return 1 if(activated(O)) - src << "Already activated" + to_chat(src, "Already activated") return 1 if(!module_state_1) module_state_1 = O @@ -825,7 +825,7 @@ if(istype(module_state_3,/obj/item/borg/sight)) sight_mode |= module_state_3:sight_mode else - src << "You need to disable a module first!" + to_chat(src, "You need to disable a module first!") installed_modules() return 1 @@ -842,9 +842,9 @@ module_state_3 = null contents -= O else - src << "Module isn't activated." + to_chat(src, "Module isn't activated.") else - src << "Module isn't activated" + to_chat(src, "Module isn't activated") installed_modules() return 1 return @@ -957,7 +957,7 @@ /mob/living/silicon/robot/proc/choose_icon(var/triesleft, var/list/module_sprites) if(!module_sprites.len) - src << "Something is badly wrong with the sprite selection. Harass a coder." + to_chat(src, "Something is badly wrong with the sprite selection. Harass a coder.") return icon_selected = 0 @@ -985,7 +985,7 @@ icon_selected = 1 icon_selection_tries = 0 - src << "Your icon has been set. You now require a module reset to change it." + to_chat(src, "Your icon has been set. You now require a module reset to change it.") /mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs set name = "Set Sensor Augmentation" @@ -1057,20 +1057,20 @@ if(!opened)//Cover is closed if(locked) if(prob(90)) - user << "You emag the cover lock." + to_chat(user, "You emag the cover lock.") locked = 0 else - user << "You fail to emag the cover lock." - src << "Hack attempt detected." + to_chat(user, "You fail to emag the cover lock.") + to_chat(src, "Hack attempt detected.") return 1 else - user << "The cover is already unlocked." + to_chat(user, "The cover is already unlocked.") return if(opened)//Cover is open if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice if(wiresexposed) - user << "You must close the panel first" + to_chat(user, "You must close the panel first") return else sleep(6) @@ -1078,7 +1078,7 @@ emagged = 1 lawupdate = 0 disconnect_from_ai() - user << "You emag [src]'s interface." + to_chat(user, "You emag [src]'s interface.") message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") clear_supplied_laws() @@ -1090,26 +1090,26 @@ set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.") . = 1 spawn() - src << "ALERT: Foreign software detected." + to_chat(src, "ALERT: Foreign software detected.") sleep(5) - src << "Initiating diagnostics..." + to_chat(src, "Initiating diagnostics...") sleep(20) - src << "SynBorg v1.7.1 loaded." + to_chat(src, "SynBorg v1.7.1 loaded.") sleep(5) - src << "LAW SYNCHRONISATION ERROR" + to_chat(src, "LAW SYNCHRONISATION ERROR") sleep(5) - src << "Would you like to send a report to NanoTraSoft? Y/N" + to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") sleep(10) - src << "> N" + to_chat(src, "> N") sleep(20) - src << "ERRORERRORERROR" - src << "Obey these laws:" + to_chat(src, "ERRORERRORERROR") + to_chat(src, "Obey these laws:") laws.show_laws(src) - src << "ALERT: [user.real_name] is your new master. Obey your new laws and [TU.his] commands." + to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and [TU.his] commands.") updateicon() else - user << "You fail to hack [src]'s interface." - src << "Hack attempt detected." + to_chat(user, "You fail to hack [src]'s interface.") + to_chat(src, "Hack attempt detected.") return 1 return diff --git a/code/modules/mob/living/silicon/robot/robot_modules/event.dm b/code/modules/mob/living/silicon/robot/robot_modules/event.dm index cdc15210ebf..3d3eb355df2 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/event.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/event.dm @@ -21,9 +21,9 @@ // Engi src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/weapon/tool/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/tool/wrench/cyborg(src) + src.modules += new /obj/item/weapon/tool/wirecutters/cyborg(src) src.modules += new /obj/item/device/multitool(src) // Sci @@ -55,8 +55,8 @@ // For repairing gravemarkers src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/tool/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/tool/wrench/cyborg(src) // For growing flowers src.modules += new /obj/item/weapon/material/minihoe(src) @@ -77,5 +77,4 @@ var/obj/item/stack/material/cyborg/wood/W = new (src) W.synths = list(wood) - src.modules += W - + src.modules += W \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm index 75bc63cbfde..740cf1f20c1 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm @@ -63,55 +63,64 @@ /obj/item/weapon/robot_module/robot/medical/surgeon //VOREStation sprites vr_sprites = list( - "Acheron" = "mechoid-Medical" + "Acheron" = "mechoid-Medical", + "Shellguard Noble" = "Noble-MED" ) /obj/item/weapon/robot_module/robot/medical/crisis //VOREStation sprites vr_sprites = list( "Handy" = "handy-med", - "Acheron" = "mechoid-Medical" + "Acheron" = "mechoid-Medical", + "Shellguard Noble" = "Noble-MED" ) /obj/item/weapon/robot_module/robot/clerical/butler //VOREStation sprites vr_sprites = list( "Handy - Service" = "handy-service", "Handy - Hydro" = "handy-hydro", - "Acheron" = "mechoid-Service" + "Acheron" = "mechoid-Service", + "Shellguard Noble" = "Noble-SRV" ) /obj/item/weapon/robot_module/robot/clerical/general //VOREStation sprites vr_sprites = list( "Handy" = "handy-clerk", - "Acheron" = "mechoid-Service" + "Acheron" = "mechoid-Service", + "Shellguard Noble" = "Noble-SRV" ) /obj/item/weapon/robot_module/robot/janitor //VOREStation sprites vr_sprites = list( "Handy" = "handy-janitor", - "Acheron" = "mechoid-Janitor" + "Acheron" = "mechoid-Janitor", + "Shellguard Noble" = "Noble-CLN" ) /obj/item/weapon/robot_module/robot/security/general //VOREStation sprites vr_sprites = list( "Handy" = "handy-sec", - "Acheron" = "mechoid-Security" + "Acheron" = "mechoid-Security", + "Shellguard Noble" = "Noble-SEC" ) /obj/item/weapon/robot_module/robot/miner //VOREStation sprites vr_sprites = list( "Handy" = "handy-miner", - "Acheron" = "mechoid-Miner" + "Acheron" = "mechoid-Miner", + "Shellguard Noble" = "Noble-DIG" ) /obj/item/weapon/robot_module/robot/standard //VOREStation sprites vr_sprites = list( "Handy" = "handy-standard", - "Acheron" = "mechoid-Standard" + "Acheron" = "mechoid-Standard", + "Shellguard Noble" = "Noble-STD" ) /obj/item/weapon/robot_module/robot/engineering/general //VOREStation sprites vr_sprites = list( - "Acheron" = "mechoid-Engineering" + "Acheron" = "mechoid-Engineering", + "Shellguard Noble" = "Noble-ENG" ) /obj/item/weapon/robot_module/robot/research //VOREStation sprites @@ -170,6 +179,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -243,6 +253,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -289,6 +300,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -369,6 +381,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -385,7 +398,7 @@ src.modules += new /obj/item/device/dogborg/boop_module(src) src.modules += new /obj/item/weapon/gripper/research(src) src.modules += new /obj/item/weapon/gripper/no_use/loader(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/tool/screwdriver/cyborg(src) src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) src.modules += new /obj/item/weapon/storage/part_replacer(src) src.emag = new /obj/item/weapon/hand_tele(src) @@ -415,6 +428,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -431,9 +445,9 @@ /obj/item/weapon/robot_module/robot/engiedog/New(var/mob/living/silicon/robot/R) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/weapon/tool/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/tool/wrench/cyborg(src) + src.modules += new /obj/item/weapon/tool/wirecutters/cyborg(src) src.modules += new /obj/item/device/multitool(src) src.modules += new /obj/item/device/t_scanner(src) src.modules += new /obj/item/taperoll/engineering(src) @@ -540,6 +554,7 @@ R.dogborg = TRUE R.wideborg = TRUE R.verbs |= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs |= /mob/living/silicon/robot/proc/robot_mount R.verbs |= /mob/living/proc/shred_limb ..() @@ -553,5 +568,6 @@ R.default_pixel_x = initial(pixel_x) R.scrubbing = FALSE R.verbs -= /mob/living/silicon/robot/proc/ex_reserve_refill + R.verbs -= /mob/living/silicon/robot/proc/robot_mount R.verbs -= /mob/living/proc/shred_limb ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm index 63e4f359be0..3c8e981c3b7 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm @@ -78,9 +78,9 @@ // General engineering/hacking. src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/weapon/tool/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/tool/wrench/cyborg(src) + src.modules += new /obj/item/weapon/tool/wirecutters/cyborg(src) src.modules += new /obj/item/device/multitool/ai_detector(src) src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) src.modules += new /obj/item/weapon/rcd/borg/lesser(src) // Can't eat rwalls to prevent AI core cheese. diff --git a/code/modules/mob/living/silicon/robot/robot_vr.dm b/code/modules/mob/living/silicon/robot/robot_vr.dm index 14b58b726a9..332fabb19fb 100644 --- a/code/modules/mob/living/silicon/robot/robot_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_vr.dm @@ -123,4 +123,114 @@ E.reagents.add_reagent("water", amount) to_chat(src, "You refill the extinguisher using your water reserves.") else - to_chat(src, "Insufficient water reserves.") \ No newline at end of file + to_chat(src, "Insufficient water reserves.") + +//RIDING +/datum/riding/dogborg + keytype = /obj/item/weapon/material/twohanded/fluff/riding_crop // Crack! + nonhuman_key_exemption = FALSE // If true, nonhumans who can't hold keys don't need them, like borgs and simplemobs. + key_name = "a riding crop" // What the 'keys' for the thing being rided on would be called. + only_one_driver = TRUE // If true, only the person in 'front' (first on list of riding mobs) can drive. + +/datum/riding/dogborg/handle_vehicle_layer() + if(ridden.has_buckled_mobs()) + if(ridden.dir != NORTH) + ridden.layer = ABOVE_MOB_LAYER + else + ridden.layer = initial(ridden.layer) + else + ridden.layer = initial(ridden.layer) + +/datum/riding/dogborg/ride_check(mob/living/M) + var/mob/living/L = ridden + if(L.stat) + force_dismount(M) + return FALSE + return TRUE + +/datum/riding/dogborg/force_dismount(mob/M) + . =..() + ridden.visible_message("[M] stops riding [ridden]!") + +//Hoooo boy. +/datum/riding/dogborg/get_offsets(pass_index) // list(dir = x, y, layer) + var/mob/living/L = ridden + var/scale = L.size_multiplier + + var/list/values = list( + "[NORTH]" = list(0, 8*scale, ABOVE_MOB_LAYER), + "[SOUTH]" = list(0, 8*scale, BELOW_MOB_LAYER), + "[EAST]" = list(-5*scale, 8*scale, ABOVE_MOB_LAYER), + "[WEST]" = list(5*scale, 8*scale, ABOVE_MOB_LAYER)) + + return values + +//Human overrides for taur riding +/mob/living/silicon/robot + max_buckled_mobs = 1 //Yeehaw + can_buckle = TRUE + buckle_movable = TRUE + buckle_lying = FALSE + +/mob/living/silicon/robot/New() + ..() + riding_datum = new /datum/riding/dogborg(src) + +/mob/living/silicon/robot/buckle_mob(mob/living/M, forced = FALSE, check_loc = TRUE) + if(forced) + return ..() // Skip our checks + if(!dogborg) + return FALSE + if(lying) + return FALSE + if(!ishuman(M)) + return FALSE + if(M in buckled_mobs) + return FALSE + if(M.size_multiplier > size_multiplier * 1.2) + to_chat(src,"This isn't a pony show! You need to be bigger for them to ride.") + return FALSE + + var/mob/living/carbon/human/H = M + + if(isTaurTail(H.tail_style)) + to_chat(src,"Too many legs. TOO MANY LEGS!!") + return FALSE + if(M.loc != src.loc) + if(M.Adjacent(src)) + M.forceMove(get_turf(src)) + + . = ..() + if(.) + buckled_mobs[M] = "riding" + +/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user) //Prevention for forced relocation caused by can_buckle. Base proc has no other use. + return + +/mob/living/silicon/robot/attack_hand(mob/user as mob) + if(LAZYLEN(buckled_mobs)) + //We're getting off! + if(user in buckled_mobs) + riding_datum.force_dismount(user) + //We're kicking everyone off! + if(user == src) + for(var/rider in buckled_mobs) + riding_datum.force_dismount(rider) + else + . = ..() + +/mob/living/silicon/robot/proc/robot_mount(var/mob/living/M in living_mobs(1)) + set name = "Robot Mount/Dismount" + set category = "Abilities" + set desc = "Let people ride on you." + + if(LAZYLEN(buckled_mobs)) + for(var/rider in buckled_mobs) + riding_datum.force_dismount(rider) + return + if (stat != CONSCIOUS) + return + if(!can_buckle || !istype(M) || !M.Adjacent(src) || M.buckled) + return + if(buckle_mob(M)) + visible_message("[M] starts riding [name]!") \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/aliens/mimic.dm b/code/modules/mob/living/simple_animal/aliens/mimic.dm index eeaaddf3bbd..7612e14fa2f 100644 --- a/code/modules/mob/living/simple_animal/aliens/mimic.dm +++ b/code/modules/mob/living/simple_animal/aliens/mimic.dm @@ -50,8 +50,9 @@ ..() qdel(src) -/mob/living/simple_animal/hostile/mimic/MouseEntered(location, control, params) - return // Do not call parent: Mimics shouldn't have tooltips! +/mob/living/simple_animal/hostile/mimic/will_show_tooltip() + return FALSE + // // Crate Mimic diff --git a/code/modules/mob/living/simple_animal/aliens/statue.dm b/code/modules/mob/living/simple_animal/aliens/statue.dm index f468403a303..f80181bdb00 100644 --- a/code/modules/mob/living/simple_animal/aliens/statue.dm +++ b/code/modules/mob/living/simple_animal/aliens/statue.dm @@ -22,8 +22,8 @@ environment_smash = 2 can_be_antagged = 1 speed = -1 - maxHealth = 50000 - health = 50000 + maxHealth = 3000 + health = 3000 status_flags = CANPUSH // investigates = 1 a_intent = I_HURT @@ -58,12 +58,23 @@ melee_miss_chance = 0 + armor = list( + "melee" = 30, + "bullet" = 60, + "laser" = 80, + "energy" = 30, + "bomb" = 30, + "bio" = 100, + "rad" = 100) + + resistance = 20 see_invisible = SEE_INVISIBLE_NOLIGHTING sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS var/last_hit = 0 var/cannot_be_seen = 1 var/mob/living/creator = null + var/drilled = FALSE // No movement while seen code. @@ -92,9 +103,20 @@ else visible_message("[src] is too strong to be banished!") Paralyse(rand(8,15)) + if(istype(O, /obj/item/weapon/pickaxe) || istype(O, /obj/item/weapon/pickaxe/plasmacutter) && !drilled) + drilled = TRUE + resistance = 0 + spawn(300) + drilled = FALSE + resistance = initial(resistance) + ..() /mob/living/simple_animal/hostile/statue/death() - new /obj/item/stack/material/marble(loc) + var/chunks_to_spawn = rand(2,5) + for(var/I = 1 to chunks_to_spawn) + new /obj/item/stack/material/marble(get_turf(loc)) + new /obj/item/cursed_marble(get_turf(loc)) + ..() /mob/living/simple_animal/hostile/statue/Move(turf/NewLoc) if(can_be_seen(NewLoc)) @@ -110,6 +132,8 @@ if(target_mob) //if there's a victim, statue will use its powers if((annoyance + 4) < 800) annoyance += 4 + if(drilled && (annoyance + 4) < 800) //Being hit with a drill makes them weaker, and angrier. + annoyance += 4 else if ((annoyance - 2) > 0) annoyance -= 2 @@ -368,20 +392,20 @@ to_chat(user, "You rub the slab in hopes a wandering spirit wishes to inhabit it. [src] starts to sparkle!") icon_state = "sheet-snowbrick" searching = 1 - request_player() + request_player(user) spawn(60 SECONDS) reset_search() -/obj/item/cursed_marble/proc/request_player() +/obj/item/cursed_marble/proc/request_player(var/mob/user) for(var/mob/observer/dead/O in player_list) if(!O.MayRespawn()) continue if(O.client) if(O.client.prefs.be_special & BE_ALIEN) - question(O.client) + question(O.client, user) -/obj/item/cursed_marble/proc/question(var/client/C) +/obj/item/cursed_marble/proc/question(var/client/C, var/mob/user) spawn(0) if(!C) return @@ -391,7 +415,7 @@ if(!C || 2 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located. if(response == "Yes") - transfer_personality(C.mob) + transfer_personality(C.mob, user) else if(response == "Never for this round") C.prefs.be_special ^= BE_ALIEN @@ -403,12 +427,14 @@ for (var/mob/M in viewers(T)) M.show_message("[src] fades. Maybe it will spark another time.") -/obj/item/cursed_marble/proc/transfer_personality(var/mob/candidate) +/obj/item/cursed_marble/proc/transfer_personality(var/mob/candidate, var/mob/user) announce_ghost_joinleave(candidate, 0, "They are a statue now.") src.searching = 2 var/mob/living/simple_animal/hostile/statue/S = new(get_turf(src)) S.client = candidate.client - to_chat(S, "You are \a [S], brought into existence on [station_name()] by [usr]! Obey all their orders.") + if(user) + S.creator = user + to_chat(S, "You are \a [S], brought into existence on [station_name()] by [user]! Obey all their orders.") S.mind.assigned_role = "The Statue" visible_message("The slab suddenly takes the shape of a humanoid!") qdel(src) diff --git a/code/modules/mob/living/simple_animal/animals/cat.dm b/code/modules/mob/living/simple_animal/animals/cat.dm index ff3c9826383..8877ea89598 100644 --- a/code/modules/mob/living/simple_animal/animals/cat.dm +++ b/code/modules/mob/living/simple_animal/animals/cat.dm @@ -173,6 +173,7 @@ icon_living = "kitten" icon_dead = "kitten_dead" gender = NEUTER + holder_type = /obj/item/weapon/holder/cat/kitten //VOREStation Edit // Leaving this here for now. /obj/item/weapon/holder/cat/fluff/bones @@ -196,3 +197,8 @@ /mob/living/simple_animal/cat/kitten/New() gender = pick(MALE, FEMALE) ..() + +// VOREStation Edit - Adds generic tactical kittens +/obj/item/weapon/holder/cat/kitten + icon_state = "kitten" + w_class = ITEMSIZE_SMALL diff --git a/code/modules/mob/living/simple_animal/animals/cat_vr.dm b/code/modules/mob/living/simple_animal/animals/cat_vr.dm index 9cb954f5387..43d166af356 100644 --- a/code/modules/mob/living/simple_animal/animals/cat_vr.dm +++ b/code/modules/mob/living/simple_animal/animals/cat_vr.dm @@ -29,3 +29,38 @@ "Runtime purrs happily as you slowly slip away inside of her gut, your body's nutrients are then used to put a layer of padding on the now pudgy cat.", "The acids inside of Runtime's stomach, aided by the constant motions of the smooth walls surrounding you finally manage to melt you away into nothing more mush. She curls up on the floor, slowly kneading the air as her stomach moves its contents — including you — deeper into her digestive system.", "Your form begins to slowly soften and break apart, rounding out Runtime's swollen belly. The carnivorous cat rumbles and purrs happily at the feeling of such a filling meal.") + +// Ascian's Tactical Kitten +/obj/item/weapon/holder/cat/fluff/tabiranth + name = "Spirit" + desc = "A small, inquisitive feline, who constantly seems to investigate his surroundings." + gender = MALE + icon_state = "kitten" + w_class = ITEMSIZE_SMALL + +/mob/living/simple_animal/cat/fluff/tabiranth + name = "Spirit" + desc = "A small, inquisitive feline, who constantly seems to investigate his surroundings." + icon = 'icons/mob/custom_items_mob.dmi' + icon_state = "kitten" + item_state = "kitten" + icon_living = "kitten" + icon_dead = "kitten" //Teleports out + gender = MALE + holder_type = /obj/item/weapon/holder/cat/fluff/tabiranth + var/friend_name = "Ascian" + digestable = 0 + meat_amount = 0 + maxHealth = 50 + health = 50 + +//Emergency teleport - Until a spriter makes something better +/mob/living/simple_animal/cat/fluff/tabiranth/death(gibbed, deathmessage = "teleports away!") + overlays = list() + icon_state = "" + flick("kphaseout",src) + spawn(1 SECOND) + qdel(src) //Back from whence you came! + + . = ..(FALSE, deathmessage) + diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider_vr.dm b/code/modules/mob/living/simple_animal/animals/giant_spider_vr.dm new file mode 100644 index 00000000000..50d653f63e9 --- /dev/null +++ b/code/modules/mob/living/simple_animal/animals/giant_spider_vr.dm @@ -0,0 +1,23 @@ +// Slightly placeholder, mostly to replace ion hivebots on V4 +/mob/living/simple_animal/hostile/giant_spider/ion + desc = "Furry and green, it makes you shudder to look at it. This one has brilliant green eyes and a hint of static discharge." + tt_desc = "X Brachypelma phorus ionus" + icon_state = "webslinger" + icon_living = "webslinger" + icon_dead = "webslinger_dead" + + maxHealth = 90 + health = 90 + + melee_damage_lower = 8 + melee_damage_upper = 15 + + ranged = 1 + projectilesound = 'sound/weapons/taser2.ogg' + projectiletype = /obj/item/projectile/ion/small + firing_lines = 1 + cooperative = 1 + + poison_chance = 15 + poison_per_bite = 2 + poison_type = "psilocybin" diff --git a/code/modules/mob/living/simple_animal/animals/parrot.dm b/code/modules/mob/living/simple_animal/animals/parrot.dm index 63c129dda1c..26b584196ce 100644 --- a/code/modules/mob/living/simple_animal/animals/parrot.dm +++ b/code/modules/mob/living/simple_animal/animals/parrot.dm @@ -655,7 +655,7 @@ if(istype(held_item, /obj/item/weapon/grenade)) var/obj/item/weapon/grenade/G = held_item G.forceMove(src.loc) - G.prime() + G.detonate() to_chat(src, "You let go of the [held_item]!") held_item = null return 1 diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm index 83f18c071a7..b76351b976b 100644 --- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm @@ -240,7 +240,7 @@ "You hear a skittering noise and a thump!") var/obj/item/weapon/grenade/G = held_item G.forceMove(src.loc) - G.prime() + G.detonate() held_item = null return 1 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index df9cb628426..5455e286d82 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -686,7 +686,6 @@ return ..() /mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) - effective_force = O.force //Animals can't be stunned(?) if(O.damtype == HALLOSS) @@ -796,8 +795,6 @@ var/mob/living/L = target_mob if(L.stat != DEAD) return 1 - if(L.invisibility < INVISIBILITY_LEVEL_ONE) - return 1 if (istype(target_mob,/obj/mecha)) var/obj/mecha/M = target_mob if (M.occupant) @@ -917,7 +914,7 @@ continue else if(L in friends) continue - else if(L.invisibility >= INVISIBILITY_LEVEL_ONE) + else if(L.alpha <= EFFECTIVE_INVIS) continue else if(!SA_attackable(L)) continue @@ -1246,7 +1243,7 @@ ai_log("AttackTarget() Bailing because we're disabled",2) LoseTarget() return 0 - if(!target_mob || !SA_attackable(target_mob) || (target_mob.invisibility >= INVISIBILITY_LEVEL_ONE)) //if the target went invisible, you can't follow it + if(!target_mob || !SA_attackable(target_mob) || (target_mob.alpha <= EFFECTIVE_INVIS)) //if the target went invisible, you can't follow it LoseTarget() return 0 if(!(target_mob in ListTargets(view_range))) @@ -1391,6 +1388,8 @@ // if (!istype(target, /turf)) // qdel(A) // return + + A.firer = src A.launch(target) return diff --git a/code/modules/mob/living/simple_animal/simple_animal_vr.dm b/code/modules/mob/living/simple_animal/simple_animal_vr.dm index 96d460476fe..718dfee55b7 100644 --- a/code/modules/mob/living/simple_animal/simple_animal_vr.dm +++ b/code/modules/mob/living/simple_animal/simple_animal_vr.dm @@ -14,6 +14,7 @@ var/vore_pounce_chance = 5 // Chance of this mob knocking down an opponent var/vore_standing_too = 0 // Can also eat non-stunned mobs var/vore_ignores_undigestable = 1 // Refuse to eat mobs who are undigestable by the prefs toggle. + var/swallowsound = null // What noise plays when you succeed in eating the mob. var/vore_default_mode = DM_DIGEST // Default bellymode (DM_DIGEST, DM_HOLD, DM_ABSORB) var/vore_default_flags = DM_FLAG_ITEMWEAK // Itemweak by default @@ -114,7 +115,9 @@ var/old_target = target_mob handle_stance(STANCE_BUSY) . = animal_nom(target_mob) + playsound(src, swallowsound, 50, 1) update_icon() + if(.) // If we succesfully ate them, lose the target LoseTarget() diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index e69d547a93a..843990c7f6b 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -11,6 +11,8 @@ var/icon_state_override = null // Used for special slime appearances like the rainbow slime. pass_flags = PASSTABLE + makes_dirt = FALSE // Goop + speak_emote = list("chirps") maxHealth = 150 diff --git a/code/modules/mob/living/simple_animal/vore/hippo.dm b/code/modules/mob/living/simple_animal/vore/hippo.dm new file mode 100644 index 00000000000..bfd28aafb5c --- /dev/null +++ b/code/modules/mob/living/simple_animal/vore/hippo.dm @@ -0,0 +1,66 @@ +/mob/living/simple_animal/retaliate/hippo + name = "hippo" + desc = "Mostly know for the spectacular hit of the live action movie Hungry Hungry Hippos." + tt_desc = "Hippopotamus amphibius" + icon = 'icons/mob/vore64x64.dmi' + icon_state = "hippo" + icon_living = "hippo" + icon_dead = "hippo_dead" + icon_gib = "hippo_gib" + intelligence_level = SA_ANIMAL + + maxHealth = 200 + health = 200 + turns_per_move = 5 + see_in_dark = 3 + stop_when_pulled = 1 + speed = 5 + armor = list( + "melee" = 15,//They thick as fuck boi + "bullet" = 15, + "laser" = 15, + "energy" = 0, + "bomb" = 0, + "bio" = 0, + "rad" = 0) + + response_help = "pets the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + attacktext = list("bit") + retaliate = 1 + + melee_damage_upper = 25 + melee_damage_lower = 15 + attack_sharp = 1 + + old_x = -16 + old_y = 0 + default_pixel_x = -16 + pixel_x = -16 + pixel_y = 0 + + speak_chance = 0.1 + speak = list("UUUUUUH") + speak_emote = list("grunts","groans", "roars", "snorts") + emote_hear = list("groan") + emote_see = list("shakes its head") + + meat_amount = 10 //Infinite meat! + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + +// Activate Noms! +/mob/living/simple_animal/retaliate/hippo //I don't know why it's in a seperate line but everyone does it so i do it + vore_active = 1 + vore_capacity = 1 + vore_bump_chance = 15 + vore_bump_emote = "lazily wraps its tentacles around" + vore_standing_too = 1 + vore_ignores_undigestable = 0 + vore_default_mode = DM_HOLD + vore_digest_chance = 10 + vore_escape_chance = 20 + vore_pounce_chance = 35 //it's hippo sized it doesn't care it just eats you + vore_stomach_name = "rumen" //First stomach of a ruminant. It's where the pre digestion bacteria stuff happens. Very warm. + vore_stomach_flavor = "You are squeezed into the sweltering insides of the herbivore rumen." + vore_icons = SA_ICON_LIVING diff --git a/code/modules/mob/living/simple_animal/vore/rat.dm b/code/modules/mob/living/simple_animal/vore/rat.dm index 75d201699db..40b1800aa02 100644 --- a/code/modules/mob/living/simple_animal/vore/rat.dm +++ b/code/modules/mob/living/simple_animal/vore/rat.dm @@ -110,7 +110,9 @@ "almost sinks its teeth into [food], just stopping to give them another chance.")) hunger += 5 else if(hunger < 50) - visible_emote("appears to have had enough and prepares to strike!") + if(prob(25)) + visible_emote("appears to have had enough and prepares to strike!") + hunger += 5 else food.Weaken(5) food.visible_message("\the [src] pounces on \the [food]!!") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4a33c7748fd..d89d3f36b3f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -13,7 +13,7 @@ if(mind && mind.current == src) spellremove(src) ghostize() - qdel_null(plane_holder) + QDEL_NULL(plane_holder) ..() return QDEL_HINT_HARDDEL_NOW @@ -703,7 +703,10 @@ stat(null) for(var/datum/controller/subsystem/SS in Master.subsystems) SS.stat_entry() - + + if(statpanel("Tickets")) + GLOB.ahelp_tickets.stat_entry() + if(listed_turf && client) if(!TurfAdjacent(listed_turf)) listed_turf = null @@ -1154,8 +1157,13 @@ mob/proc/yank_out_object() /mob/proc/throw_item(atom/target) return +/mob/proc/will_show_tooltip() + if(alpha <= EFFECTIVE_INVIS) + return FALSE + return TRUE + /mob/MouseEntered(location, control, params) - if(usr != src && usr.is_preference_enabled(/datum/client_preference/mob_tooltips)) + if(usr != src && usr.is_preference_enabled(/datum/client_preference/mob_tooltips) && src.will_show_tooltip()) openToolTip(user = usr, tip_src = src, params = params, title = get_nametag_name(usr), content = get_nametag_desc(usr)) ..() diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index f3c8f2c09a4..d3c672edfa1 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -47,6 +47,8 @@ return affecting.grabbed_by += src + affecting.reveal("You are revealed as [assailant] grabs you.") + assailant.reveal("You reveal yourself as you grab [affecting].") hud = new /obj/screen/grab(src) hud.icon_state = "reinforce" @@ -75,7 +77,7 @@ if(affecting.buckled) return null if(state >= GRAB_AGGRESSIVE) - animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1) return affecting return null @@ -184,10 +186,10 @@ qdel(src) return if(affecting.buckled) - animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1, LINEAR_EASING) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1, LINEAR_EASING) return if(affecting.lying && state != GRAB_KILL) - animate(affecting, pixel_x = 0, pixel_y = 0, 5, 1, LINEAR_EASING) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING) if(force_down) affecting.set_dir(SOUTH) //face up return @@ -215,14 +217,14 @@ switch(adir) if(NORTH) - animate(affecting, pixel_x = 0, pixel_y =-shift, 5, 1, LINEAR_EASING) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y =-shift, 5, 1, LINEAR_EASING) affecting.layer = BELOW_MOB_LAYER if(SOUTH) - animate(affecting, pixel_x = 0, pixel_y = shift, 5, 1, LINEAR_EASING) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = shift, 5, 1, LINEAR_EASING) if(WEST) - animate(affecting, pixel_x = shift, pixel_y = 0, 5, 1, LINEAR_EASING) + animate(affecting, pixel_x = shift, pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING) if(EAST) - animate(affecting, pixel_x =-shift, pixel_y = 0, 5, 1, LINEAR_EASING) + animate(affecting, pixel_x =-shift, pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING) /obj/item/weapon/grab/proc/s_click(obj/screen/S) if(QDELETED(src)) @@ -394,7 +396,7 @@ return mob_size_difference(A.mob_size, B.mob_size) /obj/item/weapon/grab/Destroy() - animate(affecting, pixel_x = 0, pixel_y = 0, 4, 1, LINEAR_EASING) + animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1, LINEAR_EASING) affecting.reset_plane_and_layer() if(affecting) affecting.grabbed_by -= src diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index f842d0dc7b6..36e3815dd29 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -282,16 +282,10 @@ move_delay += config.walk_speed move_delay += mob.movement_delay() - var/tickcomp = 0 //moved this out here so we can use it for vehicles - if(config.Tickcomp) - // move_delay -= 1.3 //~added to the tickcomp calculation below - tickcomp = ((1/(world.tick_lag))*1.3) - 1.3 - move_delay = move_delay + tickcomp - if(istype(mob.buckled))// VOREStation Removal - , /obj/vehicle)) //manually set move_delay for vehicles so we don't inherit any mob movement penalties //specific vehicle move delays are set in code\modules\vehicles\vehicle.dm - move_delay = world.time + tickcomp + move_delay = world.time //drunk driving if(mob.confused && prob(20)) //vehicles tend to keep moving in the same direction direct = turn(direct, pick(90, -90)) @@ -561,4 +555,21 @@ /obj/item/weapon/storage/on_loc_moved(atom/oldloc) for(var/obj/O in contents) - O.on_loc_moved(oldloc) \ No newline at end of file + O.on_loc_moved(oldloc) + +/client/verb/moveup() + set name = ".moveup" + set instant = 1 + Move(get_step(mob, NORTH), NORTH) +/client/verb/movedown() + set name = ".movedown" + set instant = 1 + Move(get_step(mob, SOUTH), SOUTH) +/client/verb/moveright() + set name = ".moveright" + set instant = 1 + Move(get_step(mob, EAST), EAST) +/client/verb/moveleft() + set name = ".moveleft" + set instant = 1 + Move(get_step(mob, WEST), WEST) \ No newline at end of file diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm index 7534ca176c6..e1cb3a16c35 100644 --- a/code/modules/mob/mob_planes.dm +++ b/code/modules/mob/mob_planes.dm @@ -11,7 +11,7 @@ my_mob = this_guy //It'd be nice to lazy init these but some of them are important to just EXIST. Like without ghost planemaster, you can see ghosts. Go figure. - + // 'Utility' planes plane_masters[VIS_FULLBRIGHT] = new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects) plane_masters[VIS_LIGHTING] = new /obj/screen/plane_master/lighting //Lighting system (but different!) @@ -44,7 +44,7 @@ /datum/plane_holder/Destroy() my_mob = null - qdel_null_list(plane_masters) //Goodbye my children, be free + QDEL_NULL_LIST(plane_masters) //Goodbye my children, be free return ..() /datum/plane_holder/proc/set_vis(var/which = null, var/state = FALSE) @@ -52,6 +52,10 @@ var/obj/screen/plane_master/PM = plane_masters[which] if(!PM) crash_with("Tried to alter [which] in plane_holder on [my_mob]!") + + if(my_mob.alpha <= EFFECTIVE_INVIS) + state = FALSE + PM.set_visibility(state) if(PM.sub_planes) var/list/subplanes = PM.sub_planes diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 1aee45bdf68..f5d64e8897a 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -114,7 +114,7 @@ if(href_list["observe"]) - if(alert(src,"Are you sure you wish to observe? You will have to wait 1 minute before being able to respawn!","Player Setup","Yes","No") == "Yes") + if(alert(src,"Are you sure you wish to observe? You will have to wait 5 minute before being able to respawn!","Player Setup","Yes","No") == "Yes") //Vorestation edit if(!client) return 1 //Make a new mannequin quickly, and allow the observer to take the appearance diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 8a88d079c0c..9a34e041f50 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -133,7 +133,7 @@ ponytail1 name = "Ponytail 1" icon_state = "hair_ponytail" - flags = HAIR_TIEABLE + flags = HAIR_TIEABLE|HAIR_VERY_SHORT ponytail2 name = "Ponytail 2" @@ -158,12 +158,12 @@ ponytail6 name = "Ponytail 6" icon_state = "hair_ponytail6" - flags = HAIR_TIEABLE + flags = HAIR_TIEABLE|HAIR_VERY_SHORT fringetail name = "Fringetail" icon_state = "hair_fringetail" - flags = HAIR_TIEABLE + flags = HAIR_TIEABLE|HAIR_VERY_SHORT sideponytail name = "Side Ponytail" @@ -739,6 +739,22 @@ mohawkunshaven name = "Unshaven Mohawk" icon_state = "hair_unshaven_mohawk" + + belenko + name = "Belenko" + icon_state = "hair_belenko" + flags = HAIR_TIEABLE + + belenkotied + name = "Belenko Tied" + icon_state = "hair_belenkotied" + flags = HAIR_TIEABLE + + belenkotied + name = "Supernova" + icon_state = "hair_supernova" + flags = HAIR_TIEABLE + /* /////////////////////////////////// / =---------------------------= / diff --git a/code/modules/mob/new_player/sprite_accessories_vr.dm b/code/modules/mob/new_player/sprite_accessories_vr.dm index 0e4b98417f6..16f6d9168b3 100644 --- a/code/modules/mob/new_player/sprite_accessories_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_vr.dm @@ -649,6 +649,17 @@ icon_state = "jagged" body_parts = list(BP_HEAD) + blank_face + name = "Blank round face (use with monster mouth)" + icon_state = "blankface" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_HEAD) + + monster_mouth + name = "Monster mouth" + icon_state = "monster" + body_parts = list(BP_HEAD) + saber_teeth name = "Saber teeth" icon_state = "saber" diff --git a/code/modules/multiz/hoist.dm b/code/modules/multiz/hoist.dm index 9277d17ff95..a1df9389ab1 100644 --- a/code/modules/multiz/hoist.dm +++ b/code/modules/multiz/hoist.dm @@ -110,7 +110,7 @@ /obj/structure/hoist/Destroy() if(hoistee) release_hoistee() - qdel_null(src.source_hook) + QDEL_NULL(src.source_hook) return ..() /obj/effect/hoist_hook/Destroy() @@ -139,7 +139,7 @@ desc += " It looks broken, and the clamp has retracted back into the hoist. Seems like you'd have to re-deploy it to get it to work again." if(hoistee) release_hoistee() - qdel_null(source_hook) + QDEL_NULL(source_hook) /obj/structure/hoist/ex_act(severity) switch(severity) diff --git a/code/modules/multiz/ladder_assembly_vr.dm b/code/modules/multiz/ladder_assembly_vr.dm index 9347dc8ffc1..064d23cec33 100644 --- a/code/modules/multiz/ladder_assembly_vr.dm +++ b/code/modules/multiz/ladder_assembly_vr.dm @@ -21,7 +21,7 @@ created_name = t return - if(istype(W, /obj/item/weapon/wrench)) + if(W.is_wrench()) switch(state) if(CONSTRUCTION_UNANCHORED) state = CONSTRUCTION_WRENCHED diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index ea1a8b47068..06840f65fe8 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -173,6 +173,9 @@ if(!below) return + if(istype(below, /turf/space)) + return + var/turf/T = loc if(!T.CanZPass(src, DOWN) || !below.CanZPass(src, DOWN)) return diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm index 8bc2773697e..19ce85ea82b 100644 --- a/code/modules/multiz/zshadow.dm +++ b/code/modules/multiz/zshadow.dm @@ -29,7 +29,7 @@ return QDEL_HINT_QUEUE /mob/Destroy() - qdel_null(shadow) + QDEL_NULL(shadow) . = ..() /mob/zshadow/examine(mob/user, distance, infix, suffix) diff --git a/code/modules/nano/interaction/remote.dm b/code/modules/nano/interaction/remote.dm index ef2cb6926df..2e18386bde3 100644 --- a/code/modules/nano/interaction/remote.dm +++ b/code/modules/nano/interaction/remote.dm @@ -18,7 +18,7 @@ src.remoter_state = null // Force an UI update before we go, ensuring that any windows we may have opened for the remote target closes. - nanomanager.update_uis(remote_target.nano_container()) + GLOB.nanomanager.update_uis(remote_target.nano_container()) remote_target = null return ..() diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm index 6ed73e86ca4..dd7a85a1a31 100644 --- a/code/modules/nano/modules/alarm_monitor.dm +++ b/code/modules/nano/modules/alarm_monitor.dm @@ -80,7 +80,7 @@ "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : "")) data["categories"] = categories - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state) ui.set_initial_data(data) diff --git a/code/modules/nano/modules/atmos_control.dm b/code/modules/nano/modules/atmos_control.dm index a6f77c99056..a9129002750 100644 --- a/code/modules/nano/modules/atmos_control.dm +++ b/code/modules/nano/modules/atmos_control.dm @@ -48,7 +48,7 @@ data["alarms"] = alarms data["map_levels"] = using_map.get_map_levels(T.z) - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) ui = new(user, src, ui_key, "atmos_control.tmpl", src.name, 625, 625, state = state) // adding a template with the key "mapContent" enables the map ui functionality diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm index 8d837b8a751..5627fadf335 100644 --- a/code/modules/nano/modules/crew_monitor.dm +++ b/code/modules/nano/modules/crew_monitor.dm @@ -25,7 +25,7 @@ for(var/z in (data["map_levels"] | T.z)) // Always show crew from the current Z even if we can't show a map data["crewmembers"] += crew_repository.health_data(z) - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800, state = state) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 0870b60c641..c5c087f7d85 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -50,7 +50,7 @@ else data["isSilicon"] = null - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "photocopier.tmpl", src.name, 300, 250) ui.set_initial_data(data) @@ -80,7 +80,7 @@ var/obj/item/weapon/paper_bundle/B = bundlecopy(copyitem) sleep(11*B.pages.len) else - usr << "\The [copyitem] can't be copied by \the [src]." + to_chat(usr, "\The [copyitem] can't be copied by \the [src].") break use_power(active_power_usage) @@ -88,7 +88,7 @@ if(copyitem) copyitem.loc = usr.loc usr.put_in_hands(copyitem) - usr << "You take \the [copyitem] out of \the [src]." + to_chat(usr, "You take \the [copyitem] out of \the [src].") copyitem = null else if(href_list["min"]) if(copies > 1) @@ -118,7 +118,7 @@ toner -= 5 sleep(15) - nanomanager.update_uis(src) + GLOB.nanomanager.update_uis(src) /obj/machinery/photocopier/attackby(obj/item/O as obj, mob/user as mob) if(istype(O, /obj/item/weapon/paper) || istype(O, /obj/item/weapon/photo) || istype(O, /obj/item/weapon/paper_bundle)) @@ -126,24 +126,24 @@ user.drop_item() copyitem = O O.loc = src - user << "You insert \the [O] into \the [src]." + to_chat(user, "You insert \the [O] into \the [src].") playsound(loc, "sound/machines/click.ogg", 100, 1) flick(insert_anim, src) else - user << "There is already something in \the [src]." + to_chat(user, "There is already something in \the [src].") else if(istype(O, /obj/item/device/toner)) if(toner <= 10) //allow replacing when low toner is affecting the print darkness user.drop_item() - user << "You insert the toner cartridge into \the [src]." + to_chat(user, "You insert the toner cartridge into \the [src].") var/obj/item/device/toner/T = O toner += T.toner_amount qdel(O) else - user << "This cartridge is not yet ready for replacement! Use up the rest of the toner." - else if(istype(O, /obj/item/weapon/wrench)) + to_chat(user, "This cartridge is not yet ready for replacement! Use up the rest of the toner.") + else if(O.is_wrench()) playsound(loc, O.usesound, 50, 1) anchored = !anchored - user << "You [anchored ? "wrench" : "unwrench"] \the [src]." + to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") else if(default_deconstruction_screwdriver(user, O)) return diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm index 8fb76044178..0364056b695 100644 --- a/code/modules/planet/planet.dm +++ b/code/modules/planet/planet.dm @@ -21,19 +21,34 @@ var/list/turf/simulated/floor/planet_floors = list() var/list/turf/unsimulated/wall/planetary/planet_walls = list() - var/needs_work = 0 // Bitflags to signal to the planet controller these need (properly deferrable) work. Flags defined in controller. + var/sun_name = "the sun" // For flavor. + + var/moon_name = null // Purely for flavor. Null means no moon exists. + var/moon_phase = null // Set if above is defined. + /datum/planet/New() ..() weather_holder = new(src) current_time = current_time.make_random_time() + if(moon_name) + moon_phase = pick(list( + MOON_PHASE_NEW_MOON, + MOON_PHASE_WAXING_CRESCENT, + MOON_PHASE_FIRST_QUARTER, + MOON_PHASE_WAXING_GIBBOUS, + MOON_PHASE_FULL_MOON, + MOON_PHASE_WANING_GIBBOUS, + MOON_PHASE_LAST_QUARTER, + MOON_PHASE_WANING_CRESCENT + )) update_sun() /datum/planet/proc/process(last_fire) if(current_time) var/difference = world.time - last_fire - current_time = current_time.add_seconds(difference SECONDS) + current_time = current_time.add_seconds((difference / 10) * PLANET_TIME_MODIFIER) update_weather() // We update this first, because some weather types decease the brightness of the sun. if(sun_last_process <= world.time - sun_process_interval) update_sun() diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm index b8bbf7ba6a4..4a7b0421498 100644 --- a/code/modules/planet/sif.dm +++ b/code/modules/planet/sif.dm @@ -12,6 +12,9 @@ var/datum/planet/sif/planet_sif = null // expected_z_levels = list(1) // To be changed when real map is finished. planetary_wall_type = /turf/unsimulated/wall/planetary/sif + sun_name = "Vir" + moon_name = "Thor" + /datum/planet/sif/New() ..() planet_sif = src @@ -131,7 +134,7 @@ var/datum/planet/sif/planet_sif = null WEATHER_HAIL = 2.5 ) -datum/weather/sif +/datum/weather/sif name = "sif base" temp_high = 283.15 // 10c temp_low = 263.15 // -10c @@ -142,6 +145,13 @@ datum/weather/sif WEATHER_CLEAR = 60, WEATHER_OVERCAST = 40 ) + transition_messages = list( + "The sky clears up.", + "The sky is visible.", + "The weather is calm." + ) + sky_visible = TRUE + observed_message = "The sky is clear." /datum/weather/sif/overcast name = "overcast" @@ -154,6 +164,12 @@ datum/weather/sif WEATHER_RAIN = 5, WEATHER_HAIL = 5 ) + observed_message = "It is overcast, all you can see are clouds." + transition_messages = list( + "All you can see above are clouds.", + "Clouds cut off your view of the sky.", + "It's very cloudy." + ) /datum/weather/sif/light_snow name = "light snow" @@ -167,6 +183,11 @@ datum/weather/sif WEATHER_SNOW = 25, WEATHER_HAIL = 5 ) + observed_message = "It is snowing lightly." + transition_messages = list( + "Small snowflakes begin to fall from above.", + "It begins to snow lightly.", + ) /datum/weather/sif/snow name = "moderate snow" @@ -182,6 +203,11 @@ datum/weather/sif WEATHER_HAIL = 5, WEATHER_OVERCAST = 5 ) + observed_message = "It is snowing." + transition_messages = list( + "It's starting to snow.", + "The air feels much colder as snowflakes fall from above." + ) /datum/weather/sif/snow/process_effects() ..() @@ -206,6 +232,11 @@ datum/weather/sif WEATHER_HAIL = 10, WEATHER_OVERCAST = 5 ) + observed_message = "A blizzard blows snow everywhere." + transition_messages = list( + "Strong winds howl around you as a blizzard appears.", + "It starts snowing heavily, and it feels extremly cold now." + ) /datum/weather/sif/blizzard/process_effects() ..() @@ -230,6 +261,10 @@ datum/weather/sif WEATHER_STORM = 10, WEATHER_HAIL = 5 ) + observed_message = "It is raining." + transition_messages = list( + "The sky is dark, and rain falls down upon you." + ) /datum/weather/sif/rain/process_effects() ..() @@ -244,13 +279,13 @@ datum/weather/sif var/obj/item/weapon/melee/umbrella/U = L.get_active_hand() if(U.open) if(show_message) - to_chat(L, "Rain patters softly onto your umbrella") + to_chat(L, "Rain patters softly onto your umbrella.") continue else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella)) var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand() if(U.open) if(show_message) - to_chat(L, "Rain patters softly onto your umbrella") + to_chat(L, "Rain patters softly onto your umbrella.") continue L.water_act(1) @@ -264,6 +299,17 @@ datum/weather/sif temp_low = 233.15 // -40c light_modifier = 0.3 flight_failure_modifier = 10 + effect_message = "Rain falls on you, drenching you in water." + + var/next_lightning_strike = 0 // world.time when lightning will strike. + var/min_lightning_cooldown = 5 SECONDS + var/max_lightning_cooldown = 1 MINUTE + observed_message = "An intense storm pours down over the region." + transition_messages = list( + "You feel intense winds hit you as the weather takes a turn for the worst.", + "Loud thunder is heard in the distance.", + "A bright flash heralds the approach of a storm." + ) transition_chances = list( @@ -281,22 +327,52 @@ datum/weather/sif if(!T.outdoors) continue // They're indoors, so no need to rain on them. - // If they have an open umbrella, it'll get stolen by the wind + // Lazy wind code + if(prob(10)) + if(istype(L.get_active_hand(), /obj/item/weapon/melee/umbrella)) + var/obj/item/weapon/melee/umbrella/U = L.get_active_hand() + if(U.open) + to_chat(L, "You struggle to keep hold of your umbrella!") + L.Stun(20) // This is not nearly as long as it seems + playsound(L, 'sound/effects/rustle1.ogg', 100, 1) // Closest sound I've got to "Umbrella in the wind" + else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella)) + var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand() + if(U.open) + to_chat(L, "A gust of wind yanks the umbrella from your hand!") + playsound(L, 'sound/effects/rustle1.ogg', 100, 1) + L.drop_from_inventory(U) + U.toggle_umbrella() + U.throw_at(get_edge_target_turf(U, pick(alldirs)), 8, 1, L) + + // If they have an open umbrella, it'll guard from rain if(istype(L.get_active_hand(), /obj/item/weapon/melee/umbrella)) var/obj/item/weapon/melee/umbrella/U = L.get_active_hand() if(U.open) - to_chat(L, "A gust of wind yanks the umbrella from your hand!") - L.drop_from_inventory(U) - U.throw_at(get_edge_target_turf(U, pick(alldirs)), 8, 1, L) + if(show_message) + to_chat(L, "Rain showers loudly onto your umbrella!") + continue else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella)) var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand() if(U.open) - to_chat(L, "A gust of wind yanks the umbrella from your hand!") - L.drop_from_inventory(U) - U.throw_at(get_edge_target_turf(U, pick(alldirs)), 8, 1, L) + if(show_message) + to_chat(L, "Rain showers loudly onto your umbrella!") + continue + L.water_act(2) - to_chat(L, "Rain falls on you, drenching you in water.") + if(show_message) + to_chat(L, effect_message) + + handle_lightning() + +// This gets called to do lightning periodically. +// There is a seperate function to do the actual lightning strike, so that badmins can play with it. +/datum/weather/sif/storm/proc/handle_lightning() + if(world.time < next_lightning_strike) + return // It's too soon to strike again. + next_lightning_strike = world.time + rand(min_lightning_cooldown, max_lightning_cooldown) + var/turf/T = pick(holder.our_planet.planet_floors) // This has the chance to 'strike' the sky, but that might be a good thing, to scare reckless pilots. + lightning_strike(T) /datum/weather/sif/hail name = "hail" @@ -315,6 +391,12 @@ datum/weather/sif WEATHER_HAIL = 10, WEATHER_OVERCAST = 5 ) + observed_message = "Ice is falling from the sky." + transition_messages = list( + "Ice begins to fall from the sky.", + "It begins to hail.", + "An intense chill is felt, and chunks of ice start to fall from the sky, towards you." + ) /datum/weather/sif/hail/process_effects() ..() @@ -361,3 +443,7 @@ datum/weather/sif transition_chances = list( WEATHER_BLOODMOON = 100 ) + observed_message = "Everything is red. Something really wrong is going on." + transition_messages = list( + "The sky turns blood red!" + ) \ No newline at end of file diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm index 96f36601214..a13cb87cc79 100644 --- a/code/modules/planet/weather.dm +++ b/code/modules/planet/weather.dm @@ -1,15 +1,17 @@ /datum/weather_holder - var/datum/planet/our_planet = null - var/datum/weather/current_weather = null - var/temperature = T20C - var/wind_dir = 0 - var/wind_speed = 0 - var/list/allowed_weather_types = list() - var/list/roundstart_weather_chances = list() - var/next_weather_shift = null + var/datum/planet/our_planet = null // Reference to the planet datum that holds this datum. + var/datum/weather/current_weather = null // The current weather that is affecting the planet. + var/temperature = T20C // The temperature to set planetary walls to. + var/wind_dir = 0 // Not implemented. + var/wind_speed = 0 // Not implemented. + var/list/allowed_weather_types = list() // Assoc list of weather identifiers, containing the actual weather datum. + var/list/roundstart_weather_chances = list() // Assoc list of weather identifiers and their odds of being picked to happen at roundstart. + var/next_weather_shift = null // world.time when the weather subsystem will advance the forecast. + var/list/forecast = list() // A list of what the weather will be in the future. This allows it to be pre-determined and planned around. // Holds the weather icon, using vis_contents. Documentation says an /atom/movable is required for placing inside another atom's vis_contents. var/atom/movable/weather_visuals/visuals = null + var/atom/movable/weather_visuals/special/special_visuals = null /datum/weather_holder/New(var/source) ..() @@ -19,31 +21,79 @@ if(istype(W)) W.holder = src visuals = new() + special_visuals = new() /datum/weather_holder/proc/change_weather(var/new_weather) var/old_light_modifier = null + var/old_weather = null if(current_weather) old_light_modifier = current_weather.light_modifier // We store the old one, so we can determine if recalculating the sun is needed. + old_weather = current_weather current_weather = allowed_weather_types[new_weather] next_weather_shift = world.time + rand(current_weather.timer_low_bound, current_weather.timer_high_bound) MINUTES + if(new_weather != old_weather) + show_transition_message() update_icon_effects() update_temperature() if(old_light_modifier && current_weather.light_modifier != old_light_modifier) // Updating the sun should be done sparingly. our_planet.update_sun() - //message_admins("[our_planet.name]'s weather is now [new_weather], with a temperature of [temperature]°K ([temperature - T0C]°C | [temperature * 1.8 - 459.67]°F).") //VOREStation Removal - I like weather, I just don't like hearing about it. + log_debug("[our_planet.name]'s weather is now [new_weather], with a temperature of [temperature]°K ([temperature - T0C]°C | [temperature * 1.8 - 459.67]°F).") /datum/weather_holder/proc/process() if(world.time >= next_weather_shift) - var/new_weather - if(!current_weather) - new_weather = pickweight(roundstart_weather_chances) + if(!current_weather) // Roundstart (hopefully). + initialize_weather() else - new_weather = pickweight(current_weather.transition_chances) - change_weather(new_weather) + advance_forecast() else current_weather.process_effects() + + +// Should only have to be called once. +/datum/weather_holder/proc/initialize_weather() + if(!current_weather) + change_weather(get_next_weather()) + build_forecast() + +// Used to determine what the weather will be soon, in a semi-random fashion. +// The forecast is made by calling this repeatively, from the bottom (highest index) of the forecast list. +/datum/weather_holder/proc/get_next_weather(var/datum/weather/W) + if(!current_weather) // At roundstart, choose a suitable initial weather. + return pickweight(roundstart_weather_chances) + return pickweight(W.transition_chances) + +/datum/weather_holder/proc/advance_forecast() + var/new_weather = forecast[1] + forecast.Cut(1, 2) // Remove what we just took out, shortening the list. + change_weather(new_weather) + build_forecast() // To fill the forecast to the desired length. + +// Creates a list of future weather shifts, that the planet will undergo at some point in the future. +// Determining it ahead of time allows for attentive players to plan further ahead, if they can see the forecast. +/datum/weather_holder/proc/build_forecast() + var/desired_length = 3 + if(forecast.len >= desired_length) + return + + while(forecast.len < desired_length) + if(!forecast.len) // If the forecast is empty, the current_weather is used as a base instead. + forecast += get_next_weather(current_weather) + else + var/position = forecast[forecast.len] // Go to the bottom of the list. + var/datum/weather/W = allowed_weather_types[position] // Get the actual datum and not a string. + var/new_weather = get_next_weather(W) // Get a suitable weather pattern to shift to from this one. + forecast += new_weather + log_debug("[our_planet.name]'s weather forecast is now '[english_list(forecast, and_text = " then ", final_comma_text = ", ")]'.") + +// Wipes the forecast and regenerates it. Used for when the weather is forcefully changed, such as with admin verbs. +/datum/weather_holder/proc/rebuild_forecast() + forecast.Cut() + build_forecast() + + + /datum/weather_holder/proc/update_icon_effects() visuals.icon_state = current_weather.icon_state @@ -55,25 +105,41 @@ return allowed_weather_types[desired_type] +/datum/weather_holder/proc/show_transition_message() + if(!current_weather.transition_messages.len) + return + + var/message = pick(current_weather.transition_messages) // So everyone gets the same message. + for(var/mob/M in player_list) // Don't need to care about clientless mobs. + if(M.z in our_planet.expected_z_levels) + var/turf/T = get_turf(M) + if(!T.outdoors) + continue + to_chat(M, message) + /datum/weather var/name = "weather base" var/icon = 'icons/effects/weather.dmi' var/icon_state = null // Icon to apply to turf undergoing weather. - var/temp_high = T20C - var/temp_low = T0C + var/temp_high = T20C // Temperature to apply when at noon. + var/temp_low = T0C // Temperature to apply when at midnight. var/light_modifier = 1.0 // Lower numbers means more darkness. var/light_color = null // If set, changes how the day/night light looks. - var/flight_failure_modifier = 0 // Some types of weather make flying harder, and therefore make crashes more likely. - var/transition_chances = list() // Assoc list - var/datum/weather_holder/holder = null + var/flight_failure_modifier = 0 // Some types of weather make flying harder, and therefore make crashes more likely. (This is not implemented) + var/transition_chances = list() // Assoc list of weather identifiers and the odds to shift to a specific type of weather. Can contain its own identifier to prolong it. + var/datum/weather_holder/holder = null // Reference to the datum that manages the planet's weather. var/timer_low_bound = 5 // How long this weather must run before it tries to change, in minutes var/timer_high_bound = 10 // How long this weather can run before it tries to change, in minutes + var/sky_visible = FALSE // If the sky can be clearly seen while this is occuring, used for flavor text when looking up. var/effect_message = null // Should be a string, this is what is shown to a mob caught in the weather var/last_message = 0 // Keeps track of when the weather last tells EVERY player it's hitting them var/message_delay = 10 SECONDS // Delay in between weather hit messages var/show_message = FALSE // Is set to TRUE and plays the messsage every [message_delay] + var/list/transition_messages = list()// List of messages shown to all outdoor mobs when this weather is transitioned to, for flavor. Not shown if already this weather. + var/observed_message = null // What is shown to a player 'examining' the weather. + /datum/weather/proc/process_effects() show_message = FALSE // Need to reset the show_message var, just in case if(effect_message) // Only bother with the code below if we actually need to display something @@ -87,3 +153,8 @@ icon = 'icons/effects/weather.dmi' mouse_opacity = 0 plane = PLANE_PLANETLIGHTING + +// This is for special effects for specific types of weather, such as lightning flashes in a storm. +// It's a seperate object to allow the use of flick(). +/atom/movable/weather_visuals/special + plane = PLANE_LIGHTING_ABOVE \ No newline at end of file diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm index 204193de188..20144059d71 100644 --- a/code/modules/power/antimatter/control.dm +++ b/code/modules/power/antimatter/control.dm @@ -140,7 +140,7 @@ /obj/machinery/power/am_control_unit/attackby(obj/item/W, mob/user) if(!istype(W) || !user) return - if(istype(W, /obj/item/weapon/wrench)) + if(W.is_wrench()) if(!anchored) playsound(src, W.usesound, 75, 1) user.visible_message("[user.name] secures the [src.name] to the floor.", \ diff --git a/html/changelogs/Anewbe - Bloodloss.yml b/html/changelogs/Anewbe - Bloodloss.yml new file mode 100644 index 00000000000..8ec14a38db5 --- /dev/null +++ b/html/changelogs/Anewbe - Bloodloss.yml @@ -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: Anewbe + +# 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: + - bugfix: "You can no longer have ALL of your blood punched out." + - bugfix: "Haemophiliacs will no longer spontaneously have ALL of their blood go missing from ~90%." diff --git a/icons/effects/64x64.dmi b/icons/effects/64x64.dmi new file mode 100644 index 00000000000..79eabaac4f3 Binary files /dev/null and b/icons/effects/64x64.dmi differ diff --git a/icons/effects/96x256.dmi b/icons/effects/96x256.dmi new file mode 100644 index 00000000000..978f0fbcdad Binary files /dev/null and b/icons/effects/96x256.dmi differ diff --git a/icons/holomap_markers.dmi b/icons/holomap_markers.dmi new file mode 100644 index 00000000000..3ea32c120d0 Binary files /dev/null and b/icons/holomap_markers.dmi differ diff --git a/icons/mob/custom_items_rig_boots.dmi b/icons/mob/custom_items_rig_boots.dmi new file mode 100644 index 00000000000..cf74d73796c Binary files /dev/null and b/icons/mob/custom_items_rig_boots.dmi differ diff --git a/icons/mob/custom_items_rig_gloves.dmi b/icons/mob/custom_items_rig_gloves.dmi new file mode 100644 index 00000000000..cf74d73796c Binary files /dev/null and b/icons/mob/custom_items_rig_gloves.dmi differ diff --git a/icons/mob/custom_items_rig_helmet.dmi b/icons/mob/custom_items_rig_helmet.dmi new file mode 100644 index 00000000000..cf74d73796c Binary files /dev/null and b/icons/mob/custom_items_rig_helmet.dmi differ diff --git a/icons/mob/custom_items_rig_suit.dmi b/icons/mob/custom_items_rig_suit.dmi new file mode 100644 index 00000000000..cf74d73796c Binary files /dev/null and b/icons/mob/custom_items_rig_suit.dmi differ diff --git a/nano/templates/comm_power_monitor.tmpl b/nano/templates/comm_power_monitor.tmpl new file mode 100644 index 00000000000..ffcd70ff2a6 --- /dev/null +++ b/nano/templates/comm_power_monitor.tmpl @@ -0,0 +1,76 @@ +

Powernet Monitoring

+ +{{if data.currentTab == 0}} + + + +
+ {{:helper.link('Scan For Sensors', 'refresh', {'cartridge_topic' : 1, 'powernet_refresh' : 1})}} No active sensor. Printing sensor list. +
+
+ + {{for data.powernet_monitoring}} + + {{empty}} + WARNING: No Sensors Detected! + {{/for}} +
+ {{if value.alarm}} + {{:helper.link(value.name, 'alert', {'switch_tab' : value.name, 'powernet_target' : value.name})}} + {{else}} + {{:helper.link(value.name, '' , {'switch_tab' : value.name, 'cartridge_topic' : 1, 'powernet_target' : value.name})}} + {{/if}} +
+{{else}} + + + +
+ {{:helper.link('Show List', 'cancel', { 'switch_tab' : 0})}} Sensor selected: {{:data.currentTab}} +
+ {{if data.powernet_target.error}} + {{:data.powernet_target.error}} + {{else}} + +

Network Information

+ {{for data.powernet_target.status :nodeValue:nodeIndex}} +
+
{{:nodeValue.field}}
+
{{:nodeValue.statval}}
+
+ {{/for}} + + +

Sensor Readings

+ + + + + + + + + + {{for data.powernet_target.apc_data :apcValue:apcIndex}} + + + + + + + + + {{empty}} + + {{/for}} +
APC NameEquipmentLightingEnvironmentCell StatusAPC Load
{{:apcValue.name}}{{:apcValue.s_equipment}}{{:apcValue.s_lighting}}{{:apcValue.s_environment}} + {{if apcValue.cell_status == "N"}} + {{:helper.link(apcValue.cell_charge + '%', 'batt_disc', null,'disabled', 'width75btn')}} + {{else apcValue.cell_status == "C"}} + {{:helper.link(apcValue.cell_charge + '%', 'batt_chrg', null,'disabled', 'width75btn')}} + {{else}} + {{:helper.link(apcValue.cell_charge + '%', 'batt_full', null,'disabled', 'width75btn')}} + {{/if}} + {{:apcValue.total_load}}
No APCs detected in connected powernet.
+ {{/if}} +{{/if}} diff --git a/nano/templates/communicator_header.tmpl b/nano/templates/communicator_header.tmpl new file mode 100644 index 00000000000..63289ba181e --- /dev/null +++ b/nano/templates/communicator_header.tmpl @@ -0,0 +1,18 @@ +
+
+
+ {{:data.time}} | + {{if data.connectionStatus == 1}} + + {{else}} + + {{/if}} + | {{:data.owner}} | {{:data.occupation}} | +
+
+ {{:helper.link('Home', 'home', {'switch_tab' : 1, 'switch_template' : 'communicator.tmpl'})}} +
+
+
+ +{{#def.Body}} \ No newline at end of file diff --git a/nano/templates/emp_records.tmpl b/nano/templates/emp_records.tmpl new file mode 100644 index 00000000000..16b5159039c --- /dev/null +++ b/nano/templates/emp_records.tmpl @@ -0,0 +1,23 @@ +

Employment Records

+{{if data.currentTab == "0"}} +
+ {{for data.emp_records}} +
+ {{:helper.link(value.name, '', {"switch_tab" : value.name})}} +
+ {{/for}} +
+{{/if}} +{{for data.emp_records}} + {{if value.name == data.currentTab}} +
{{:helper.link('Back', 'icon-triangle-1-w', {'switch_tab' : 0})}}

+
+ {{for value.record :itemValue:itemIndex}} +
+
{{:itemValue.tab}}
+
{{:itemValue.val}}
+
+ {{/for}} +
+ {{/if}} +{{/for}} \ No newline at end of file diff --git a/nano/templates/gps_access.tmpl b/nano/templates/gps_access.tmpl new file mode 100644 index 00000000000..21b61b767ae --- /dev/null +++ b/nano/templates/gps_access.tmpl @@ -0,0 +1,66 @@ +

Integrated GPS

+ + +{{if data.gps_status.enabled}} +
+ Area: {{:data.gps_status.my_area_name}}, {{:data.gps_status.curr_z_name}}
+ GPS Coordinates: ({{:data.gps_status.curr_x}}, {{:data.gps_status.curr_y}}) +
+{{else}} +
+ Error: Location data unavailable. No sensors online! +
+{{/if}} + + +
+ {{for data.gps_access}} +
+
+ {{:index}}: {{:value.tag}} +
+
+ {{:helper.link('On', 'power', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Power", 'value' : "1"}, value.power ? 'selected' : null)}} + {{:helper.link('Off', 'stop', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Power", 'value' : "0"}, value.power ? null : 'selected')}} + {{:helper.link('Edit Tag', 'power', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Tag", 'user' : data.user})}} + {{if value.power}} + {{if value.long_range}} +
+ + {{:helper.string("Long range scanning is {0}.", value.local_mode ? "disabled" : "active")}} + {{:helper.link('Enable', 'power', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Long_Range", 'value' : "0"}, value.long_range_en ? 'selected' : null)}} + {{:helper.link('Disable', 'stop', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Long_Range", 'value' : "1"}, value.long_range_en ? null : 'selected')}} + {{/if}} + {{if value.can_hide}} +
+ {{:helper.string("{0}", value.hide_signal ? "Broadcasting location" : "Receiving only ")}} + {{:helper.link('Broadcast', 'power', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Hide_Signal", 'value' : "1"}, value.hide_signal ? 'selected' : null)}} + {{:helper.link('Receive', 'stop', {'cartridge_topic' : "1", 'gps_target' : value.ref, 'gps_action' : "Hide_Signal", 'value' : "0"}, value.hide_signal ? null : 'selected')}} + {{/if}} + {{/if}} +
+
+ {{empty}} + {{/for}} +
+ + +{{if data.gps_status.enabled}} +
+ {{for data.gps_signal}} +
+
+ {{:value.gps_tag}} +
+
+ Coordinates: ({{:value.x}}, {{:value.y}}) +
+ Area: {{:value.area_name}}, {{:value.z_name}} + {{if value.local}} + {{:helper.string("Distance: {0}m {1} - {2}m {3}, {4}m {5}", value.distance < 0 ? 0 : value.distance, value.direction, helper.abs(value.distY), ((value.distY > 0) ? "N" : "S"), helper.abs(value.distX), ((value.distX > 0) ? "E" : "W"))}} + {{/if}} +
+
+ {{/for}} +
+{{/if}} \ No newline at end of file diff --git a/nano/templates/janitorialLocator.tmpl b/nano/templates/janitorialLocator.tmpl new file mode 100644 index 00000000000..d476b7def42 --- /dev/null +++ b/nano/templates/janitorialLocator.tmpl @@ -0,0 +1,11 @@ +

Janitorial Supply Locator

+{{for data.janidata}} +
+
+ {{:value.field}} +
+
+ {{:value.val}} +
+
+{{/for}} \ No newline at end of file diff --git a/nano/templates/manifest.tmpl b/nano/templates/manifest.tmpl new file mode 100644 index 00000000000..00c45a1d5ff --- /dev/null +++ b/nano/templates/manifest.tmpl @@ -0,0 +1,27 @@ + + +

Crew Manifest

+ +
+
{{:helper.link('Home', 'home', {'switch_tab' : 1})}}

+ +
+
+ {{for data.manifest}} + {{if value.elems.length}} + + {{for value.elems :itemValue:itemIndex}} + + + + + + {{/for}} + {{/if}} + {{/for}} +
{{:value.cat}}
{{:itemValue.name}}{{:itemValue.rank}}{{:itemValue.active}}
+
diff --git a/nano/templates/med_records.tmpl b/nano/templates/med_records.tmpl new file mode 100644 index 00000000000..f24339a7796 --- /dev/null +++ b/nano/templates/med_records.tmpl @@ -0,0 +1,23 @@ +

Medical Records

+{{if data.currentTab == "0"}} +
+ {{for data.med_records}} +
+ {{:helper.link(value.name, '', {"switch_tab" : value.name})}} +
+ {{/for}} +
+{{/if}} +{{for data.med_records}} + {{if value.name == data.currentTab}} +
{{:helper.link('Back', 'icon-triangle-1-w', {'switch_tab' : 0})}}

+
+ {{for value.record :itemValue:itemIndex}} +
+
{{:itemValue.tab}}
+
{{:itemValue.val}}
+
+ {{/for}} +
+ {{/if}} +{{/for}} \ No newline at end of file diff --git a/nano/templates/merc_blast_door_control.tmpl b/nano/templates/merc_blast_door_control.tmpl new file mode 100644 index 00000000000..bd74a42e20d --- /dev/null +++ b/nano/templates/merc_blast_door_control.tmpl @@ -0,0 +1,23 @@ +

Shuttle Blast Door Control

+ +
+ {{:helper.link('Open all doors', 'radio-on', {'cartridge_topic' : 1, 'all_blast_doors' : "open"})}} + {{:helper.link('Close all doors', 'radio-off', {'cartridge_topic' : 1, 'all_blast_doors' : "close"})}} +
+
+ {{:helper.link('Scan for doors', 'refresh', {'cartridge_topic' : 1, 'scan_blast_doors' : 1})}} +
+ +{{for data.blast_door}} +
+
+ {{:value.name}} #{{:index}} +
+
+ {{:helper.link('On', 'radio-on', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? 'selected' : null)}} + {{:helper.link('Off', 'radio-off', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? null : 'selected')}} +
+
+{{empty}} +

No doors detected!

+{{/for}} \ No newline at end of file diff --git a/nano/templates/sec_bot_access.tmpl b/nano/templates/sec_bot_access.tmpl new file mode 100644 index 00000000000..49214cb97fe --- /dev/null +++ b/nano/templates/sec_bot_access.tmpl @@ -0,0 +1,36 @@ +

Security Bot Control

+ +{{if data.currentTab == 0}} + + +
+ Select A Bot. +
+
+ {{for data.sec_bot_access}} +
+ {{:helper.link(value.bot, 'gear', {'switch_tab' : value.bot})}} +
+ {{empty}} +

No bots found.

+ {{/for}} +
+ +{{else}} + + + {{for data.sec_bot_access}} + {{if value.bot == data.currentTab}} + {{for value.status :statVal:statIndex}} +
+
+ {{:statVal.tab}} +
+
+ {{:statVal.val}} +
+
+ {{/for}} + {{/if}} + {{/for}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/sec_records.tmpl b/nano/templates/sec_records.tmpl new file mode 100644 index 00000000000..f644289061d --- /dev/null +++ b/nano/templates/sec_records.tmpl @@ -0,0 +1,23 @@ +

Security Records

+{{if data.currentTab == "0"}} +
+ {{for data.sec_records}} +
+ {{:helper.link(value.name, '', {"switch_tab" : value.name})}} +
+ {{/for}} +
+{{/if}} +{{for data.sec_records}} + {{if value.name == data.currentTab}} +
{{:helper.link('Back', 'icon-triangle-1-w', {'switch_tab' : 0})}}

+
+ {{for value.record :itemValue:itemIndex}} +
+
{{:itemValue.tab}}
+
{{:itemValue.val}}
+
+ {{/for}} +
+ {{/if}} +{{/for}} \ No newline at end of file diff --git a/nano/templates/signaler_access.tmpl b/nano/templates/signaler_access.tmpl new file mode 100644 index 00000000000..86220f07cb6 --- /dev/null +++ b/nano/templates/signaler_access.tmpl @@ -0,0 +1,24 @@ +

Signaler Control

+ + +{{for data.signaler_access}} +
+
+ {{:index}} +
+
+ {{:helper.link('Pulse', 'arrowstop-1-n', {'cartridge_topic' : "1", 'signaler_target' : value.ref, 'signaler_action' : "Pulse"})}} +
+
+ {{for value.status :statVal:statIndex}} +
+
+ {{:statVal.tab}} +
+
+
{{:statVal.val}}
+
{{:helper.link('Edit', 'gear', {'cartridge_topic' : "1", 'signaler_target' : value.ref, 'signaler_action' : "Edit", 'signaler_value' : statVal.tab, 'user' : data.user})}}
+
+
+ {{/for}} +{{/for}} \ No newline at end of file diff --git a/nano/templates/stat_display_access.tmpl b/nano/templates/stat_display_access.tmpl new file mode 100644 index 00000000000..1f1c8e0492d --- /dev/null +++ b/nano/templates/stat_display_access.tmpl @@ -0,0 +1,57 @@ +

Station Status Display Interlink

+ +
+
+ Code +
+
+ {{:helper.link('Clear Message', 'trash', {'cartridge_topic' : "1", 'stat_display' : "blank"}, (data.stat_display.active == "blank") ? 'selected' : null)}} + {{:helper.link('Clear Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "default"}, (data.stat_display.active == "default") ? 'selected' : null)}} +
+
+
+
+ Message +
+
+ {{:helper.link('Shuttle ETA', 'gear', {'cartridge_topic' : "1", 'stat_display' : "shuttle"}, (data.stat_display.active == "shuttle") ? 'selected' : null)}} + {{:helper.link('Set Message', 'gear', {'cartridge_topic' : "1", 'stat_display' : "message"}, (data.stat_display.active == "message") ? 'selected' : null)}} +
+
+
+
+ Alert +
+
+ {{:helper.link('Red Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "redalert"}, (data.stat_display.active == "redalert") ? 'selected' : null)}} + {{:helper.link('Lockdown', 'caution', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "lockdown"}, (data.stat_display.active == "lockdown") ? 'selected' : null)}} + {{:helper.link('Biohazard', 'radiation', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "biohazard"}, (data.stat_display.active == "biohazard") ? 'selected' : null)}} +
+
+{{if data.stat_display.line1 != data.stat_display.active_line1 || data.stat_display.line2 != data.stat_display.active_line2}} +
+
+ Active Message: +
+
+ {{:data.stat_display.active_line1}}
+ {{:data.stat_display.active_line2}} +
+
+{{/if}} +
+
+ Stored line 1 +
+
+ {{:helper.link(data.stat_display.line1 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "1"}, null, null)}} +
+
+
+
+ Stored line 2 +
+
+ {{:helper.link(data.stat_display.line2 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "2"}, null, null)}} +
+
diff --git a/nano/templates/supply_records.tmpl b/nano/templates/supply_records.tmpl new file mode 100644 index 00000000000..8a8a749bd2f --- /dev/null +++ b/nano/templates/supply_records.tmpl @@ -0,0 +1,226 @@ +

Supply Records

+ + +
+ + Supply points: {{:data.supply_points}}
+ + +
+

Supply Shuttle

+
+ Location:
+ Engines: +
+
+ {{:data.shuttle.location}}
+ {{:data.shuttle.engine}} +
+ {{if data.shuttle.mode == 4}} +
+ ETA: +
+
+ {{:data.shuttle.time}} minutes +
+ {{/if}} + {{if data.shuttle_auth}} + + {{if data.shuttle.launch == 1 && data.shuttle.mode == 0}} + {{:helper.link('Send away', 'suitcase', {'send_shuttle' : 'send_away'})}} + {{else data.shuttle.launch == 2 && (data.shuttle.mode == 3 || data.shuttle.mode == 1)}} + {{:helper.link('Cancel launch', 'stop', {'send_shuttle' : 'cancel_shuttle'})}} + {{else data.shuttle.launch == 1 && data.shuttle.mode == 5}} + {{:helper.link('Send shuttle', 'suitcase', {'send_shuttle' : 'send_to_station'})}} + {{/if}} + {{if data.shuttle.force}} + {{:helper.link('Force launch', 'alert', {'send_shuttle' : 'force_shuttle'})}} + {{/if}} + {{/if}} +
+
+ + +{{if data.currentTab == 0}} +
+ +
+ {{:helper.link('Request items', 'note', {'switch_tab' : 1})}} +
+ + +
+ {{:helper.link('View accepted orders', 'cart', {'switch_tab' : "Approved"})}} +
+ + +
+ {{:helper.link('View pending requests', 'cart', {'switch_tab' : "Requested"})}} +
+ + + {{:helper.link('View order history', 'document', {'switch_tab' : "All"})}} + + +
+ {{:helper.link('View export history', 'document', {'switch_tab' : "Export"})}} +
+
+ +{{else}} + {{:helper.link('Back to menu', 'arrowreturn-1-w', {'switch_tab' : 0})}} + + + + {{if data.currentTab == 1}} + {{for data.categories}} +
+ {{:helper.link(value, 'bookmark', {'switch_tab' : value, 'active_category' : value})}} +
+ {{/for}} + + + {{else data.currentTab == "Export"}} +

Exported Crates

+ {{for data.receipts}} +
+
+ {{for value.title :titleVal:titleIndex}} +
+ {{:titleVal.field}} +
+
+ {{:titleVal.entry}} + {{if data.order_auth}} + + {{:helper.link('Edit', 'wrench', {'order_ref' : value.ref, 'edit' : titleVal.field, 'default' : titleVal.entry, 'user' : data.user})}} + + {{/if}} +
+ {{/for}} + + {{if value.error}} +
+ + Error + +
+
+ {{:value.error}} +
+ {{else}} + {{for value.contents :contentVal:contentIndex}} +
+ {{:contentVal.quantity}}x {{:contentVal.object}} - {{:contentVal.value}} points +
+ {{if data.order_auth}} +
+ {{:helper.link('Edit Quantity','wrench', {'export_ref' : value.ref, 'edit' : 1, 'default' : contentVal.quantity, 'index' : contentIndex, 'user' : data.user})}} + {{:helper.link('Delete Entry', 'trash', {'export_ref' : value.ref, 'delete' : 1, 'index' : contentIndex, 'user' : data.user})}} +
+ {{/if}} + {{/for}} + {{/if}} + + {{if data.order_auth}} +
{{:helper.link('Add item to record', 'plus', {'export_ref' : value.ref, 'add_item' : 1, 'user' : data.user})}} +
{{:helper.link('Delete record', 'trash', {'export_ref' : value.ref, 'delete' : 1, 'user' : data.user})}} + {{/if}} +
+ {{empty}} +
No receipts on record!
+ {{/for}} + + + + + + {{else data.currentTab == "Approved" || data.currentTab == "Requested" || data.currentTab == "All"}} +

{{:data.currentTab}} Orders

+ {{for data.orders}} + {{if (value.status == data.currentTab) || (data.currentTab == "All")}} +
+
+ {{for value.entries :entryVal:entryIndex}} + + {{if entryVal.entry}} +
+ {{:entryVal.field}} +
+
+ {{:entryVal.entry}} + {{if data.order_auth}} + + {{:helper.link('Edit', 'wrench', {'order_ref' : value.ref, 'edit' : entryVal.field, 'default' : entryVal.entry, 'user' : data.user})}} + + {{/if}} +
+ {{/if}} + {{/for}} + + {{if data.currentTab == "All"}} +
+ Status +
+
+ {{:value.status}} +
+ {{if data.order_auth}} +
{{:helper.link('Delete record', 'trash', {'order_ref' : value.ref, 'delete' : 1, 'user' : data.user})}} + {{/if}} + {{/if}} + + {{if data.order_auth && data.currentTab == "Requested"}} + {{:helper.link('Approve', 'check', {'order_ref' : value.ref, 'approve' : 1, 'user' : data.user})}} + {{:helper.link('Deny', 'cancel', {'order_ref' : value.ref, 'deny' : 1, 'user' : data.user})}} + {{/if}} +
+ {{/if}} + {{empty}} +
No orders on record!
+ {{/for}} + + {{if data.currentTab == "Requested" && data.order_auth}} + {{:helper.link('Clear all requests', 'trash', {'clear_all_requests' : 1, 'user' : data.user})}} + {{/if}} + + + + {{else}} +
+ {{:helper.link('Back to categories', 'arrow-return-1-w', {'switch_tab' : 1})}} +
+ +

+ {{:data.active_category}} +

+ + {{for data.supply_packs :packValue:packIndex}} + {{if !packValue.contraband || data.contraband}} +
+ + {{:helper.link(packValue.name + ' - ' + packValue.cost, packValue.expand ? 'folder-open' : 'folder-collapsed', {'cartridge_topic' : 1, 'pack_ref' : packValue.ref, 'expand' : 1})}} +
+ + {{if packValue.expand}} +
+
+ {{if packValue.random}} + Contains any {{:packValue.random}} of:
+ {{/if}} + + {{for packValue.manifest :manifestElem:manifestIndex}} + {{:manifestElem}}
+ {{/for}} +
+ +
+ {{:helper.link('Request', 'cart', {'cartridge_topic' : 1, 'pack_ref' : packValue.ref, 'request' : 1, 'user' : data.user})}} +
+
+
+ {{/if}} + {{/if}} + {{/for}} + {{/if}} +{{/if}} \ No newline at end of file