diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index 3c0e190427..2e14fb96eb 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -6,6 +6,7 @@ #define OXY "oxy" #define CLONE "clone" #define HALLOSS "halloss" +#define ELECTROCUTE "electrocute" #define CUT "cut" #define BRUISE "bruise" @@ -56,3 +57,4 @@ #define INFECTION_LEVEL_ONE 100 #define INFECTION_LEVEL_TWO 500 #define INFECTION_LEVEL_THREE 1000 +#define INFECTION_LEVEL_MAX 1500 \ No newline at end of file diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm index a79bf09d95..a33adbae29 100644 --- a/code/datums/autolathe/arms.dm +++ b/code/datums/autolathe/arms.dm @@ -298,6 +298,15 @@ name = "speedloader (.38 rubber)" path =/obj/item/ammo_magazine/s38/rubber +/datum/category_item/autolathe/arms/speedloader_45 + name = "speedloader (.45)" + path = /obj/item/ammo_magazine/s45 + hidden = 1 + +/datum/category_item/autolathe/arms/speedloader_45r + name = "speedloader (.45 rubber)" + path = /obj/item/ammo_magazine/s45/rubber + // Commented out until metal exploits with autolathe is fixed. /*/datum/category_item/autolathe/arms/pistol_clip_45 name = "ammo clip (.45)" diff --git a/code/datums/supplypacks/contraband.dm b/code/datums/supplypacks/contraband.dm index cbe52301df..d600c2969c 100644 --- a/code/datums/supplypacks/contraband.dm +++ b/code/datums/supplypacks/contraband.dm @@ -63,11 +63,13 @@ /obj/item/clothing/suit/storage/vest/heavy/merc, /obj/item/clothing/glasses/night, /obj/item/weapon/storage/box/anti_photons, - /obj/item/ammo_magazine/clip/c12g/pellet, /obj/item/ammo_magazine/clip/c12g + /obj/item/ammo_magazine/clip/c12g/pellet, + /obj/item/ammo_magazine/clip/c12g ), list( //the doc, /obj/item/weapon/storage/firstaid/combat, - /obj/item/weapon/gun/projectile/dartgun, /obj/item/weapon/reagent_containers/hypospray, + /obj/item/weapon/gun/projectile/dartgun, + /obj/item/weapon/reagent_containers/hypospray, /obj/item/weapon/reagent_containers/glass/bottle/chloralhydrate, /obj/item/weapon/reagent_containers/glass/bottle/cyanide, /obj/item/ammo_magazine/chemdart diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm index bd16322e20..efa5c454f2 100644 --- a/code/datums/supplypacks/engineering.dm +++ b/code/datums/supplypacks/engineering.dm @@ -21,6 +21,48 @@ containertype = /obj/structure/closet/crate/engineering containername = "Superconducting Magnetic Coil crate" +/datum/supply_packs/eng/shield_capacitor + name = "Shield Capacitor" + contains = list(/obj/machinery/shield_capacitor) + cost = 20 + containertype = /obj/structure/closet/crate/engineering + containername = "shield capacitor crate" + +/datum/supply_packs/eng/shield_capacitor/advanced + name = "Advanced Shield Capacitor" + contains = list(/obj/machinery/shield_capacitor/advanced) + cost = 30 + containertype = /obj/structure/closet/crate/engineering + containername = "advanced shield capacitor crate" + +/datum/supply_packs/eng/bubble_shield + name = "Bubble Shield Generator" + contains = list(/obj/machinery/shield_gen) + cost = 40 + containertype = /obj/structure/closet/crate/engineering + containername = "shield bubble generator crate" + +/datum/supply_packs/eng/bubble_shield/advanced + name = "Advanced Bubble Shield Generator" + contains = list(/obj/machinery/shield_gen/advanced) + cost = 60 + containertype = /obj/structure/closet/crate/engineering + containername = "advanced bubble shield generator crate" + +/datum/supply_packs/eng/hull_shield + name = "Hull Shield Generator" + contains = list(/obj/machinery/shield_gen/external) + cost = 80 + containertype = /obj/structure/closet/crate/engineering + containername = "shield hull generator crate" + +/datum/supply_packs/eng/hull_shield/advanced + name = "Advanced Hull Shield Generator" + contains = list(/obj/machinery/shield_gen/external/advanced) + cost = 120 + containertype = /obj/structure/closet/crate/engineering + containername = "advanced hull shield generator crate" + /datum/supply_packs/eng/electrical name = "Electrical maintenance crate" contains = list( diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm index b4d51ed1b5..fef3f3e350 100644 --- a/code/datums/supplypacks/medical.dm +++ b/code/datums/supplypacks/medical.dm @@ -119,7 +119,7 @@ /obj/item/weapon/storage/belt/medical, /obj/item/device/radio/headset/heads/cmo, /obj/item/clothing/under/rank/chief_medical_officer, - /obj/item/weapon/reagent_containers/hypospray, + /obj/item/weapon/reagent_containers/hypospray/vial, /obj/item/clothing/accessory/stethoscope, /obj/item/clothing/glasses/hud/health, /obj/item/clothing/suit/storage/toggle/labcoat/cmo, diff --git a/code/datums/supplypacks/voidsuits.dm b/code/datums/supplypacks/voidsuits.dm index 658ed5562f..dda9aa4ed4 100644 --- a/code/datums/supplypacks/voidsuits.dm +++ b/code/datums/supplypacks/voidsuits.dm @@ -142,7 +142,7 @@ /obj/item/clothing/shoes/magboots = 2, /obj/item/weapon/tank/oxygen = 2 ) - cost = 50 + cost = 60 containertype = "/obj/structure/closet/crate/secure" containername = "Vey-Med Medical voidsuit crate" access = access_medical_equip diff --git a/code/datums/uplink/ammunition.dm b/code/datums/uplink/ammunition.dm index d644a9eaa8..c0b7600aad 100644 --- a/code/datums/uplink/ammunition.dm +++ b/code/datums/uplink/ammunition.dm @@ -22,6 +22,14 @@ name = "Pistol Magazine (.45 AP)" path = /obj/item/ammo_magazine/m45/ap +/datum/uplink_item/item/ammo/s45m + name = "Speedloader (.45)" + path = /obj/item/ammo_magazine/s45 + +/datum/uplink_item/item/ammo/s45map + name = "Speedloader (.45 AP)" + path = /obj/item/ammo_magazine/s45/ap + /datum/uplink_item/item/ammo/tommymag name = "Tommygun Magazine (.45)" path = /obj/item/ammo_magazine/m45tommy diff --git a/code/game/antagonist/station/thug.dm b/code/game/antagonist/station/thug.dm index 54f5f83663..2ea752e3b7 100644 --- a/code/game/antagonist/station/thug.dm +++ b/code/game/antagonist/station/thug.dm @@ -13,5 +13,5 @@ var/datum/antagonist/thug/thugs Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \ and before taking extreme actions, please try to also contact the administration! \ Think through your actions and make the roleplay immersive! Please remember all \ - rules aside from those without explicit exceptions apply to antagonists." - flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE \ No newline at end of file + rules aside from those with explicit exceptions apply to antagonists." + flags = ANTAG_SUSPICIOUS | ANTAG_IMPLANT_IMMUNE | ANTAG_RANDSPAWN | ANTAG_VOTABLE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index b7210f22a3..e4bd3b85ea 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1,6 +1,6 @@ /atom/movable layer = 3 - appearance_flags = TILE_BOUND + appearance_flags = TILE_BOUND|PIXEL_SCALE var/last_move = null var/anchored = 0 // var/elevation = 2 - not used anywhere @@ -15,7 +15,7 @@ var/moved_recently = 0 var/mob/pulledby = null var/item_state = null // Used to specify the item state for the on-mob overlays. - + var/icon_scale = 1 // Used to scale icons up or down in update_transform(). var/auto_init = 1 /atom/movable/New() @@ -296,3 +296,12 @@ return null return text2num(pickweight(candidates)) +/atom/movable/proc/update_transform() + var/matrix/M = matrix() + M.Scale(icon_scale) + src.transform = M + +// Use this to set the object's scale. +/atom/movable/proc/adjust_scale(new_scale) + icon_scale = new_scale + update_transform() diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index e54eb3c1cd..022366c865 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -4,6 +4,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E var/list/datum/absorbed_dna/absorbed_dna = list() var/list/absorbed_languages = list() // Necessary because of set_species stuff var/absorbedcount = 0 + var/lingabsorbedcount = 1 //Starts at one, because that's us var/chem_charges = 20 var/chem_recharge_rate = 0.5 var/chem_storage = 50 @@ -11,8 +12,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E var/changelingID = "Changeling" var/geneticdamage = 0 var/isabsorbing = 0 - var/geneticpoints = 5 - var/max_geneticpoints = 5 + var/geneticpoints = 7 + var/max_geneticpoints = 7 var/readapts = 1 var/max_readapts = 2 var/list/purchased_powers = list() @@ -219,7 +220,11 @@ turf/proc/AdjacentTurfsRangedSting() victims += C var/mob/living/carbon/T = input(src, "Who will we sting?") as null|anything in victims - if(!T) return + if(!T) + return + if(T.isSynthetic()) + src << "We are unable to pierce the outer shell of [T]." + return if(!(T in view(changeling.sting_range))) return if(!sting_can_reach(T, changeling.sting_range)) return if(!changeling_power(required_chems)) return diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 396e6faf34..0af67b22ed 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -90,16 +90,23 @@ continue absorbDNA(dna_data) changeling.absorbedcount++ + T.mind.changeling.absorbed_dna.len = 1 - changeling.geneticpoints += 5 - changeling.max_geneticpoints += 5 + // This is where lings get boosts from eating eachother + if(T.mind.changeling.lingabsorbedcount) + for(var/a = 1 to T.mind.changeling.lingabsorbedcount) + changeling.lingabsorbedcount++ + changeling.geneticpoints += 4 + changeling.max_geneticpoints += 4 + src << "We absorbed another changeling, and we grow stronger. Our genomes increase." T.mind.changeling.chem_charges = 0 T.mind.changeling.geneticpoints = -1 T.mind.changeling.max_geneticpoints = -1 //To prevent revival. T.mind.changeling.absorbedcount = 0 + T.mind.changeling.lingabsorbedcount = 0 changeling.absorbedcount++ changeling.isabsorbing = 0 diff --git a/code/game/gamemodes/changeling/powers/armblade.dm b/code/game/gamemodes/changeling/powers/armblade.dm index 139950e900..5ab724789b 100644 --- a/code/game/gamemodes/changeling/powers/armblade.dm +++ b/code/game/gamemodes/changeling/powers/armblade.dm @@ -134,4 +134,5 @@ /obj/item/weapon/melee/changeling/claw/greater name = "hand greatclaw" force = 20 - armor_penetration = 20 \ No newline at end of file + armor_penetration = 20 + pry = 1 \ No newline at end of file diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index ca1d5639e9..8db7a49255 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -123,7 +123,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," if(word1 == cultwords["hell"] && word2 == cultwords["join"] && word3 == cultwords["self"]) return tearreality() if(word1 == cultwords["destroy"] && word2 == cultwords["see"] && word3 == cultwords["technology"]) - return emp(src.loc,3) + return emp(src.loc,5) if(word1 == cultwords["travel"] && word2 == cultwords["blood"] && word3 == cultwords["self"]) return drain() if(word1 == cultwords["see"] && word2 == cultwords["hell"] && word3 == cultwords["join"]) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 48f0f02bfc..65ad3d7f01 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -7,8 +7,8 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' /datum/game_mode/heist name = "Heist" config_tag = "heist" - required_players = 9 - required_players_secret = 9 + required_players = 12 + required_players_secret = 12 required_enemies = 3 round_description = "An unidentified bluespace signature is approaching the station!" extended_round_description = "The Company's majority control of phoron in the system has marked the \ diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index e85af7e82b..f7233c1266 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -12,8 +12,8 @@ var/list/nuke_disks = list() colony of sizable population and considerable wealth causes it to often be the target of various \ attempts of robbery, fraud and other malicious actions." config_tag = "mercenary" - required_players = 9 - required_players_secret = 9 + required_players = 12 + required_players_secret = 12 required_enemies = 3 end_on_antag_death = 0 var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 39d3f739d7..850f061250 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -440,7 +440,7 @@ datum/objective/steal "a chief medical officer's jumpsuit" = /obj/item/clothing/under/rank/chief_medical_officer, "a head of security's jumpsuit" = /obj/item/clothing/under/rank/head_of_security, "a head of personnel's jumpsuit" = /obj/item/clothing/under/rank/head_of_personnel, - "the hypospray" = /obj/item/weapon/reagent_containers/hypospray, + "the hypospray" = /obj/item/weapon/reagent_containers/hypospray/vial, "the colony director's pinpointer" = /obj/item/weapon/pinpointer, "an ablative armor vest" = /obj/item/clothing/suit/armor/laserproof, ) diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index f74b1d6185..a0ac2f646c 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -74,7 +74,7 @@ var/global/datum/controller/occupations/job_master proc/FreeRole(var/rank) //making additional slot on the fly var/datum/job/job = GetJob(rank) - if(job && job.current_positions >= job.total_positions && job.total_positions != -1) + if(job && job.total_positions != -1) job.total_positions++ return 1 return 0 diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 50d6988e35..4daf8392de 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -55,31 +55,31 @@ if(shocked) shock(user, 50) - - var/dat = "

Autolathe Control Panel


" + var/list/dat = list() + dat += "

Autolathe Control Panel


" if(!disabled) dat += "" - var/material_top = "" - var/material_bottom = "" + var/list/material_top = list("") + var/list/material_bottom = list("") for(var/material in stored_material) material_top += "" material_bottom += "" - dat += "[material_top][material_bottom]
[material][stored_material[material]]/[storage_capacity[material]]

" + dat += "[material_top.Join()][material_bottom.Join()]
" dat += "

Printable Designs

Showing: [current_category].

" for(var/datum/category_item/autolathe/R in current_category.items) if(R.hidden && !hacked) continue var/can_make = 1 - var/material_string = "" - var/multiplier_string = "" + var/list/material_string = list() + var/list/multiplier_string = list() var/max_sheets var/comma if(!R.resources || !R.resources.len) - material_string = "No resources required." + material_string += "No resources required." else //Make sure it's buildable and list requires resources. for(var/material in R.resources) @@ -98,12 +98,12 @@ if(R.is_stack) if(max_sheets && max_sheets > 0) max_sheets = min(max_sheets, R.max_stack) // Limit to the max allowed by stack type. - multiplier_string += "
" + multiplier_string += "
" for(var/i = 5;i*" : ""][can_make ? "" : ""][R.name][can_make ? "" : ""][R.hidden ? "*" : ""][multiplier_string]" + dat += "" dat += "
[material_string]
[R.hidden ? "*" : ""][can_make ? "" : ""][R.name][can_make ? "" : ""][R.hidden ? "*" : ""][multiplier_string.Join()][material_string.Join()]

" //Hacking. @@ -113,7 +113,7 @@ dat += "
" - user << browse(dat, "window=autolathe") + user << browse(dat.Join(), "window=autolathe") onclose(user, "autolathe") /obj/machinery/autolathe/attackby(var/obj/item/O as obj, var/mob/user as mob) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index acd7a446c1..9b01f7b6bd 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -127,6 +127,36 @@ icon = 'icons/obj/doors/Doormaint.dmi' assembly_type = /obj/structure/door_assembly/door_assembly_mai +/obj/machinery/door/airlock/maintenance/cargo + icon = 'icons/obj/doors/Doormaint_cargo.dmi' + req_one_access = list(access_cargo) + +/obj/machinery/door/airlock/maintenance/command + icon = 'icons/obj/doors/Doormaint_command.dmi' + req_one_access = list(access_heads) + +/obj/machinery/door/airlock/maintenance/common + icon = 'icons/obj/doors/Doormaint_common.dmi' + +/obj/machinery/door/airlock/maintenance/engi + icon = 'icons/obj/doors/Doormaint_engi.dmi' + req_one_access = list(access_engine) + +/obj/machinery/door/airlock/maintenance/int + icon = 'icons/obj/doors/Doormaint_int.dmi' + +/obj/machinery/door/airlock/maintenance/medical + icon = 'icons/obj/doors/Doormaint_med.dmi' + req_one_access = list(access_medical) + +/obj/machinery/door/airlock/maintenance/rnd + icon = 'icons/obj/doors/Doormaint_rnd.dmi' + req_one_access = list(access_research) + +/obj/machinery/door/airlock/maintenance/sec + icon = 'icons/obj/doors/Doormaint_sec.dmi' + req_one_access = list(access_security) + /obj/machinery/door/airlock/external name = "External Airlock" icon = 'icons/obj/doors/Doorext.dmi' diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm index 45501a3de7..434f7e64cb 100644 --- a/code/game/machinery/doors/multi_tile.dm +++ b/code/game/machinery/doors/multi_tile.dm @@ -2,15 +2,44 @@ /obj/machinery/door/airlock/multi_tile width = 2 appearance_flags = 0 + var/obj/machinery/filler_object/filler1 + var/obj/machinery/filler_object/filler2 /obj/machinery/door/airlock/multi_tile/New() ..() SetBounds() + if(opacity) + create_fillers() + +/obj/machinery/door/airlock/multi_tile/Destroy() + qdel_null(filler1) + qdel_null(filler2) + return ..() /obj/machinery/door/airlock/multi_tile/Move() . = ..() SetBounds() +/obj/machinery/door/airlock/multi_tile/open() + . = ..() + + if(filler1) + filler1.set_opacity(opacity) + if(filler2) + filler2.set_opacity(opacity) + + return . + +/obj/machinery/door/airlock/multi_tile/close() + . = ..() + + if(filler1) + filler1.set_opacity(opacity) + if(filler2) + filler2.set_opacity(opacity) + + return . + /obj/machinery/door/airlock/multi_tile/proc/SetBounds() if(dir in list(EAST, WEST)) bound_width = width * world.icon_size @@ -19,9 +48,35 @@ bound_width = world.icon_size bound_height = width * world.icon_size +/obj/machinery/door/airlock/multi_tile/proc/create_fillers() + if(src.dir > 3) + filler1 = new/obj/machinery/filler_object (src.loc) + filler2 = new/obj/machinery/filler_object (get_step(src,EAST)) + else + filler1 = new/obj/machinery/filler_object (src.loc) + filler2 = new/obj/machinery/filler_object (get_step(src,NORTH)) + filler1.density = 0 + filler2.density = 0 + filler1.set_opacity(opacity) + filler2.set_opacity(opacity) + /obj/machinery/door/airlock/multi_tile/glass name = "Glass Airlock" icon = 'icons/obj/doors/Door2x1glass.dmi' opacity = 0 glass = 1 assembly_type = /obj/structure/door_assembly/multi_tile + +/obj/machinery/door/airlock/multi_tile/metal + name = "Airlock" + icon = 'icons/obj/doors/Door2x1metal.dmi' + assembly_type = /obj/structure/door_assembly/multi_tile + +/obj/machinery/filler_object + name = "" + icon = 'icons/obj/doors/rapid_pdoor.dmi' + icon_state = "" + density = 0 + +/obj/machinery/door/airlock/multi_tile/metal/mait + icon = 'icons/obj/doors/Door2x1_Maint.dmi' diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 96ab5eab20..87077b68db 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -289,3 +289,27 @@ if(!usr.incapacitated()) return go_in(usr) + +/obj/machinery/recharge_station/ghost_pod_recharger + name = "drone pod" + desc = "This is a pod which used to contain a drone... Or maybe it still does?" + icon = 'icons/obj/structures.dmi' + +/obj/machinery/recharge_station/ghost_pod_recharger/update_icon() + ..() + if(stat & BROKEN) + icon_state = "borg_pod_closed" + desc = "It appears broken..." + return + + if(occupant) + if((stat & NOPOWER) && !has_cell_power()) + icon_state = "borg_pod_closed" + desc = "It appears to be unpowered..." + else + icon_state = "borg_pod_closed" + else + icon_state = "borg_pod_opened" + + if(icon_update_tick == 0) + build_overlays() \ No newline at end of file diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 30a0743e09..7f76bc978c 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -640,7 +640,7 @@ name = "Nonstandard suit cycler" model_text = "Nonstandard" req_access = list(access_syndicate) - departments = list("Mercenary") + departments = list("Mercenary", "Charring") can_repair = 1 /obj/machinery/suit_cycler/attack_ai(mob/user as mob) @@ -752,7 +752,7 @@ //Clear the access reqs, disable the safeties, and open up all paintjobs. user << "You run the sequencer across the interface, corrupting the operating protocols." - departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Crowd Control","Emergency Medical Response","^%###^%$") + departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Crowd Control","Emergency Medical Response","^%###^%$", "Charring") species = list("Human","Tajara","Skrell","Unathi", "Teshari") emagged = 1 @@ -1073,6 +1073,15 @@ suit.name = "blood-red voidsuit" suit.item_state = "syndie_voidsuit" suit.icon_state = "rig-syndie" + if("Charring") + if(helmet) + helmet.name = "soot-covered voidsuit helmet" + helmet.icon_state = "rig0-firebug" + helmet.item_state = "rig0-firebug" + if(suit) + suit.name = "soot-covered voidsuit" + suit.item_state = "rig-firebug" + suit.icon_state = "rig-firebug" if(helmet) helmet.name = "refitted [helmet.name]" if(suit) suit.name = "refitted [suit.name]" diff --git a/code/game/machinery/vr_console.dm b/code/game/machinery/vr_console.dm new file mode 100644 index 0000000000..e21aa27c96 --- /dev/null +++ b/code/game/machinery/vr_console.dm @@ -0,0 +1,222 @@ +/obj/machinery/vr_sleeper + name = "VR sleeper" + desc = "A fancy bed with built-in sensory I/O ports and connectors to interface users' minds with their bodies in virtual reality." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "syndipod_0" + density = 1 + anchored = 1 + circuit = /obj/item/weapon/circuitboard/vr_sleeper + var/mob/living/carbon/human/occupant = null + var/mob/living/carbon/human/avatar = null + var/datum/mind/vr_mind = null + + use_power = 1 + idle_power_usage = 15 + active_power_usage = 200 + light_color = "#FF0000" + +/obj/machinery/vr_sleeper/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/stack/material/glass/reinforced(src, 2) + + RefreshParts() + +/obj/machinery/vr_sleeper/initialize() + update_icon() + +/obj/machinery/vr_sleeper/process() + if(stat & (NOPOWER|BROKEN)) + return + +/obj/machinery/vr_sleeper/update_icon() + icon_state = "syndipod_[occupant ? "1" : "0"]" + +/obj/machinery/vr_sleeper/Topic(href, href_list) + if(..()) + return 1 + + if(usr == occupant) + to_chat(usr, "You can't reach the controls from the inside.") + return + + add_fingerprint(usr) + + if(href_list["eject"]) + go_out() + + return 1 + +/obj/machinery/vr_sleeper/attackby(var/obj/item/I, var/mob/user) + add_fingerprint(user) + if(default_deconstruction_screwdriver(user, I)) + return + else if(default_deconstruction_crowbar(user, I)) + return + + +/obj/machinery/vr_sleeper/MouseDrop_T(var/mob/target, var/mob/user) + if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !isliving(target)) + return + go_in(target, user) + + + +/obj/machinery/sleeper/relaymove(var/mob/user) + ..() + if(usr.incapacitated()) + return + go_out() + + + +/obj/machinery/vr_sleeper/emp_act(var/severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + + if(occupant) + // This will eject the user from VR + // ### Fry the brain? + go_out() + + ..(severity) + +/obj/machinery/vr_sleeper/verb/eject() + set src in oview(1) + set category = "Object" + set name = "Eject VR Capsule" + + if(usr.incapacitated()) + return + + if(usr != occupant && avatar && alert(avatar, "Someone wants to remove you from virtual reality. Do you want to leave?", "Leave VR?", "Yes", "No") == "No") + return + + // The player in VR is fine with leaving, kick them out and reset avatar + avatar.exit_vr() + avatar = null + go_out() + add_fingerprint(usr) + +/obj/machinery/vr_sleeper/verb/climb_in() + set src in oview(1) + set category = "Object" + set name = "Enter VR Capsule" + + if(usr.incapacitated()) + return + go_in(usr, usr) + add_fingerprint(usr) + +/obj/machinery/vr_sleeper/relaymove(mob/user as mob) + if(user.incapacitated()) + return 0 //maybe they should be able to get out with cuffs, but whatever + go_out() + +/obj/machinery/vr_sleeper/proc/go_in(var/mob/M, var/mob/user) + if(!M) + return + if(stat & (BROKEN|NOPOWER)) + return + if(!ishuman(M)) + user << "\The [src] rejects [M] with a sharp beep." + if(occupant) + user << "\The [src] is already occupied." + return + + if(M == user) + visible_message("\The [user] starts climbing into \the [src].") + else + visible_message("\The [user] starts putting [M] into \the [src].") + + if(do_after(user, 20)) + if(occupant) + to_chat(user, "\The [src] is already occupied.") + return + M.stop_pulling() + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + update_use_power(2) + occupant = M + + update_icon() + + enter_vr() + return + +/obj/machinery/vr_sleeper/proc/go_out() + if(!occupant) + return + + if(occupant.client) + occupant.client.eye = occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + occupant.loc = src.loc + occupant = null + for(var/atom/movable/A in src) // In case an object was dropped inside or something + if(A == circuit) + continue + if(A in component_parts) + continue + A.loc = src.loc + update_use_power(1) + update_icon() + +/obj/machinery/vr_sleeper/proc/enter_vr() + + // No mob to transfer a mind from + if(!occupant) + return + + // No mind to transfer + if(!occupant.mind) + return + + // Mob doesn't have an active consciousness to send/receive from + if(occupant.stat != CONSCIOUS) + return + + avatar = occupant.vr_link + // If they've already enterred VR, and are reconnecting, prompt if they want a new body + if(avatar && alert(occupant, "You already have a Virtual Reality avatar. Would you like to use it?", "New avatar", "Yes", "No") == "No") + // Delink the mob + occupant.vr_link = null + avatar = null + + if(!avatar) + // Get the desired spawn location to put the body + var/S = null + var/list/vr_landmarks = list() + for(var/obj/effect/landmark/virtual_reality/sloc in landmarks_list) + vr_landmarks += sloc.name + + S = input(occupant, "Please select a location to spawn your avatar at:", "Spawn location") as null|anything in vr_landmarks + if(!S) + return 0 + + for(var/obj/effect/landmark/virtual_reality/i in landmarks_list) + if(i.name == S) + S = i + break + + avatar = new(S, "Virtual Reality Avatar") + // If the user has a non-default (Human) bodyshape, make it match theirs. + if(occupant.species.name != "Promethean" && occupant.species.name != "Human") + avatar.shapeshifter_change_shape(occupant.species.name) + avatar.forceMove(get_turf(S)) // Put the mob on the landmark, instead of inside it + avatar.Sleeping(1) + + occupant.enter_vr(avatar) + + // Prompt for username after they've enterred the body. + var/newname = sanitize(input(avatar, "You are enterring virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change") as null|text, MAX_NAME_LEN) + if (newname) + avatar.real_name = newname + + else + occupant.enter_vr(avatar) + diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index 547406aa1d..b8cb8006d2 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -107,6 +107,18 @@ return 1 +/obj/effect/landmark/virtual_reality + name = "virtual_reality" + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + anchored = 1.0 + +/obj/effect/landmark/virtual_reality/New() + ..() + tag = "virtual_reality*[name]" + invisibility = 101 + return 1 + //Costume spawner landmarks /obj/effect/landmark/costume/New() //costume spawner, selects a random subclass and disappears diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 6b4a09c6a5..8b00612641 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -80,6 +80,7 @@ var/list/sprite_sheets_obj = list() var/toolspeed = 1.0 // This is a multipler on how 'fast' a tool works. e.g. setting this to 0.5 will make the tool work twice as fast. + var/addblends // Icon overlay for ADD highlights when applicable. /obj/item/New() ..() diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 16e27006b4..a23abb5b06 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -59,7 +59,7 @@ //..() //Doesn't need to run the parent. Since when can fucking bodybags be welded shut? -Agouri return else if(istype(W, /obj/item/weapon/wirecutters)) - user << "You cut the tag off the bodybag" + to_chat(user, "You cut the tag off the bodybag") src.name = "body bag" src.overlays.Cut() return @@ -160,7 +160,7 @@ O.name = "used stasis bag" O.icon = src.icon O.icon_state = "bodybag_used" - O.desc = "Pretty useless now.." + O.desc = "Pretty useless now..." qdel(src) /obj/structure/closet/body_bag/cryobag/MouseDrop(over_object, src_location, over_location) @@ -211,9 +211,9 @@ /obj/structure/closet/body_bag/cryobag/examine(mob/user) ..() if(Adjacent(user)) //The bag's rather thick and opaque from a distance. - user << "You peer into \the [src]." + to_chat(user, "You peer into \the [src].") if(syringe) - user << "It has a syringe added to it." + to_chat(user, "It has a syringe added to it.") for(var/mob/living/L in contents) L.examine(user) diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm index decb40d807..3f1c67aafb 100644 --- a/code/game/objects/items/devices/defib.dm +++ b/code/game/objects/items/devices/defib.dm @@ -374,7 +374,10 @@ // This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled /obj/item/weapon/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/user) if(!H.client && !H.teleop) - to_chat(find_dead_player(H.ckey, 1), "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived!") + for(var/mob/observer/dead/ghost in player_list) + if(ghost.mind == H.mind) + to_chat(ghost, "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)") + break //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process user.visible_message("\The [user] begins to place [src] on [H]'s chest.", "You begin to place [src] on [H]'s chest...") diff --git a/code/game/objects/items/devices/geiger.dm b/code/game/objects/items/devices/geiger.dm index 62cb9d9862..dbac918609 100644 --- a/code/game/objects/items/devices/geiger.dm +++ b/code/game/objects/items/devices/geiger.dm @@ -1,7 +1,7 @@ -#define RAD_LEVEL_LOW 5 //10 // Around the level at which radiation starts to become harmful -#define RAD_LEVEL_MODERATE 15 //15 -#define RAD_LEVEL_HIGH 50 //50 -#define RAD_LEVEL_VERY_HIGH 100 //100 +#define RAD_LEVEL_LOW 0.01 // Around the level at which radiation starts to become harmful +#define RAD_LEVEL_MODERATE 10 +#define RAD_LEVEL_HIGH 25 +#define RAD_LEVEL_VERY_HIGH 50 //Geiger counter //Rewritten version of TG's geiger counter @@ -19,7 +19,14 @@ /obj/item/device/geiger/New() processing_objects |= src +/obj/item/device/geiger/Destroy() + processing_objects -= src + return ..() + /obj/item/device/geiger/process() + get_radiation() + +/obj/item/device/geiger/proc/get_radiation() if(!scanning) return radiation_count = radiation_repository.get_rads_at_turf(get_turf(src)) @@ -27,12 +34,29 @@ /obj/item/device/geiger/examine(mob/user) ..(user) - to_chat(user, "[scanning ? "ambient" : "stored"] radiation level: [radiation_count ? radiation_count : "0"]Bq.") + get_radiation() + to_chat(user, "[scanning ? "Ambient" : "Stored"] radiation level: [radiation_count ? radiation_count : "0"]Bq.") + +/obj/item/device/geiger/rad_act(amount) + if(!amount || !scanning) + return FALSE + + if(amount > radiation_count) + radiation_count = amount + + var/sound = "geiger" + if(amount < 5) + sound = "geiger_weak" + playsound(src, sound, between(10, 10 + (radiation_count * 4), 100), 0) + if(sound == "geiger_weak") // A weak geiger sound every two seconds sounds too infrequent. + spawn(1 SECOND) + playsound(src, sound, between(10, 10 + (radiation_count * 4), 100), 0) + update_icon() /obj/item/device/geiger/attack_self(var/mob/user) scanning = !scanning update_icon() - to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] [src].") + to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] \the [src].") /obj/item/device/geiger/update_icon() if(!scanning) @@ -40,12 +64,18 @@ return 1 switch(radiation_count) - if(null) icon_state = "geiger_on_1" - if(-INFINITY to RAD_LEVEL_LOW) icon_state = "geiger_on_1" - if(RAD_LEVEL_LOW + 1 to RAD_LEVEL_MODERATE) icon_state = "geiger_on_2" - if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH) icon_state = "geiger_on_3" - if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH) icon_state = "geiger_on_4" - if(RAD_LEVEL_VERY_HIGH + 1 to INFINITY) icon_state = "geiger_on_5" + if(null) + icon_state = "geiger_on_1" + if(-INFINITY to RAD_LEVEL_LOW) + icon_state = "geiger_on_1" + if(RAD_LEVEL_LOW to RAD_LEVEL_MODERATE) + icon_state = "geiger_on_2" + if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH) + icon_state = "geiger_on_3" + if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH) + icon_state = "geiger_on_4" + if(RAD_LEVEL_VERY_HIGH to INFINITY) + icon_state = "geiger_on_5" #undef RAD_LEVEL_LOW #undef RAD_LEVEL_MODERATE diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 53d647a4f0..ca4b8d8066 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -8,7 +8,7 @@ var/spamcheck = 0 var/emagged = 0 var/insults = 0 - var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TATER!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "FOR THE SYNDICATE!") + var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TERRORIST!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "GLORY TO ALMACH!") /obj/item/device/megaphone/attack_self(mob/living/user as mob) if (user.client) diff --git a/code/game/objects/items/gunbox.dm b/code/game/objects/items/gunbox.dm new file mode 100644 index 0000000000..add1530ca4 --- /dev/null +++ b/code/game/objects/items/gunbox.dm @@ -0,0 +1,19 @@ +/obj/item/gunbox + name = "detective's gun box" + desc = "A secure box containing a Detective's sidearm." + icon = 'icons/obj/storage.dmi' + icon_state = "gunbox" + w_class = ITEMSIZE_HUGE + +/obj/item/gunbox/attack_self(mob/living/user) + var/list/options = list() + options[".45 Pistol"] = list(/obj/item/weapon/gun/projectile/colt/detective, /obj/item/ammo_magazine/m45/rubber, /obj/item/ammo_magazine/m45/rubber) + options[".45 Revolver"] = list(/obj/item/weapon/gun/projectile/revolver/detective45, /obj/item/ammo_magazine/s45/rubber, /obj/item/ammo_magazine/s45/rubber) + var/choice = input(user,"Would you prefer a pistol or a revolver?") as null|anything in options + if(src && choice) + var/list/things_to_spawn = options[choice] + for(var/new_type in things_to_spawn) // Spawn all the things, the gun and the ammo. + var/atom/movable/AM = new new_type(get_turf(src)) + if(istype(AM, /obj/item/weapon/gun)) + to_chat(user, "You have chosen \the [AM]. Say hello to your new friend.") + qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index dde2f168b0..d878dd74fe 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -75,11 +75,11 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open) - user << "The [affecting.name] is cut open, you'll need more than a bandage!" + to_chat(user, "The [affecting.name] is cut open, you'll need more than a bandage!") return if(affecting.is_bandaged()) - user << "The wounds on [M]'s [affecting.name] have already been bandaged." + to_chat(user, "The wounds on [M]'s [affecting.name] have already been bandaged.") return 1 else user.visible_message("\The [user] starts treating [M]'s [affecting.name].", \ @@ -93,9 +93,13 @@ if(used == amount) break if(!do_mob(user, M, W.damage/5)) - user << "You must stand still to bandage wounds." + to_chat(user, "You must stand still to bandage wounds.") break + if(affecting.is_bandaged()) // We do a second check after the delay, in case it was bandaged after the first check. + to_chat(user, "The wounds on [M]'s [affecting.name] have already been bandaged.") + return 1 + if (W.current_stage <= W.max_bleeding_stage) user.visible_message("\The [user] bandages \a [W.desc] on [M]'s [affecting.name].", \ "You bandage \a [W.desc] on [M]'s [affecting.name]." ) @@ -111,9 +115,9 @@ affecting.update_damages() if(used == amount) if(affecting.is_bandaged()) - user << "\The [src] is used up." + to_chat(user, "\The [src] is used up.") else - user << "\The [src] is used up, but there are more wounds to treat on \the [affecting.name]." + to_chat(user, "\The [src] is used up, but there are more wounds to treat on \the [affecting.name].") use(used) /obj/item/stack/medical/ointment @@ -135,17 +139,20 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open) - user << "The [affecting.name] is cut open, you'll need more than a bandage!" + to_chat(user, "The [affecting.name] is cut open, you'll need more than a bandage!") return if(affecting.is_salved()) - user << "The wounds on [M]'s [affecting.name] have already been salved." + to_chat(user, "The wounds on [M]'s [affecting.name] have already been salved.") return 1 else user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \ "You start salving the wounds on [M]'s [affecting.name]." ) if(!do_mob(user, M, 10)) - user << "You must stand still to salve wounds." + to_chat(user, "You must stand still to salve wounds.") + return 1 + if(affecting.is_salved()) // We do a second check after the delay, in case it was bandaged after the first check. + to_chat(user, "The wounds on [M]'s [affecting.name] have already been salved.") return 1 user.visible_message("[user] salved wounds on [M]'s [affecting.name].", \ "You salved wounds on [M]'s [affecting.name]." ) @@ -169,11 +176,11 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open) - user << "The [affecting.name] is cut open, you'll need more than a bandage!" + to_chat(user, "The [affecting.name] is cut open, you'll need more than a bandage!") return if(affecting.is_bandaged() && affecting.is_disinfected()) - user << "The wounds on [M]'s [affecting.name] have already been treated." + to_chat(user, "The wounds on [M]'s [affecting.name] have already been treated.") return 1 else user.visible_message("\The [user] starts treating [M]'s [affecting.name].", \ @@ -187,8 +194,11 @@ if(used == amount) break if(!do_mob(user, M, W.damage/5)) - user << "You must stand still to bandage wounds." + to_chat(user, "You must stand still to bandage wounds.") break + if(affecting.is_bandaged() && affecting.is_disinfected()) // We do a second check after the delay, in case it was bandaged after the first check. + to_chat(user, "The wounds on [M]'s [affecting.name] have already been bandaged.") + return 1 if (W.current_stage <= W.max_bleeding_stage) user.visible_message("\The [user] cleans \a [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue.", \ "You clean and seal \a [W.desc] on [M]'s [affecting.name]." ) @@ -205,9 +215,9 @@ affecting.update_damages() if(used == amount) if(affecting.is_bandaged()) - user << "\The [src] is used up." + to_chat(user, "\The [src] is used up.") else - user << "\The [src] is used up, but there are more wounds to treat on \the [affecting.name]." + to_chat(user, "\The [src] is used up, but there are more wounds to treat on \the [affecting.name].") use(used) /obj/item/stack/medical/advanced/ointment @@ -228,16 +238,19 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open) - user << "The [affecting.name] is cut open, you'll need more than a bandage!" + to_chat(user, "The [affecting.name] is cut open, you'll need more than a bandage!") if(affecting.is_salved()) - user << "The wounds on [M]'s [affecting.name] have already been salved." + to_chat(user, "The wounds on [M]'s [affecting.name] have already been salved.") return 1 else user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \ "You start salving the wounds on [M]'s [affecting.name]." ) if(!do_mob(user, M, 10)) - user << "You must stand still to salve wounds." + to_chat(user, "You must stand still to salve wounds.") + return 1 + if(affecting.is_salved()) // We do a second check after the delay, in case it was bandaged after the first check. + to_chat(user, "The wounds on [M]'s [affecting.name] have already been salved.") return 1 user.visible_message( "[user] covers wounds on [M]'s [affecting.name] with regenerative membrane.", \ "You cover wounds on [M]'s [affecting.name] with regenerative membrane." ) @@ -264,20 +277,23 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) var/limb = affecting.name if(!(affecting.organ_tag in splintable_organs)) - user << "You can't use \the [src] to apply a splint there!" + to_chat(user, "You can't use \the [src] to apply a splint there!") return if(affecting.splinted) - user << "[M]'s [limb] is already splinted!" + to_chat(user, "[M]'s [limb] is already splinted!") return if (M != user) user.visible_message("[user] starts to apply \the [src] to [M]'s [limb].", "You start to apply \the [src] to [M]'s [limb].", "You hear something being wrapped.") else if(( !user.hand && (affecting.organ_tag in list(BP_R_ARM, BP_R_HAND)) || \ user.hand && (affecting.organ_tag in list(BP_L_ARM, BP_L_HAND)) )) - user << "You can't apply a splint to the arm you're using!" + to_chat(user, "You can't apply a splint to the arm you're using!") return user.visible_message("[user] starts to apply \the [src] to their [limb].", "You start to apply \the [src] to your [limb].", "You hear something being wrapped.") if(do_after(user, 50, M)) + if(affecting.splinted) + to_chat(user, "[M]'s [limb] is already splinted!") + return if(M == user && prob(75)) user.visible_message("\The [user] fumbles [src].", "You fumble [src].", "You hear something being wrapped.") return diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index 95803696d4..63a0df6d32 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -6,6 +6,7 @@ icon_state = "nanopaste" origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) amount = 10 + toolspeed = 0.75 //Used in surgery, shouldn't be the same speed as a normal screwdriver on mechanical organ repair. w_class = ITEMSIZE_SMALL no_variants = FALSE @@ -14,12 +15,13 @@ return 0 if (istype(M,/mob/living/silicon/robot)) //Repairing cyborgs var/mob/living/silicon/robot/R = M - if (R.getBruteLoss() || R.getFireLoss() ) - R.adjustBruteLoss(-15) - R.adjustFireLoss(-15) - R.updatehealth() - use(1) - user.visible_message("\The [user] applied some [src] on [R]'s damaged areas.",\ + if (R.getBruteLoss() || R.getFireLoss()) + if(do_after(user,7 * toolspeed)) + R.adjustBruteLoss(-15) + R.adjustFireLoss(-15) + R.updatehealth() + use(1) + user.visible_message("\The [user] applied some [src] on [R]'s damaged areas.",\ "You apply some [src] at [R]'s damaged areas.") else user << "All [R]'s systems are nominal." @@ -28,14 +30,17 @@ var/mob/living/carbon/human/H = M var/obj/item/organ/external/S = H.get_organ(user.zone_sel.selecting) - if(S.open >= 2) - if (S && (S.robotic >= ORGAN_ROBOT)) - if(!S.get_damage()) - user << "Nothing to fix here." - else if(can_use(1)) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - S.heal_damage(15, 15, robo_repair = 1) - H.updatehealth() - use(1) - user.visible_message("\The [user] applies some nanite paste on [user != M ? "[M]'s [S.name]" : "[S]"] with [src].",\ - "You apply some nanite paste on [user == M ? "your" : "[M]'s"] [S.name].") + if (S && (S.robotic >= ORGAN_ROBOT)) + if(!S.get_damage()) + user << "Nothing to fix here." + else if(can_use(1)) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(S.open >= 2) + if(do_after(user,5 * toolspeed)) + S.heal_damage(20, 20, robo_repair = 1) + else if(do_after(user,5 * toolspeed)) + S.heal_damage(10,10, robo_repair =1) + H.updatehealth() + use(1) + user.visible_message("\The [user] applies some nanite paste on [user != M ? "[M]'s [S.name]" : "[S]"] with [src].",\ + "You apply some nanite paste on [user == M ? "your" : "[M]'s"] [S.name].") diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 6065d6a514..a79faa60d2 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -699,54 +699,6 @@ desc = "A \"Space Life\" brand Emergency Response Team Commander action figure." icon_state = "ert" -/obj/item/toy/therapy_red - name = "red therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is red." - icon = 'icons/obj/toy.dmi' - icon_state = "therapyred" - item_state = "egg4" // It's the red egg in items_left/righthand - w_class = ITEMSIZE_TINY - -/obj/item/toy/therapy_purple - name = "purple therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is purple." - icon = 'icons/obj/toy.dmi' - icon_state = "therapypurple" - item_state = "egg1" // It's the magenta egg in items_left/righthand - w_class = ITEMSIZE_TINY - -/obj/item/toy/therapy_blue - name = "blue therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is blue." - icon = 'icons/obj/toy.dmi' - icon_state = "therapyblue" - item_state = "egg2" // It's the blue egg in items_left/righthand - w_class = ITEMSIZE_TINY - -/obj/item/toy/therapy_yellow - name = "yellow therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is yellow." - icon = 'icons/obj/toy.dmi' - icon_state = "therapyyellow" - item_state = "egg5" // It's the yellow egg in items_left/righthand - w_class = ITEMSIZE_TINY - -/obj/item/toy/therapy_orange - name = "orange therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is orange." - icon = 'icons/obj/toy.dmi' - icon_state = "therapyorange" - item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless - w_class = ITEMSIZE_TINY - -/obj/item/toy/therapy_green - name = "green therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is green." - icon = 'icons/obj/toy.dmi' - icon_state = "therapygreen" - item_state = "egg3" // It's the green egg in items_left/righthand - w_class = ITEMSIZE_TINY - /* * Plushies */ @@ -800,9 +752,10 @@ //Small plushies. /obj/item/toy/plushie name = "generic small plush" - desc = "A very generic small plushie. It seems to not want to exist." + desc = "A small toy plushie. It's very cute." icon = 'icons/obj/toy.dmi' icon_state = "nymphplushie" + w_class = ITEMSIZE_TINY var/last_message = 0 /obj/item/toy/plushie/attack_self(mob/user as mob) @@ -815,9 +768,24 @@ else if (user.a_intent == I_GRAB) user.visible_message("\The [user] attempts to strangle [src]!","You attempt to strangle [src]!") else - user.visible_message("\The [user] pokes the [src].","You poke the [src].") + user.visible_message("\The [user] pokes [src].","You poke [src].") last_message = world.time +obj/item/toy/plushie/verb/rename_plushie() + set name = "Name Plushie" + set category = "Object" + set desc = "Give your plushie a cute name!" + w_class = ITEMSIZE_TINY + var/mob/M = usr + if(!M.mind) return 0 + + var/input = sanitizeSafe(input("What do you want to name the plushie?", ,""), MAX_NAME_LEN) + + if(src && input && !M.stat && in_range(M,src)) + name = input + to_chat(M, "You name the plushie [input], giving it a hug for good luck.") + return 1 + /obj/item/toy/plushie/nymph name = "diona nymph plush" desc = "A plushie of an adorable diona nymph! While its level of self-awareness is still being debated, its level of cuteness is not." @@ -830,7 +798,7 @@ /obj/item/toy/plushie/kitten name = "kitten plush" - desc = "A plushie of a cute kitten! Watch as it purrs it's way right into your heart." + desc = "A plushie of a cute kitten! Watch as it purrs its way right into your heart." icon_state = "kittenplushie" /obj/item/toy/plushie/lizard @@ -848,6 +816,49 @@ desc = "A farwa plush doll. It's soft and comforting!" icon_state = "farwaplushie" +/obj/item/toy/plushie/therapy/red + name = "red therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is red." + icon = 'icons/obj/toy.dmi' + icon_state = "therapyred" + item_state = "egg4" // It's the red egg in items_left/righthand + +/obj/item/toy/plushie/therapy/purple + name = "purple therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is purple." + icon = 'icons/obj/toy.dmi' + icon_state = "therapypurple" + item_state = "egg1" // It's the magenta egg in items_left/righthand + +/obj/item/toy/plushie/therapy/blue + name = "blue therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is blue." + icon = 'icons/obj/toy.dmi' + icon_state = "therapyblue" + item_state = "egg2" // It's the blue egg in items_left/righthand + +/obj/item/toy/plushie/therapy/yellow + name = "yellow therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is yellow." + icon = 'icons/obj/toy.dmi' + icon_state = "therapyyellow" + item_state = "egg5" // It's the yellow egg in items_left/righthand + +/obj/item/toy/plushie/therapy/orange + name = "orange therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is orange." + icon = 'icons/obj/toy.dmi' + icon_state = "therapyorange" + item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless + +/obj/item/toy/plushie/therapy/green + name = "green therapy doll" + desc = "A toy for therapeutic and recreational purposes. This one is green." + icon = 'icons/obj/toy.dmi' + icon_state = "therapygreen" + item_state = "egg3" // It's the green egg in items_left/righthand + + //Toy cult sword /obj/item/toy/cultsword name = "foam sword" diff --git a/code/game/objects/items/weapons/circuitboards/frame.dm b/code/game/objects/items/weapons/circuitboards/frame.dm index fa48be65bb..3cbc54e855 100644 --- a/code/game/objects/items/weapons/circuitboards/frame.dm +++ b/code/game/objects/items/weapons/circuitboards/frame.dm @@ -202,6 +202,15 @@ /obj/item/weapon/reagent_containers/syringe = 3, /obj/item/stack/material/glass/reinforced = 2) +/obj/item/weapon/circuitboard/vr_sleeper + name = T_BOARD("VR sleeper") + build_path = /obj/machinery/vr_sleeper + board_type = new /datum/frame/frame_types/medical_pod + origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2) + req_components = list( + /obj/item/weapon/stock_parts/scanning_module = 1, + /obj/item/stack/material/glass/reinforced = 2) + /obj/item/weapon/circuitboard/dna_analyzer name = T_BOARD("dna analyzer") build_path = /obj/machinery/dnaforensics diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm index f075ea49f9..e0975361eb 100644 --- a/code/game/objects/items/weapons/id cards/station_ids.dm +++ b/code/game/objects/items/weapons/id cards/station_ids.dm @@ -373,8 +373,8 @@ job_access_type = /datum/job/bartender /obj/item/weapon/card/id/civilian/botanist - assignment = "Gardener" - rank = "Gardener" + assignment = "Botanist" + rank = "Botanist" job_access_type = /datum/job/hydro /obj/item/weapon/card/id/civilian/chaplain diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 2c56cd690b..045f910190 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -656,6 +656,61 @@ nextrefueltick = world.time + 10 reagents.add_reagent("fuel", 1) +/* + * Backpack Welder. + */ + +/obj/item/weapon/weldingtool/tubefed + name = "tube-fed welding tool" + desc = "A bulky, cooler-burning welding tool that draws from a worn welding tank." + icon_state = "tubewelder" + max_fuel = 10 + w_class = ITEMSIZE_NO_CONTAINER + matter = null + toolspeed = 1.25 + change_icons = 0 + flame_intensity = 1 + eye_safety_modifier = 1 + always_process = TRUE + var/obj/item/weapon/weldpack/mounted_pack = null + +/obj/item/weapon/weldingtool/tubefed/New(location) + ..() + if(istype(location, /obj/item/weapon/weldpack)) + var/obj/item/weapon/weldpack/holder = location + mounted_pack = holder + else + qdel(src) + +/obj/item/weapon/weldingtool/tubefed/Destroy() + mounted_pack.nozzle = null + mounted_pack = null + return ..() + +/obj/item/weapon/weldingtool/tubefed/process() + if(mounted_pack) + if(!istype(mounted_pack.loc,/mob/living/carbon/human)) + mounted_pack.return_nozzle() + else + var/mob/living/carbon/human/H = mounted_pack.loc + if(H.back != mounted_pack) + mounted_pack.return_nozzle() + + if(mounted_pack.loc != src.loc && src.loc != mounted_pack) + mounted_pack.return_nozzle() + visible_message("\The [src] retracts to its fueltank.") + + if(get_fuel() <= get_max_fuel()) + mounted_pack.reagents.trans_to_obj(src, 1) + + ..() + +/obj/item/weapon/weldingtool/tubefed/dropped(mob/user) + ..() + if(src.loc != user) + mounted_pack.return_nozzle() + to_chat(user, "\The [src] retracts to its fueltank.") + /* * Electric/Arc Welder */ diff --git a/code/game/objects/items/weapons/weldbackpack.dm b/code/game/objects/items/weapons/weldbackpack.dm index 6a6d77521e..0312ca55f8 100644 --- a/code/game/objects/items/weapons/weldbackpack.dm +++ b/code/game/objects/items/weapons/weldbackpack.dm @@ -6,46 +6,140 @@ icon_state = "welderpack" w_class = ITEMSIZE_LARGE var/max_fuel = 350 + var/obj/item/weapon/nozzle = null //Attached welder, or other spray device. + var/nozzle_attached = 0 /obj/item/weapon/weldpack/New() var/datum/reagents/R = new/datum/reagents(max_fuel) //Lotsa refills reagents = R R.my_atom = src R.add_reagent("fuel", max_fuel) + nozzle = new/obj/item/weapon/weldingtool/tubefed(src) + nozzle_attached = 1 + +/obj/item/weapon/weldpack/Destroy() + qdel(nozzle) + nozzle = null + return ..() + +/obj/item/weapon/weldpack/dropped(mob/user) + ..() + if(nozzle) + user.remove_from_mob(nozzle) + return_nozzle() + to_chat(user, "\The [nozzle] retracts to its fueltank.") + +/obj/item/weapon/weldpack/proc/get_nozzle(var/mob/living/user) + if(!ishuman(user)) + return 0 + + var/mob/living/carbon/human/H = user + + if(H.hands_are_full()) //Make sure our hands aren't full. + to_chat(H, "Your hands are full. Drop something first.") + return 0 + + var/obj/item/weapon/F = nozzle + H.put_in_hands(F) + nozzle_attached = 0 + + return 1 + +/obj/item/weapon/weldpack/proc/return_nozzle(var/mob/living/user) + nozzle.forceMove(src) + nozzle_attached = 1 /obj/item/weapon/weldpack/attackby(obj/item/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/weldingtool)) + if(istype(W, /obj/item/weapon/weldingtool) && !(W == nozzle)) var/obj/item/weapon/weldingtool/T = W if(T.welding & prob(50)) message_admins("[key_name_admin(user)] triggered a fueltank explosion.") log_game("[key_name(user)] triggered a fueltank explosion.") - user << "That was stupid of you." + to_chat(user,"That was stupid of you.") explosion(get_turf(src),-1,0,2) if(src) qdel(src) return - else + else if(T.status) if(T.welding) - user << "That was close!" + to_chat(user,"That was close!") src.reagents.trans_to_obj(W, T.max_fuel) - user << "Welder refilled!" + to_chat(user, "Welder refilled!") playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) return - user << "The tank scoffs at your insolence. It only provides services to welders." + else if(nozzle) + if(nozzle == W) + if(!user.unEquip(W)) + to_chat(user,"\The [W] seems to be stuck to your hand.") + return + if(!nozzle_attached) + return_nozzle() + to_chat(user,"You attach \the [W] to the [src].") + return + else + to_chat(user,"The [src] already has a nozzle!") + else + to_chat(user,"The tank scoffs at your insolence. It only provides services to welders.") return +/obj/item/weapon/weldpack/attack_hand(mob/user as mob) + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/wearer = user + if(wearer.back == src) + if(nozzle && nozzle_attached) + if(!wearer.incapacitated()) + get_nozzle(user) + else + to_chat(user,"\The [src] does not have a nozzle attached!") + else + ..() + else + ..() + /obj/item/weapon/weldpack/afterattack(obj/O as obj, mob/user as mob, proximity) if(!proximity) // this replaces and improves the get_dist(src,O) <= 1 checks used previously return if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume < max_fuel) O.reagents.trans_to_obj(src, max_fuel) - user << "You crack the cap off the top of the pack and fill it back up again from the tank." + to_chat(user,"You crack the cap off the top of the pack and fill it back up again from the tank.") playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) return else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && src.reagents.total_volume == max_fuel) - user << "The pack is already full!" + to_chat(user,"The pack is already full!") return +/obj/item/weapon/weldpack/MouseDrop(obj/over_object as obj) //This is terrifying. + if(!canremove) + return + + if (ishuman(usr) || issmall(usr)) //so monkeys can take off their backpacks -- Urist + + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech. why? + return + + if (!( istype(over_object, /obj/screen) )) + return ..() + + //makes sure that the thing is equipped, so that we can't drag it into our hand from miles away. + //there's got to be a better way of doing this. + if (!(src.loc == usr) || (src.loc && src.loc.loc == usr)) + return + + if (( usr.restrained() ) || ( usr.stat )) + return + + if ((src.loc == usr) && !(istype(over_object, /obj/screen)) && !usr.unEquip(src)) + return + + switch(over_object.name) + if("r_hand") + usr.u_equip(src) + usr.put_in_r_hand(src) + if("l_hand") + usr.u_equip(src) + usr.put_in_l_hand(src) + src.add_fingerprint(usr) + /obj/item/weapon/weldpack/examine(mob/user) ..(user) user << text("\icon[] [] units of fuel left!", src, src.reagents.total_volume) diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index c15b454878..11d13abe77 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -504,12 +504,12 @@ /obj/random/toy/item_to_spawn() return pick(/obj/item/toy/bosunwhistle, - /obj/item/toy/therapy_red, - /obj/item/toy/therapy_purple, - /obj/item/toy/therapy_blue, - /obj/item/toy/therapy_yellow, - /obj/item/toy/therapy_orange, - /obj/item/toy/therapy_green, + /obj/item/toy/plushie/therapy/red, + /obj/item/toy/plushie/therapy/purple, + /obj/item/toy/plushie/therapy/blue, + /obj/item/toy/plushie/therapy/yellow, + /obj/item/toy/plushie/therapy/orange, + /obj/item/toy/plushie/therapy/green, /obj/item/toy/cultsword, /obj/item/toy/katana, /obj/item/toy/snappop, @@ -1060,4 +1060,22 @@ var/list/multi_point_spawns /obj/item/clothing/suit/space/void/security/riot, /obj/item/clothing/head/helmet/space/void/security/riot ) + ) + +/obj/random/multiple/voidsuit/mining + name = "Random Mining Voidsuit" + desc = "This is a random mining voidsuit." + icon = 'icons/obj/clothing/suits.dmi' + icon_state = "rig-mining" + +/obj/random/multiple/voidsuit/mining/item_to_spawn() + return pick( + prob(5);list( + /obj/item/clothing/suit/space/void/mining, + /obj/item/clothing/head/helmet/space/void/mining + ), + prob(1);list( + /obj/item/clothing/suit/space/void/mining/alt, + /obj/item/clothing/head/helmet/space/void/mining/alt + ) ) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm index fe838a5291..0af7913df8 100644 --- a/code/game/objects/structures/crates_lockers/closets/fireaxe.dm +++ b/code/game/objects/structures/crates_lockers/closets/fireaxe.dm @@ -36,7 +36,7 @@ playsound(user, 'sound/machines/lockreset.ogg', 50, 1) if(do_after(user, 20 * O.toolspeed)) src.locked = 0 - user << " You disable the locking modules." + to_chat(user, " You disable the locking modules.") update_icon() return else if(istype(O, /obj/item/weapon)) @@ -50,7 +50,7 @@ else playsound(user, 'sound/effects/Glasshit.ogg', 100, 1) //We don't want this playing every time if(W.force < 15) - user << "The cabinet's protective glass glances off the hit." + to_chat(user, "The cabinet's protective glass glances off the hit.") else src.hitstaken++ if(src.hitstaken == 4) @@ -63,12 +63,14 @@ if (istype(O, /obj/item/weapon/material/twohanded/fireaxe) && src.localopened) if(!fireaxe) if(O:wielded) - user << "Unwield the axe first." - return + O:wielded = 0 + O.update_icon() + //to_chat(user, "Unwield the axe first.") + //return fireaxe = O user.remove_from_mob(O) src.contents += O - user << "You place the fire axe back in the [src.name]." + to_chat(user, "You place the fire axe back in the [src.name].") update_icon() else if(src.smashed) @@ -91,11 +93,11 @@ spawn(10) update_icon() return else - user << "Resetting circuitry..." + to_chat(user, "Resetting circuitry...") playsound(user, 'sound/machines/lockenable.ogg', 50, 1) if(do_after(user,20 * O.toolspeed)) src.locked = 1 - user << " You re-enable the locking modules." + to_chat(user, " You re-enable the locking modules.") return else localopened = !localopened @@ -116,13 +118,13 @@ hasaxe = 1 if(src.locked) - user <<"The cabinet won't budge!" + to_chat(user, "The cabinet won't budge!") return if(localopened) if(fireaxe) user.put_in_hands(fireaxe) fireaxe = null - user << "You take the fire axe from the [name]." + to_chat (user, "You take the fire axe from the [name].") src.add_fingerprint(user) update_icon() else @@ -149,7 +151,7 @@ attack_tk(mob/user as mob) if(localopened && fireaxe) fireaxe.forceMove(loc) - user << "You telekinetically remove the fire axe." + to_chat(user, "You telekinetically remove the fire axe.") fireaxe = null update_icon() return @@ -161,9 +163,9 @@ if (isrobot(usr) || src.locked || src.smashed) if(src.locked) - usr << "The cabinet won't budge!" + to_chat(usr, "The cabinet won't budge!") else if(src.smashed) - usr << "The protective glass is broken!" + to_chat(usr, "The protective glass is broken!") return localopened = !localopened @@ -180,23 +182,23 @@ if(fireaxe) usr.put_in_hands(fireaxe) fireaxe = null - usr << "You take the Fire axe from the [name]." + to_chat(usr, "You take the Fire axe from the [name].") else - usr << "The [src.name] is empty." + to_chat(usr, "The [src.name] is empty.") else - usr << "The [src.name] is closed." + to_chat(usr, "The [src.name] is closed.") update_icon() attack_ai(mob/user as mob) if(src.smashed) - user << "The security of the cabinet is compromised." + to_chat(user, "The security of the cabinet is compromised.") return else locked = !locked if(locked) - user << "Cabinet locked." + to_chat(user, "Cabinet locked.") else - user << "Cabinet unlocked." + to_chat(user, "Cabinet unlocked.") return update_icon() //Template: fireaxe[has fireaxe][is opened][hits taken][is smashed]. If you want the opening or closing animations, add "opening" or "closing" right after the numbers diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm index 92bc2ab469..9e5f0b7815 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -204,7 +204,7 @@ new /obj/item/device/radio/headset/heads/cmo(src) new /obj/item/device/radio/headset/heads/cmo/alt(src) new /obj/item/device/flash(src) - new /obj/item/weapon/reagent_containers/hypospray(src) + new /obj/item/weapon/reagent_containers/hypospray/vial(src) new /obj/item/clothing/suit/storage/hooded/wintercoat/medical(src) new /obj/item/clothing/shoes/boots/winter/medical(src) new /obj/item/weapon/storage/box/freezer(src) @@ -243,21 +243,17 @@ New() ..() - new /obj/item/clothing/under/rank/psych(src) - new /obj/item/clothing/under/rank/psych/turtleneck(src) - new /obj/item/clothing/suit/straight_jacket(src) - new /obj/item/weapon/reagent_containers/glass/bottle/stoxin(src) - new /obj/item/weapon/reagent_containers/syringe(src) - new /obj/item/weapon/storage/pill_bottle/citalopram(src) - new /obj/item/weapon/reagent_containers/pill/methylphenidate(src) - new /obj/item/weapon/clipboard(src) - new /obj/item/weapon/folder/white(src) - new /obj/item/device/taperecorder(src) - new /obj/item/device/tape/random(src) - new /obj/item/device/tape/random(src) - new /obj/item/device/tape/random(src) - new /obj/item/device/camera(src) - new /obj/item/toy/therapy_blue(src) + new /obj/item/weapon/storage/box/pillbottles(src) + new /obj/item/weapon/storage/box/pillbottles(src) + new /obj/item/weapon/storage/box/beakers(src) + new /obj/item/weapon/storage/box/autoinjectors(src) + new /obj/item/weapon/storage/box/syringes(src) + new /obj/item/weapon/reagent_containers/dropper(src) + new /obj/item/weapon/reagent_containers/dropper(src) + new /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline(src) + new /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline(src) + new /obj/item/weapon/reagent_containers/glass/bottle/antitoxin(src) + new /obj/item/weapon/reagent_containers/glass/bottle/antitoxin(src) return /obj/structure/closet/secure_closet/psych @@ -274,8 +270,21 @@ New() ..() - new /obj/item/weapon/storage/box/pillbottles(src) - new /obj/item/weapon/storage/box/pillbottles(src) + new /obj/item/clothing/under/rank/psych(src) + new /obj/item/clothing/under/rank/psych/turtleneck(src) + new /obj/item/clothing/suit/straight_jacket(src) + new /obj/item/weapon/reagent_containers/glass/bottle/stoxin(src) + new /obj/item/weapon/reagent_containers/syringe(src) + new /obj/item/weapon/storage/pill_bottle/citalopram(src) + new /obj/item/weapon/reagent_containers/pill/methylphenidate(src) + new /obj/item/weapon/clipboard(src) + new /obj/item/weapon/folder/white(src) + new /obj/item/device/taperecorder(src) + new /obj/item/device/tape/random(src) + new /obj/item/device/tape/random(src) + new /obj/item/device/tape/random(src) + new /obj/item/device/camera(src) + new /obj/item/toy/plushie/therapy/blue(src) return /obj/structure/closet/secure_closet/medical_wall diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index d863aecd24..83aa687957 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -276,15 +276,13 @@ ..() new /obj/item/clothing/accessory/badge/holo/detective(src) new /obj/item/clothing/gloves/black(src) + new /obj/item/gunbox(src) new /obj/item/weapon/storage/belt/detective(src) new /obj/item/weapon/storage/box/evidence(src) new /obj/item/device/radio/headset/headset_sec(src) new /obj/item/device/radio/headset/headset_sec/alt(src) new /obj/item/clothing/suit/storage/vest/detective(src) - new /obj/item/ammo_magazine/m45/rubber(src) - new /obj/item/ammo_magazine/m45/rubber(src) new /obj/item/taperoll/police(src) - new /obj/item/weapon/gun/projectile/colt/detective(src) new /obj/item/clothing/accessory/holster/armpit(src) new /obj/item/device/flashlight/maglight(src) new /obj/item/weapon/reagent_containers/food/drinks/flask/detflask(src) diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm new file mode 100644 index 0000000000..3bb158a576 --- /dev/null +++ b/code/game/objects/structures/fitness.dm @@ -0,0 +1,65 @@ +/obj/structure/fitness + icon = 'icons/obj/stationobjs.dmi' + anchored = 1 + var/being_used = 0 + +/obj/structure/fitness/punchingbag + name = "punching bag" + desc = "A punching bag." + icon_state = "punchingbag" + density = 1 + var/list/hit_message = list("hit", "punch", "kick", "robust") + +/obj/structure/fitness/punchingbag/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + ..() + return + if(user.nutrition < 20) + to_chat(user, "You need more energy to use the punching bag. Go eat something.") + else + if(user.a_intent == I_HURT) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + flick("[icon_state]_hit", src) + playsound(src.loc, 'sound/effects/woodhit.ogg', 25, 1, -1) + user.do_attack_animation(src) + user.nutrition = user.nutrition - 5 + to_chat(user, "You [pick(hit_message)] \the [src].") + +/obj/structure/fitness/weightlifter + name = "weightlifting machine" + desc = "A machine used to lift weights." + icon_state = "weightlifter" + var/weight = 1 + var/list/qualifiers = list("with ease", "without any trouble", "with great effort") + +/obj/structure/fitness/weightlifter/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/wrench)) + playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1) + weight = ((weight) % qualifiers.len) + 1 + to_chat(user, "You set the machine's weight level to [weight].") + +/obj/structure/fitness/weightlifter/attack_hand(var/mob/living/carbon/human/user) + if(!istype(user)) + return + if(user.loc != src.loc) + to_chat(user, "You must be on the weight machine to use it.") + return + if(user.nutrition < 50) + to_chat(user, "You need more energy to lift weights. Go eat something.") + return + if(being_used) + to_chat(user, "The weight machine is already in use by somebody else.") + return + else + being_used = 1 + playsound(src.loc, 'sound/effects/weightlifter.ogg', 50, 1) + user.set_dir(SOUTH) + flick("[icon_state]_[weight]", src) + if(do_after(user, 20 + (weight * 10))) + playsound(src.loc, 'sound/effects/weightdrop.ogg', 25, 1) + user.nutrition -= weight * 10 + to_chat(user, "You lift the weights [qualifiers[weight]].") + being_used = 0 + else + to_chat(user, "Against your previous judgement, perhaps working out is not for you.") + being_used = 0 diff --git a/code/game/objects/structures/ghost_pods/ghost_pods.dm b/code/game/objects/structures/ghost_pods/ghost_pods.dm index 7beba29caa..9eeefeee61 100644 --- a/code/game/objects/structures/ghost_pods/ghost_pods.dm +++ b/code/game/objects/structures/ghost_pods/ghost_pods.dm @@ -22,6 +22,8 @@ if(winner.len) var/mob/observer/dead/D = winner[1] create_occupant(D) + new /obj/machinery/recharge_station/ghost_pod_recharger(src.loc) + del(src) return TRUE else return FALSE @@ -29,7 +31,6 @@ // Override this to create whatever mob you need. Be sure to call ..() if you don't want it to make infinite mobs. /obj/structure/ghost_pod/proc/create_occupant(var/mob/M) used = TRUE - icon_state = icon_state_opened return TRUE diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 42ee6af2e3..c457e3ae2c 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -77,6 +77,9 @@ return return +/obj/structure/morgue/attack_robot(mob/user) + if(Adjacent(user)) + attack_hand(user) /obj/structure/morgue/attack_hand(mob/user as mob) if (src.connected) @@ -156,6 +159,10 @@ connected = null return ..() +/obj/structure/m_tray/attack_robot(mob/user) + if(Adjacent(user)) + attack_hand(user) + /obj/structure/m_tray/attack_hand(mob/user as mob) if (src.connected) for(var/atom/movable/A as mob|obj in src.loc) @@ -181,7 +188,7 @@ if (user != O) for(var/mob/B in viewers(user, 3)) if ((B.client && !( B.blinded ))) - B << "\The [user] stuffs [O] into [src]!" + to_chat(B, "\The [user] stuffs [O] into [src]!") return @@ -189,25 +196,16 @@ * Crematorium */ -/obj/structure/crematorium +/obj/structure/morgue/crematorium name = "crematorium" desc = "A human incinerator. Works well on barbeque nights." icon = 'icons/obj/stationobjs.dmi' icon_state = "crema1" - density = 1 - var/obj/structure/c_tray/connected = null - anchored = 1.0 var/cremating = 0 var/id = 1 var/locked = 0 -/obj/structure/crematorium/Destroy() - if(connected) - qdel(connected) - connected = null - return ..() - -/obj/structure/crematorium/proc/update() +/obj/structure/morgue/crematorium/update() if (src.connected) src.icon_state = "crema0" else @@ -217,37 +215,7 @@ src.icon_state = "crema1" return -/obj/structure/crematorium/ex_act(severity) - switch(severity) - if(1.0) - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.loc) - ex_act(severity) - qdel(src) - return - if(2.0) - if (prob(50)) - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.loc) - ex_act(severity) - qdel(src) - return - if(3.0) - if (prob(5)) - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.loc) - ex_act(severity) - qdel(src) - return - return - -/obj/structure/crematorium/attack_hand(mob/user as mob) -// if (cremating) AWW MAN! THIS WOULD BE SO MUCH MORE FUN ... TO WATCH -// user.show_message("Uh-oh, that was a bad idea.", 1) -// //usr << "Uh-oh, that was a bad idea." -// src:loc:poison += 20000000 -// src:loc:firelevel = src:loc:poison -// return +/obj/structure/morgue/crematorium/attack_hand(mob/user as mob) if (cremating) usr << "It's locked." return @@ -260,10 +228,10 @@ qdel(src.connected) else if (src.locked == 0) playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) - src.connected = new /obj/structure/c_tray( src.loc ) - step(src.connected, SOUTH) + src.connected = new /obj/structure/m_tray/c_tray( src.loc ) + step(src.connected, EAST) src.connected.layer = OBJ_LAYER - var/turf/T = get_step(src, SOUTH) + var/turf/T = get_step(src, EAST) if (T.contents.Find(src.connected)) src.connected.connected = src src.icon_state = "crema0" @@ -276,7 +244,7 @@ src.add_fingerprint(user) update() -/obj/structure/crematorium/attackby(P as obj, mob/user as mob) +/obj/structure/morgue/crematorium/attackby(P as obj, mob/user as mob) if (istype(P, /obj/item/weapon/pen)) var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text if (user.get_active_hand() != P) @@ -291,13 +259,13 @@ src.add_fingerprint(user) return -/obj/structure/crematorium/relaymove(mob/user as mob) +/obj/structure/morgue/crematorium/relaymove(mob/user as mob) if (user.stat || locked) return - src.connected = new /obj/structure/c_tray( src.loc ) - step(src.connected, SOUTH) + src.connected = new /obj/structure/m_tray/c_tray( src.loc ) + step(src.connected, EAST) src.connected.layer = OBJ_LAYER - var/turf/T = get_step(src, SOUTH) + var/turf/T = get_step(src, EAST) if (T.contents.Find(src.connected)) src.connected.connected = src src.icon_state = "crema0" @@ -309,25 +277,22 @@ src.connected = null return -/obj/structure/crematorium/proc/cremate(atom/A, mob/user as mob) -// for(var/obj/machinery/crema_switch/O in src) //trying to figure a way to call the switch, too drunk to sort it out atm -// if(var/on == 1) -// return +/obj/structure/morgue/crematorium/proc/cremate(atom/A, mob/user as mob) if(cremating) return //don't let you cremate something twice or w/e if(contents.len <= 0) for (var/mob/M in viewers(src)) - M.show_message("You hear a hollow crackle.", 1) + to_chat(M,"You hear a hollow crackle.") return else if(!isemptylist(src.search_contents_for(/obj/item/weapon/disk/nuclear))) - usr << "You get the feeling that you shouldn't cremate one of the items in the cremator." + to_chat(user,"You get the feeling that you shouldn't cremate one of the items in the cremator.") return for (var/mob/M in viewers(src)) - M.show_message("You hear a roar as the crematorium activates.", 1) + to_chat(M,"You hear a roar as the crematorium activates.") cremating = 1 locked = 1 @@ -363,51 +328,11 @@ /* * Crematorium tray */ -/obj/structure/c_tray +/obj/structure/m_tray/c_tray name = "crematorium tray" desc = "Apply body before burning." icon = 'icons/obj/stationobjs.dmi' icon_state = "cremat" - density = 1 - layer = 2.0 - var/obj/structure/crematorium/connected = null - anchored = 1 - throwpass = 1 - -/obj/structure/c_tray/Destroy() - if(connected && connected.connected == src) - connected.connected = null - connected = null - return ..() - -/obj/structure/c_tray/attack_hand(mob/user as mob) - if (src.connected) - for(var/atom/movable/A as mob|obj in src.loc) - if (!( A.anchored )) - A.forceMove(src.connected) - //Foreach goto(26) - src.connected.connected = null - src.connected.update() - add_fingerprint(user) - //SN src = null - qdel(src) - return - return - -/obj/structure/c_tray/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) - if ((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src) || user.contents.Find(O))) - return - if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) - return - if (!ismob(user) || user.stat || user.lying || user.stunned) - return - O.forceMove(src.loc) - if (user != O) - for(var/mob/B in viewers(user, 3)) - if ((B.client && !( B.blinded ))) - B << text("[] stuffs [] into []!", user, O, src) - //Foreach goto(99) - return /obj/machinery/button/crematorium name = "crematorium igniter" @@ -421,9 +346,9 @@ if(..()) return if(src.allowed(user)) - for (var/obj/structure/crematorium/C in world) + for (var/obj/structure/morgue/crematorium/C in world) if (C.id == id) if (!C.cremating) C.cremate(user) else - usr << "Access denied." + to_chat(user,"Access denied.") diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 0e577bb36b..d3e94e1446 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -20,6 +20,7 @@ var/material/material var/material/padding_material var/base_icon = "bed" + var/applies_material_colour = 1 /obj/structure/bed/New(var/newloc, var/new_material, var/new_padding_material) ..(newloc) @@ -46,7 +47,8 @@ var/cache_key = "[base_icon]-[material.name]" if(isnull(stool_cache[cache_key])) var/image/I = image('icons/obj/furniture.dmi', base_icon) - I.color = material.icon_colour + if(applies_material_colour) //VOREStation Add - Goes with added var + I.color = material.icon_colour stool_cache[cache_key] = I overlays |= stool_cache[cache_key] // Padding overlay. diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 0e6064785d..d1f2753e52 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -82,6 +82,14 @@ src.set_dir(turn(src.dir, 90)) return +/obj/structure/bed/chair/shuttle + name = "chair" + desc = "You sit in this. Either by will or force." + icon_state = "shuttle_chair" + color = null + base_icon = "shuttle_chair" + applies_material_colour = 0 + // Leaving this in for the sake of compilation. /obj/structure/bed/chair/comfy desc = "It's a chair. It looks comfy." diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 028e0af3dc..6450894f4c 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -91,16 +91,13 @@ playsound(src, "shatter", 70, 1) if(display_message) visible_message("[src] shatters!") - if(dir == SOUTHWEST) - var/index = null - index = 0 - while(index < 2) - new shardtype(loc) //todo pooling? - if(reinf) new /obj/item/stack/rods(loc) - index++ - else + new shardtype(loc) + if(reinf) + new /obj/item/stack/rods(loc) + if(is_fulltile()) new shardtype(loc) //todo pooling? - if(reinf) new /obj/item/stack/rods(loc) + if(reinf) + new /obj/item/stack/rods(loc) qdel(src) return @@ -290,11 +287,9 @@ else playsound(src, W.usesound, 75, 1) visible_message("[user] dismantles \the [src].") - if(dir == SOUTHWEST) - var/obj/item/stack/material/mats = new glasstype(loc) - mats.amount = is_fulltile() ? 4 : 2 - else - new glasstype(loc) + var/obj/item/stack/material/mats = new glasstype(loc) + if(is_fulltile()) + mats.amount = 4 qdel(src) else if(istype(W,/obj/item/frame) && anchored) var/obj/item/frame/F = W @@ -329,6 +324,9 @@ if(usr.incapacitated()) return 0 + if(is_fulltile()) + return 0 + if(anchored) usr << "It is fastened to the floor therefore you can't rotate it!" return 0 @@ -348,6 +346,9 @@ if(usr.incapacitated()) return 0 + if(is_fulltile()) + return 0 + if(anchored) usr << "It is fastened to the floor therefore you can't rotate it!" return 0 @@ -361,13 +362,16 @@ /obj/structure/window/New(Loc, start_dir=null, constructed=0) ..() + if (start_dir) + set_dir(start_dir) + //player-constructed windows if (constructed) anchored = 0 + state = 0 update_verbs() - - if (start_dir) - set_dir(start_dir) + if(is_fulltile()) + maxhealth *= 2 health = maxhealth @@ -406,10 +410,10 @@ //Updates the availabiliy of the rotation verbs /obj/structure/window/proc/update_verbs() - if(anchored) + if(anchored || is_fulltile()) verbs -= /obj/structure/window/proc/rotate verbs -= /obj/structure/window/proc/revrotate - else + else if(!is_fulltile()) verbs += /obj/structure/window/proc/rotate verbs += /obj/structure/window/proc/revrotate @@ -507,14 +511,6 @@ glasstype = /obj/item/stack/material/glass/reinforced force_threshold = 6 - -/obj/structure/window/New(Loc, constructed=0) - ..() - - //player-constructed windows - if (constructed) - state = 0 - /obj/structure/window/reinforced/full dir = SOUTHWEST icon_state = "fwindow" diff --git a/code/game/sound.dm b/code/game/sound.dm index c23614942b..afeeaafcae 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -51,6 +51,8 @@ var/list/keyboard_sound = list ('sound/effects/keyboard/keyboard1.ogg','sound/ef var/list/mechstep_sound = list('sound/mecha/mechstep1.ogg', 'sound/mecha/mechstep2.ogg') var/list/bodyfall_sound = list('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg') var/list/can_sound = list('sound/effects/can_open1.ogg','sound/effects/can_open2.ogg','sound/effects/can_open3.ogg','sound/effects/can_open4.ogg') +var/list/geiger_sound = list('sound/items/geiger1.ogg', 'sound/items/geiger2.ogg', 'sound/items/geiger3.ogg', 'sound/items/geiger4.ogg', 'sound/items/geiger5.ogg') +var/list/geiger_weak_sound = list('sound/items/geiger_weak1.ogg', 'sound/items/geiger_weak2.ogg', 'sound/items/geiger_weak3.ogg', 'sound/items/geiger_weak4.ogg') //var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg') @@ -186,4 +188,6 @@ var/const/FALLOFF_SOUNDS = 0.5 if ("canopen") soundin = pick(can_sound) if ("mechstep") soundin = pick(mechstep_sound) //if ("gunshot") soundin = pick(gun_sound) + if("geiger") soundin = pick(geiger_sound) + if("geiger_weak") soundin = pick(geiger_weak_sound) return soundin diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index fa6dec5715..8fafb555a3 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -43,6 +43,8 @@ var/ooc_style = "everyone" if(holder && !holder.fakekey) ooc_style = "elevated" + if(holder.rights & R_EVENT) + ooc_style = "event_manager" if(holder.rights & R_MOD) ooc_style = "moderator" if(holder.rights & R_DEBUG) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 121e355d22..c7d0bb262b 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1223,21 +1223,6 @@ proc/admin_notice(var/message, var/rights) if(istype(H)) H.regenerate_icons() - -/* - helper proc to test if someone is an event manager or not. Got tired of writing this same check all over the place. -*/ -/proc/is_eventM(client/C) - - if(!istype(C)) - return 0 - if(!C.holder) - return 0 - - if(C.holder.rights == R_EVENT) - return 1 - return 0 - /proc/get_options_bar(whom, detail = 2, name = 0, link = 1, highlight_special = 1) if(!whom) return "(*null*)" diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index b6d0abbe1c..473770ac2b 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -100,18 +100,18 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_item/admin_secret category = /datum/admin_secret_category/admin_secrets log = 0 - permissions = R_ADMIN + permissions = R_ADMIN|R_EVENT /datum/admin_secret_item/random_event category = /datum/admin_secret_category/random_events - permissions = R_FUN + permissions = R_FUN|R_EVENT warn_before_use = 1 /datum/admin_secret_item/fun_secret category = /datum/admin_secret_category/fun_secrets - permissions = R_FUN + permissions = R_FUN|R_EVENT warn_before_use = 1 /datum/admin_secret_item/final_solution category = /datum/admin_secret_category/final_solutions - permissions = R_FUN|R_SERVER|R_ADMIN + permissions = R_FUN|R_SERVER|R_ADMIN|R_EVENT diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 2503c73abb..0b02b98ef3 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -8,7 +8,6 @@ var/list/admin_verbs_default = list( /client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, // /client/proc/check_antagonists, //shows all antags, // /client/proc/cmd_mod_say, - /client/proc/cmd_eventM_check_new_players, // /client/proc/deadchat //toggles deadchat on/off, // /client/proc/toggle_ahelp_sound, ) @@ -330,11 +329,11 @@ var/list/admin_verbs_mod = list( ) var/list/admin_verbs_event_manager = list( + /client/proc/cmd_event_say, /client/proc/cmd_admin_pm_context, /client/proc/cmd_admin_pm_panel, /datum/admins/proc/PlayerNotes, /client/proc/admin_ghost, - /client/proc/cmd_mod_say, /datum/admins/proc/show_player_info, /client/proc/dsay, /client/proc/cmd_admin_subtle_message, @@ -448,9 +447,6 @@ var/list/admin_verbs_event_manager = list( feedback_add_details("admin_verb","TAVVS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - - - /client/proc/admin_ghost() set category = "Admin" set name = "Aghost" @@ -461,7 +457,7 @@ var/list/admin_verbs_event_manager = list( if(ghost.can_reenter_corpse) ghost.reenter_corpse() else - ghost << "Error: Aghost: Can't reenter corpse, event managers that use adminHUD while aghosting are not permitted to enter their corpse again" + to_chat(ghost, "Error: Aghost: Can't reenter corpse.") return feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -777,7 +773,7 @@ var/list/admin_verbs_event_manager = list( set category = "Admin" if(holder) - if(alert("Confirm self-deadmin for the round? You can't re-admin yourself without someont promoting you.",,"Yes","No") == "Yes") + if(alert("Confirm self-deadmin for the round? You can't re-admin yourself without someone promoting you.",,"Yes","No") == "Yes") log_admin("[src] deadmined themself.") message_admins("[src] deadmined themself.", 1) deadmin() diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 1531790268..92536a6e05 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -363,20 +363,14 @@ PM "} - - if(usr.client) - var/client/C = usr.client - if(is_eventM(C)) - dat += {" N/A "} - else - switch(is_special_character(M)) - if(0) - dat += {"Traitor?"} - if(1) - dat += {"Traitor?"} - if(2) - dat += {"Traitor?"} + switch(is_special_character(M)) + if(0) + dat += {"Traitor?"} + if(1) + dat += {"Traitor?"} + if(2) + dat += {"Traitor?"} else dat += {" N/A "} diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 63209f84b4..264e5ad64e 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -36,7 +36,8 @@ if(check_rights(R_ADMIN, 0)) sender_name = "[sender_name]" for(var/client/C in admins) - C << "" + create_text_tag("mod", "MOD:", C) + " [sender_name]([admin_jump_link(mob, C.holder)]): [msg]" + if(check_rights(R_ADMIN|R_MOD|R_SERVER)) + C << "" + create_text_tag("mod", "MOD:", C) + " [sender_name]([admin_jump_link(mob, C.holder)]): [msg]" feedback_add_details("admin_verb","MS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -45,7 +46,7 @@ set name = "Esay" set hidden = 1 - if(!check_rights(R_ADMIN|R_MOD|R_EVENT|R_SERVER)) + if(!check_rights(R_ADMIN|R_MOD|R_EVENT|R_SERVER|R_EVENT)) return msg = sanitize(msg) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index c14c74edd1..b80d95e3c1 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -65,42 +65,6 @@ message_admins("SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]", 1) feedback_add_details("admin_verb","SMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_eventM_check_new_players() //Allows event managers / admins to determine who the newer players are. - set category = "Admin" - set name = "Check new Players" - if(!holder) - src << "Only staff members may use this command." - - var/age = alert(src, "Age check", "Show accounts yonger then _____ days","7", "30" , "All") - - if(age == "All") - age = 9999999 - else - age = text2num(age) - - var/missing_ages = 0 - var/msg = "" - - var/highlight_special_characters = 1 - if(is_eventM(usr.client)) - highlight_special_characters = 0 - - for(var/client/C in clients) - if(C.player_age == "Requires database") - missing_ages = 1 - continue - if(C.player_age < age) - msg += "[key_name(C, 1, 1, highlight_special_characters)]: account is [C.player_age] days old
" - - if(missing_ages) - src << "Some accounts did not have proper ages set in their clients. This function requires database to be present" - - if(msg != "") - src << browse(msg, "window=Player_age_check") - else - src << "No matches for that age range found." - - /client/proc/cmd_admin_world_narrate() // Allows administrators to fluff events a little easier -- TLE set category = "Special Verbs" set name = "Global Narrate" diff --git a/code/modules/busy_space/organizations.dm b/code/modules/busy_space/organizations.dm index b8bc38b291..da08c70c4a 100644 --- a/code/modules/busy_space/organizations.dm +++ b/code/modules/busy_space/organizations.dm @@ -104,7 +104,7 @@ // Note that the current station being used will be pruned from this list upon being instantiated destination_names = list( "NSS Exodus in Nyx", - "NCS Northern Star in Vir", + //"NCS Northern Star in Vir", "NLS Southern Cross in Vir", "NAS Vir Central Command", "a dockyard orbiting Sif", diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index c6500143f0..73d91129e7 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -3,6 +3,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O /datum/preferences var/equip_preview_mob = EQUIP_PREVIEW_ALL + var/icon/bgstate = "000" + var/list/bgstate_options = list("000", "fff", "steel", "white") + /datum/category_item/player_setup_item/general/body name = "Body" sort_order = 3 @@ -34,6 +37,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["synth_green"] >> pref.g_synth S["synth_blue"] >> pref.b_synth pref.preview_icon = null + S["bgstate"] >> pref.bgstate /datum/category_item/player_setup_item/general/body/save_character(var/savefile/S) S["species"] << pref.species @@ -61,6 +65,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["synth_red"] << pref.r_synth S["synth_green"] << pref.g_synth S["synth_blue"] << pref.b_synth + S["bgstate"] << pref.bgstate /datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) if(!pref.species || !(pref.species in playable_species)) @@ -87,6 +92,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O if(!pref.rlimb_data) pref.rlimb_data = list() if(!pref.body_markings) pref.body_markings = list() else pref.body_markings &= body_marking_styles_list + if(!pref.bgstate || !(pref.bgstate in pref.bgstate_options)) + pref.bgstate = "000" // Moved from /datum/preferences/proc/copy_to() /datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character) @@ -268,6 +275,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O . += "Preview
" . += "
" + . += "
Cycle background" . += "
[pref.equip_preview_mob & EQUIP_PREVIEW_LOADOUT ? "Hide loadout" : "Show loadout"]" . += "
[pref.equip_preview_mob & EQUIP_PREVIEW_JOB ? "Hide job gear" : "Show job gear"]" . += "" @@ -694,6 +702,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.b_synth = hex2num(copytext(new_color, 6, 8)) return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["cycle_bg"]) + pref.bgstate = next_in_list(pref.bgstate, pref.bgstate_options) + return TOPIC_REFRESH_UPDATE_PREVIEW + return ..() /datum/category_item/player_setup_item/general/body/proc/reset_limbs() diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm index 6f3115fd2f..860869883f 100644 --- a/code/modules/client/preference_setup/loadout/loadout_general.dm +++ b/code/modules/client/preference_setup/loadout/loadout_general.dm @@ -34,6 +34,18 @@ display_name = "Spaceball booster pack" path = /obj/item/weapon/pack/spaceball +/datum/gear/plushie + display_name = "plushie selection" + path = /obj/item/toy/plushie/ + +/datum/gear/plushie/New() + ..() + var/list/plushies = list() + for(var/plushie in subtypesof(/obj/item/toy/plushie/) - /obj/item/toy/plushie/therapy) + var/obj/item/toy/plushie/plushie_type = plushie + plushies[initial(plushie_type.name)] = plushie_type + gear_tweaks += new/datum/gear_tweak/path(sortAssoc(plushies)) + /datum/gear/flask display_name = "flask" path = /obj/item/weapon/reagent_containers/food/drinks/flask/barflask diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm index f7737c9dde..bbaca4c363 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head.dm @@ -154,34 +154,10 @@ path = /obj/item/clothing/head/fedora/grey /datum/gear/head/hairflower - display_name = "hair flower pin, red" - path = /obj/item/clothing/head/hairflower - -/datum/gear/head/hairflower/yellow - display_name = "hair flower pin, yellow" - path = /obj/item/clothing/head/hairflower/yellow - -/datum/gear/head/hairflower/pink - display_name = "hair flower pin, pink" - path = /obj/item/clothing/head/hairflower/pink - -/datum/gear/head/hairflower/blue - display_name = "hair flower pin, blue" - path = /obj/item/clothing/head/hairflower/blue - -/datum/gear/head/hairflower/violet - display_name = "hair flower pin, violet" - path = /obj/item/clothing/head/hairflower/violet - -/datum/gear/head/hairflower/orange - display_name = "hair flower pin, orange" - path = /obj/item/clothing/head/hairflower/orange - -/datum/gear/head/hairflower/white display_name = "hair flower pin" path = /obj/item/clothing/head/hairflower/white -/datum/gear/head/hairflower/white/New() +/datum/gear/head/hairflower/New() ..() gear_tweaks = list(gear_tweak_free_color_choice) @@ -372,4 +348,4 @@ /datum/gear/head/surgical/purple display_name = "surgical cap, purple" - path = /obj/item/clothing/head/surgery/purple \ No newline at end of file + path = /obj/item/clothing/head/surgery/purple diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/client/preference_setup/loadout/loadout_shoes.dm index ba2d995b27..6b15fba5ea 100644 --- a/code/modules/client/preference_setup/loadout/loadout_shoes.dm +++ b/code/modules/client/preference_setup/loadout/loadout_shoes.dm @@ -73,10 +73,6 @@ display_name = "shoes, yellow" path = /obj/item/clothing/shoes/yellow -/datum/gear/shoes/flats - display_name = "flats, black" - path = /obj/item/clothing/shoes/flats - /datum/gear/shoes/hitops/ display_name = "high-top, white" path = /obj/item/clothing/shoes/hitops/ @@ -109,30 +105,6 @@ display_name = "high-top, yellow" path = /obj/item/clothing/shoes/hitops/yellow -/datum/gear/shoes/flats/blue - display_name = "flats, blue" - path = /obj/item/clothing/shoes/flats/blue - -/datum/gear/shoes/flats/brown - display_name = "flats, brown" - path = /obj/item/clothing/shoes/flats/brown - -/datum/gear/shoes/flats/orange - display_name = "flats, orange" - path = /obj/item/clothing/shoes/flats/orange - -/datum/gear/shoes/flats/purple - display_name = "flats, purple" - path = /obj/item/clothing/shoes/flats/purple - -/datum/gear/shoes/flats/red - display_name = "flats, red" - path = /obj/item/clothing/shoes/flats/red - -/datum/gear/shoes/flats/white - display_name = "flats, white" - path = /obj/item/clothing/shoes/flats/white - /datum/gear/shoes/flipflops display_name = "flip flops" path = /obj/item/clothing/shoes/flipflop @@ -157,11 +129,11 @@ ..() gear_tweaks = list(gear_tweak_free_color_choice) -/datum/gear/shoes/flats/color +/datum/gear/shoes/flats display_name = "flats" path = /obj/item/clothing/shoes/flats/white/color -/datum/gear/shoes/flats/color/New() +/datum/gear/shoes/flats/New() ..() gear_tweaks = list(gear_tweak_free_color_choice) @@ -246,4 +218,4 @@ /datum/gear/shoes/boots/winter/hydro display_name = "hydroponics winter boots" path = /obj/item/clothing/shoes/boots/winter/hydro - allowed_roles = list("Botanist", "Xenobiologist") \ No newline at end of file + allowed_roles = list("Botanist", "Xenobiologist") diff --git a/code/modules/client/preference_setup/traits/trait_defines.dm b/code/modules/client/preference_setup/traits/trait_defines.dm index 0431ac611b..86b8ede6f7 100644 --- a/code/modules/client/preference_setup/traits/trait_defines.dm +++ b/code/modules/client/preference_setup/traits/trait_defines.dm @@ -72,6 +72,25 @@ Regardless, you find it quite difficult to land shots where you wanted them to go." modifier_type = /datum/modifier/trait/inaccurate +/datum/trait/modifier/physical/smaller + name = "Smaller" + modifier_type = /datum/modifier/trait/smaller + mutually_exclusive = list(/datum/trait/modifier/physical/small, /datum/trait/modifier/physical/large, /datum/trait/modifier/physical/larger) + +/datum/trait/modifier/physical/small + name = "Small" + modifier_type = /datum/modifier/trait/small + mutually_exclusive = list(/datum/trait/modifier/physical/smaller, /datum/trait/modifier/physical/large, /datum/trait/modifier/physical/larger) + +/datum/trait/modifier/physical/large + name = "Large" + modifier_type = /datum/modifier/trait/large + mutually_exclusive = list(/datum/trait/modifier/physical/smaller, /datum/trait/modifier/physical/small, /datum/trait/modifier/physical/larger) + +/datum/trait/modifier/physical/larger + name = "Larger" + modifier_type = /datum/modifier/trait/larger + mutually_exclusive = list(/datum/trait/modifier/physical/smaller, /datum/trait/modifier/physical/small, /datum/trait/modifier/physical/large) // These two traits might be borderline, feel free to remove if they get abused. /datum/trait/modifier/physical/high_metabolism diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm index 94ed2c9f87..d7e0362272 100644 --- a/code/modules/clothing/gloves/color.dm +++ b/code/modules/clothing/gloves/color.dm @@ -77,6 +77,7 @@ desc = "A pair of gloves that reach past the elbow. Fancy!" name = "evening gloves" icon_state = "evening_gloves" + addblends = "evening_gloves_a" cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index cc3f276566..85f51e2cdd 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -34,9 +34,11 @@ /obj/item/clothing/head/hairflower/white icon_state = "hairflower_white" + addblends = "hairflower_white_a" /obj/item/clothing/head/hairflower/bow icon_state = "bow" + addblends = "bow_a" name = "hair bow" desc = "A ribbon tied into a bow with a clip on the back to attach to hair." item_state_slots = list(slot_r_hand_str = "pill", slot_l_hand_str = "pill") @@ -155,6 +157,7 @@ /obj/item/clothing/head/flatcap/grey icon_state = "flat_capw" + addblends = "flat_capw_a" item_state_slots = list(slot_r_hand_str = "greysoft", slot_l_hand_str = "greysoft") /obj/item/clothing/head/pirate @@ -300,6 +303,7 @@ name = "hijab" desc = "A veil that is wrapped to cover the head and chest" icon_state = "hijab" + addblends = "hijab_a" item_state_slots = list(slot_r_hand_str = "beret_white", slot_l_hand_str = "beret_white") body_parts_covered = 0 flags_inv = BLOCKHAIR @@ -308,12 +312,14 @@ name = "kippa" desc = "A small, brimless cap." icon_state = "kippa" + addblends = "kippa_a" body_parts_covered = 0 /obj/item/clothing/head/turban name = "turban" desc = "A cloth used to wind around the head" icon_state = "turban" + addblends = "turban_a" item_state_slots = list(slot_r_hand_str = "beret_white", slot_l_hand_str = "beret_white") body_parts_covered = 0 flags_inv = BLOCKHEADHAIR @@ -322,24 +328,28 @@ name = "taqiyah" desc = "A short, rounded skullcap usually worn for religious purposes." icon_state = "taqiyah" + addblends = "taqiyah_a" item_state_slots = list(slot_r_hand_str = "taq", slot_l_hand_str = "taq") /obj/item/clothing/head/beanie name = "beanie" desc = "A head-hugging brimless winter cap. This one is tight." icon_state = "beanie" + addblends = "beanie_a" body_parts_covered = 0 /obj/item/clothing/head/beanie_loose name = "loose beanie" desc = "A head-hugging brimless winter cap. This one is loose." icon_state = "beanie_hang" + addblends = "beanie_hang_a" body_parts_covered = 0 /obj/item/clothing/head/beretg name = "beret" desc = "A beret, an artists favorite headwear." icon_state = "beret_g" + addblends = "beret_g_a" body_parts_covered = 0 /obj/item/clothing/head/sombrero diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index 6b4b270f97..85ffb970b8 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -54,6 +54,7 @@ name = "white flats" desc = "Shiny white flats." icon_state = "flatswhite" + addblends = "flatswhite_a" item_state_slots = list(slot_r_hand_str = "white", slot_l_hand_str = "white") /obj/item/clothing/shoes/flats/white/color diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index c1c833a308..8ee0ae2d32 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -124,23 +124,27 @@ name = "flip flops" desc = "A pair of foam flip flops. For those not afraid to show a little ankle." icon_state = "thongsandal" + addblends = "thongsandal_a" /obj/item/clothing/shoes/athletic name = "athletic shoes" desc = "A pair of sleek atheletic shoes. Made by and for the sporty types." icon_state = "sportshoe" + addblends = "sportshoe_a" item_state_slots = list(slot_r_hand_str = "sportheld", slot_l_hand_str = "sportheld") /obj/item/clothing/shoes/skater name = "skater shoes" desc = "A pair of wide shoes with thick soles. Designed for skating." icon_state = "skatershoe" + addblends = "skatershoe_a" item_state_slots = list(slot_r_hand_str = "skaterheld", slot_l_hand_str = "skaterheld") /obj/item/clothing/shoes/heels name = "high heels" desc = "A pair of high-heeled shoes. Fancy!" icon_state = "heels" + addblends = "heels_a" /obj/item/clothing/shoes/footwraps name = "cloth footwraps" diff --git a/code/modules/clothing/spacesuits/void/station.dm b/code/modules/clothing/spacesuits/void/station.dm index 31830fb275..3c5dc32e68 100644 --- a/code/modules/clothing/spacesuits/void/station.dm +++ b/code/modules/clothing/spacesuits/void/station.dm @@ -150,20 +150,20 @@ item_state_slots = list(slot_r_hand_str = "medical_voidsuit_bio", slot_l_hand_str = "medical_voidsuit_bio") armor = list(melee = 45, bullet = 5, laser = 20, energy = 5, bomb = 15, bio = 100, rad = 75) -//Medical Surplus Voidsuit +//Medical Streamlined Voidsuit /obj/item/clothing/head/helmet/space/void/medical/alt name = "streamlined medical voidsuit helmet" desc = "A trendy, lightly radiation-shielded voidsuit helmet trimmed in a fetching green." icon_state = "rig0-medicalalt" - armor = list(melee = 30, bullet = 5, laser = 10,energy = 5, bomb = 5, bio = 100, rad = 60) + armor = list(melee = 30, bullet = 5, laser = 20,energy = 5, bomb = 25, bio = 100, rad = 80) light_overlay = "helmet_light_dual_green" /obj/item/clothing/suit/space/void/medical/alt icon_state = "rig-medicalalt" name = "streamlined medical voidsuit" desc = "A more recent model of Vey-Med voidsuit, featuring the latest in radiation shielding technology, without sacrificing comfort or style." - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage/firstaid,/obj/item/device/healthanalyzer,/obj/item/stack/medical) - armor = list(melee = 30, bullet = 5, laser = 10,energy = 5, bomb = 5, bio = 100, rad = 60) + slowdown = 0 + armor = list(melee = 30, bullet = 5, laser = 20,energy = 5, bomb = 25, bio = 100, rad = 80) //Security /obj/item/clothing/head/helmet/space/void/security diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm index 934d7407d9..dfc416aa69 100644 --- a/code/modules/clothing/spacesuits/void/void.dm +++ b/code/modules/clothing/spacesuits/void/void.dm @@ -54,7 +54,7 @@ //Breach thresholds, should ideally be inherited by most (if not all) voidsuits. //With 0.2 resiliance, will reach 10 breach damage after 3 laser carbine blasts or 8 smg hits. - breach_threshold = 18 + breach_threshold = 12 can_breach = 1 //Inbuilt devices. diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 602b854287..006de8e99c 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -277,6 +277,7 @@ obj/item/clothing/suit/kimono name = "kimono" desc = "A traditional Japanese kimono." icon_state = "kimono" + addblends = "kimono_a" /* * coats @@ -344,6 +345,7 @@ obj/item/clothing/suit/storage/toggle/peacoat name = "peacoat" desc = "A well-tailored, stylish peacoat." icon_state = "peacoat" + addblends = "peacoat_a" item_state_slots = list(slot_r_hand_str = "peacoat", slot_l_hand_str = "peacoat") flags_inv = HIDEHOLSTER /* diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 4392a26492..2acaff6852 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -45,6 +45,16 @@ mob_overlay = image("icon" = sprite_sheets[wearer.species.get_bodytype(wearer)], "icon_state" = "[tmp_icon_state]") else mob_overlay = image("icon" = INV_ACCESSORIES_DEF_ICON, "icon_state" = "[tmp_icon_state]") + if(addblends) + var/icon/base = new/icon("icon" = mob_overlay.icon, "icon_state" = mob_overlay.icon_state) + var/addblend_icon = new/icon("icon" = mob_overlay.icon, "icon_state" = src.addblends) + if(color) + base.Blend(src.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + mob_overlay = image(base) + else + mob_overlay.color = src.color + return mob_overlay //when user attached an accessory to S diff --git a/code/modules/clothing/under/accessories/armband.dm b/code/modules/clothing/under/accessories/armband.dm index 3f53c44392..bf40074a2a 100644 --- a/code/modules/clothing/under/accessories/armband.dm +++ b/code/modules/clothing/under/accessories/armband.dm @@ -37,6 +37,7 @@ /obj/item/clothing/accessory/armband/med/color name = "armband" desc = "A fancy armband." + addblends = "med_a" /obj/item/clothing/accessory/armband/medblue name = "EMT armband" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index f9a0a9ab37..77046dd89e 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -627,17 +627,20 @@ name = "long dress" desc = "A long dress." icon_state = "whitedress2" + addblends = "whitedress2_a" flags_inv = HIDESHOES /obj/item/clothing/under/dress/white3 name = "short dress" desc = "A short, plain dress." icon_state = "whitedress3" + addblends = "whitedress3_a" /obj/item/clothing/under/dress/white4 name = "long flared dress" desc = "A long white dress that flares out at the bottom." icon_state = "whitedress4" + addblends = "whitedress4_a" flags_inv = HIDESHOES /obj/item/clothing/under/dress/darkred diff --git a/code/modules/clothing/under/pants.dm b/code/modules/clothing/under/pants.dm index 322115cc0b..c306d842d0 100644 --- a/code/modules/clothing/under/pants.dm +++ b/code/modules/clothing/under/pants.dm @@ -121,6 +121,7 @@ name = "yoga pants" desc = "A pair of tight-fitting yoga pants for those lazy days." icon_state = "yogapants" + addblends = "yogapants_a" /* * Baggy Pants diff --git a/code/modules/economy/economy_misc.dm b/code/modules/economy/economy_misc.dm index a2cc9aafb9..84a187ef91 100644 --- a/code/modules/economy/economy_misc.dm +++ b/code/modules/economy/economy_misc.dm @@ -49,6 +49,7 @@ /var/list/economic_species_modifier = list( /datum/species/human = 10, + /datum/species/human/vatgrown = 10, /datum/species/skrell = 12, /datum/species/unathi = 7, /datum/species/tajaran = 7, diff --git a/code/modules/integrated_electronics/core/helpers.dm b/code/modules/integrated_electronics/core/helpers.dm index edfa6b1a86..e31b26fbb1 100644 --- a/code/modules/integrated_electronics/core/helpers.dm +++ b/code/modules/integrated_electronics/core/helpers.dm @@ -18,7 +18,9 @@ else io_list.Add(new io_type(src, io_entry, default_data)) -/obj/item/integrated_circuit/proc/set_pin_data(var/pin_type, var/pin_number, var/new_data) +/obj/item/integrated_circuit/proc/set_pin_data(var/pin_type, var/pin_number, datum/new_data) + if (istype(new_data) && !isweakref(new_data)) + new_data = weakref(new_data) var/datum/integrated_io/pin = get_pin_ref(pin_type, pin_number) return pin.write_data_to_pin(new_data) diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm index c22d65e421..8621e2b7ed 100644 --- a/code/modules/integrated_electronics/core/pins.dm +++ b/code/modules/integrated_electronics/core/pins.dm @@ -112,6 +112,8 @@ list[]( /datum/integrated_io/proc/write_data_to_pin(var/new_data) if(isnull(new_data) || isnum(new_data) || istext(new_data) || isweakref(new_data)) // Anything else is a type we don't want. + if(istext(new_data)) + new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0) data = new_data holder.on_data_written() diff --git a/code/modules/integrated_electronics/core/special_pins/string_pin.dm b/code/modules/integrated_electronics/core/special_pins/string_pin.dm index 6128418c1f..595a205318 100644 --- a/code/modules/integrated_electronics/core/special_pins/string_pin.dm +++ b/code/modules/integrated_electronics/core/special_pins/string_pin.dm @@ -4,11 +4,14 @@ /datum/integrated_io/string/ask_for_pin_data(mob/user) var/new_data = input("Please type in a string.","[src] string writing") as null|text - if(holder.check_interactivity(user) ) + new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0) + + if(new_data && holder.check_interactivity(user) ) to_chat(user, "You input [new_data ? "new_data" : "NULL"] into the pin.") write_data_to_pin(new_data) /datum/integrated_io/string/write_data_to_pin(var/new_data) + new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0) if(isnull(new_data) || istext(new_data)) data = new_data holder.on_data_written() diff --git a/code/modules/integrated_electronics/core/tools.dm b/code/modules/integrated_electronics/core/tools.dm index 08765b94e5..0f702be3de 100644 --- a/code/modules/integrated_electronics/core/tools.dm +++ b/code/modules/integrated_electronics/core/tools.dm @@ -125,6 +125,7 @@ if("string") accepting_refs = 0 new_data = input("Now type in a string.","[src] string writing") as null|text + new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0) if(istext(new_data) && CanInteract(user, physical_state)) data_to_write = new_data to_chat(user, "You set \the [src]'s memory to \"[new_data]\".") diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm index c417c3e4fd..0a516e360a 100644 --- a/code/modules/integrated_electronics/passive/power.dm +++ b/code/modules/integrated_electronics/passive/power.dm @@ -29,6 +29,28 @@ if(assembly) assembly.give_power(adjusted_power) +/obj/item/integrated_circuit/passive/power/starter + name = "starter" + desc = "This tiny circuit will send a pulse right after device is turned on, or when power is restored." + icon_state = "led" + complexity = 1 + activators = list("pulse out" = IC_PINTYPE_PULSE_OUT) + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + var/is_charge=0 + +/obj/item/integrated_circuit/passive/power/starter/make_energy() + if(assembly.battery) + if(assembly.battery.charge) + if(!is_charge) + activate_pin(1) + is_charge=1 + else + is_charge=0 + else + is_charge=0 + return FALSE + // For implants. /obj/item/integrated_circuit/passive/power/metabolic_siphon name = "metabolic siphon" @@ -82,6 +104,44 @@ origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3, TECH_DATA = 2) spawn_flags = IC_SPAWN_RESEARCH var/power_amount = 250 +//fuel cell + +/obj/item/integrated_circuit/passive/power/chemical_cell + name = "fuel cell" + desc = "Produces electricity from chemicals." + icon_state = "chemical_cell" + extended_desc = "This is effectively an internal beaker. It will consume and produce power from phoron, slime jelly, welding fuel, carbon,\ + ethanol, nutriments and blood, in order of decreasing efficiency. It will consume fuel only if the battery can take more energy." + flags = OPENCONTAINER + complexity = 4 + inputs = list() + outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) + activators = list() + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + var/volume = 60 + var/list/fuel = list("phoron" = 50000, "slimejelly" = 25000, "fuel" = 15000, "carbon" = 10000, "ethanol"= 10000, "nutriment" =8000, "blood" = 5000) + +/obj/item/integrated_circuit/passive/power/chemical_cell/New() + ..() + create_reagents(volume) + +/obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + ..() + +/obj/item/integrated_circuit/passive/power/chemical_cell/on_reagent_change() + set_pin_data(IC_OUTPUT, 1, reagents.total_volume) + push_data() + +/obj/item/integrated_circuit/passive/power/chemical_cell/make_energy() + if(assembly) + for(var/I in fuel) + if((assembly.battery.maxcharge-assembly.battery.charge) / CELLRATE > fuel[I]) + if(reagents.remove_reagent(I, 1)) + assembly.give_power(fuel[I]) + // For really fat machines. /obj/item/integrated_circuit/passive/power/relay/large diff --git a/code/modules/integrated_electronics/subtypes/data_transfer.dm b/code/modules/integrated_electronics/subtypes/data_transfer.dm index 7b5846eb8d..e490ccd27a 100644 --- a/code/modules/integrated_electronics/subtypes/data_transfer.dm +++ b/code/modules/integrated_electronics/subtypes/data_transfer.dm @@ -27,13 +27,10 @@ /obj/item/integrated_circuit/transfer/multiplexer/do_work() var/input_index = get_pin_data(IC_INPUT, 1) - var/output = null if(!isnull(input_index) && (input_index >= 1 && input_index < inputs.len)) - output = get_pin_data(IC_INPUT, input_index + 1) - - set_pin_data(IC_OUTPUT, 1, output) - push_data() + set_pin_data(IC_OUTPUT, 1,get_pin_data(IC_INPUT, input_index + 1)) + push_data() activate_pin(2) /obj/item/integrated_circuit/transfer/multiplexer/medium @@ -79,10 +76,8 @@ /obj/item/integrated_circuit/transfer/demultiplexer/do_work() var/output_index = get_pin_data(IC_INPUT, 1) - var/output = get_pin_data(IC_INPUT, 2) - for(var/i = 1 to outputs.len) - set_pin_data(IC_OUTPUT, i, i == output_index ? output : null) + set_pin_data(IC_OUTPUT, i, i == output_index ? get_pin_data(IC_INPUT, 2) : null) activate_pin(2) @@ -101,4 +96,51 @@ name = "sixteen demultiplexer" icon_state = "dmux16" w_class = ITEMSIZE_SMALL + number_of_outputs = 16 + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer + name = "two pulse demultiplexer" + desc = "Selector switch to choose the pin to be activated by number." + extended_desc = "The first input pin is used to select which of the pulse out pins will be activated after activation of the circuit. \ + If the output selection is outside the valid range then no output is given." + complexity = 2 + icon_state = "dmux2" + inputs = list("output selection" = IC_PINTYPE_NUMBER) + outputs = list() + activators = list("select" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + power_draw_per_use = 4 + var/number_of_outputs = 2 + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer/New() + for(var/i = 1 to number_of_outputs) + // outputs += "output [i]" + activators["output [i]"] = IC_PINTYPE_PULSE_OUT + complexity = number_of_outputs + + ..() + desc += " It has [number_of_outputs] output pins." + extended_desc += " This pulse demultiplexer has a range from 1 to [activators.len - 1]." + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer/do_work() + var/output_index = get_pin_data(IC_INPUT, 1) + + if(output_index == Clamp(output_index, 1, number_of_outputs)) + activate_pin(round(output_index + 1 ,1)) + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer/medium + name = "four pulse demultiplexer" + icon_state = "dmux4" + number_of_outputs = 4 + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer/large + name = "eight pulse demultiplexer" + icon_state = "dmux8" + w_class = ITEMSIZE_SMALL + number_of_outputs = 8 + +/obj/item/integrated_circuit/transfer/pulsedemultiplexer/huge + name = "sixteen pulse demultiplexer" + icon_state = "dmux16" + w_class = ITEMSIZE_SMALL number_of_outputs = 16 \ 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 d752f0d5cd..8da4fad6d8 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -110,8 +110,10 @@ /obj/item/integrated_circuit/input/adv_med_scanner - name = "integrated advanced medical analyser" - desc = "A very small version of the medbot's medical analyser. This allows the machine to know how healthy someone is. \ + + name = "integrated advanced medical analyzer" + desc = "A very small version of the medibot's medical analyzer. This allows the machine to know how healthy someone is. \ + 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 @@ -134,7 +136,9 @@ var/mob/living/carbon/human/H = get_pin_data_as_type(IC_INPUT, 1, /mob/living/carbon/human) if(!istype(H)) //Invalid input return + if(H in view(get_turf(H))) // Like medbot's analyzer it can be used in range.. + var/total_health = round(H.health/H.getMaxHealth(), 0.01)*100 var/missing_health = H.getMaxHealth() - H.health @@ -336,6 +340,7 @@ // Set the pins so when someone sees them, they won't show as null set_pin_data(IC_INPUT, 1, frequency) set_pin_data(IC_INPUT, 2, code) + push_data() /obj/item/integrated_circuit/input/signaler/Destroy() if(radio_controller) @@ -464,6 +469,7 @@ set_pin_data(IC_OUTPUT, 1, null) set_pin_data(IC_OUTPUT, 2, null) if(!T) + push_data() return set_pin_data(IC_OUTPUT, 1, T.x) @@ -486,7 +492,7 @@ "speaker" = IC_PINTYPE_STRING, "message" = IC_PINTYPE_STRING ) - activators = list("on message received" = IC_PINTYPE_PULSE_IN, "on translation" = IC_PINTYPE_PULSE_OUT) + activators = list("on message received" = IC_PINTYPE_PULSE_OUT, "on translation" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH power_draw_per_use = 15 @@ -618,4 +624,235 @@ push_data() activate_pin(2) +/obj/item/integrated_circuit/input/atmo_scanner + name = "integrated atmospheric analyser" + desc = "The same atmospheric analysis module that is integrated into every PDA. \ + This allows the machine to know the composition, temperature and pressure of the surrounding atmosphere." + icon_state = "medscan_adv" + complexity = 9 + inputs = list() + outputs = list( + "pressure" = IC_PINTYPE_NUMBER, + "temperature" = IC_PINTYPE_NUMBER, + "oxygen" = IC_PINTYPE_NUMBER, + "nitrogen" = IC_PINTYPE_NUMBER, + "carbon dioxide" = IC_PINTYPE_NUMBER, + "phoron" = IC_PINTYPE_NUMBER, + "other" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 60 +/obj/item/integrated_circuit/input/atmo_scanner/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) + set_pin_data(IC_OUTPUT, 1, pressure) + set_pin_data(IC_OUTPUT, 2, round(environment.temperature-T0C,0.1)) + set_pin_data(IC_OUTPUT, 3, round(o2_level*100,0.1)) + set_pin_data(IC_OUTPUT, 4, round(n2_level*100,0.1)) + set_pin_data(IC_OUTPUT, 5, round(co2_level*100,0.1)) + set_pin_data(IC_OUTPUT, 6, round(phoron_level*100,0.01)) + set_pin_data(IC_OUTPUT, 7, round(unknown_level, 0.01)) + else + set_pin_data(IC_OUTPUT, 1, 0) + set_pin_data(IC_OUTPUT, 2, -273.15) + set_pin_data(IC_OUTPUT, 3, 0) + set_pin_data(IC_OUTPUT, 4, 0) + set_pin_data(IC_OUTPUT, 5, 0) + set_pin_data(IC_OUTPUT, 6, 0) + set_pin_data(IC_OUTPUT, 7, 0) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/pressure_sensor + name = "integrated pressure sensor" + desc = "A tiny pressure sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "pressure" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/pressure_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + + if (total_moles) + set_pin_data(IC_OUTPUT, 1, pressure) + else + set_pin_data(IC_OUTPUT, 1, 0) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/temperature_sensor + name = "integrated temperature sensor" + desc = "A tiny temperature sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "temperature" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/temperature_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/total_moles = environment.total_moles + + if (total_moles) + set_pin_data(IC_OUTPUT, 1, round(environment.temperature-T0C,0.1)) + else + set_pin_data(IC_OUTPUT, 1, -273.15) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/oxygen_sensor + name = "integrated oxygen sensor" + desc = "A tiny oxygen sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "oxygen" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/oxygen_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/total_moles = environment.total_moles + + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + set_pin_data(IC_OUTPUT, 1, round(o2_level*100,0.1)) + else + set_pin_data(IC_OUTPUT, 1, 0) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/co2_sensor + name = "integrated co2 sensor" + desc = "A tiny carbon dioxide sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "co2" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/co2_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/total_moles = environment.total_moles + + if (total_moles) + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + set_pin_data(IC_OUTPUT, 1, round(co2_level*100,0.1)) + else + set_pin_data(IC_OUTPUT, 1, 0) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/nitrogen_sensor + name = "integrated nitrogen sensor" + desc = "A tiny nitrogen sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "nitrogen" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/nitrogen_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/total_moles = environment.total_moles + + if (total_moles) + var/n2_level = environment.gas["nitrogen"]/total_moles + set_pin_data(IC_OUTPUT, 1, round(n2_level*100,0.1)) + else + set_pin_data(IC_OUTPUT, 1, 0) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/input/phoron_sensor + name = "integrated phoron sensor" + desc = "A tiny phoron gas sensor module similar to that found in a PDA atmosphere analyser." + icon_state = "medscan_adv" + complexity = 3 + inputs = list() + outputs = list( + "phoron" = IC_PINTYPE_NUMBER + ) + activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3) + power_draw_per_use = 20 + +/obj/item/integrated_circuit/input/phoron_sensor/do_work() + var/turf/T = get_turf(src) + if(!istype(T)) //Invalid input + return + var/datum/gas_mixture/environment = T.return_air() + + var/total_moles = environment.total_moles + + if (total_moles) + var/phoron_level = environment.gas["phoron"]/total_moles + set_pin_data(IC_OUTPUT, 1, round(phoron_level*100,0.1)) + else + set_pin_data(IC_OUTPUT, 1, 0) + push_data() + activate_pin(2) diff --git a/code/modules/integrated_electronics/subtypes/lists.dm b/code/modules/integrated_electronics/subtypes/lists.dm index 84e0724bb9..943141b071 100644 --- a/code/modules/integrated_electronics/subtypes/lists.dm +++ b/code/modules/integrated_electronics/subtypes/lists.dm @@ -52,12 +52,123 @@ push_data() activate_pin(2) +/obj/item/integrated_circuit/list/search + name = "search circuit" + desc = "This circuit will give index of desired element in the list." + extended_desc = "Search will start at 1 position and will return first matching position." + inputs = list( + "list" = IC_PINTYPE_LIST, + "item" = IC_PINTYPE_ANY + ) + outputs = list( + "index" = IC_PINTYPE_NUMBER + ) + icon_state = "addition" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/list/search/do_work() + var/list/input_list = get_pin_data(IC_INPUT, 1) + var/item = get_pin_data(IC_INPUT, 2) + set_pin_data(IC_OUTPUT, 1, input_list.Find(item)) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/list/at + name = "at circuit" + desc = "This circuit will pick an element from a list by index." + extended_desc = "If there is no element with such index, result will be null." + inputs = list( + "list" = IC_PINTYPE_LIST, + "index" = IC_PINTYPE_NUMBER + ) + outputs = list("item" = IC_PINTYPE_ANY) + icon_state = "addition" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/list/at/do_work() + var/list/input_list = get_pin_data(IC_INPUT, 1) + var/index = get_pin_data(IC_INPUT, 2) + var/item = input_list[index] + set_pin_data(IC_OUTPUT, 1, item) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/list/delete + name = "delete circuit" + desc = "This circuit will delete the element from a list by index." + extended_desc = "If there is no element with such index, result list will be unchanged." + inputs = list( + "list" = IC_PINTYPE_LIST, + "index" = IC_PINTYPE_NUMBER + ) + outputs = list( + "item" = IC_PINTYPE_LIST + ) + icon_state = "addition" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/list/delete/do_work() + var/list/input_list = get_pin_data(IC_INPUT, 1) + var/list/red_list = list() + var/index = get_pin_data(IC_INPUT, 2) + var/j = 0 + for(var/I in input_list) + j = j + 1 + if(j != index) + red_list.Add(I) + set_pin_data(IC_OUTPUT, 1, red_list) + push_data() + activate_pin(2) + +/obj/item/integrated_circuit/list/write + name = "write circuit" + desc = "This circuit will write element in list with given index." + extended_desc = "If there is no element with such index, it will give the same list, as before." + inputs = list( + "list" = IC_PINTYPE_LIST, + "index" = IC_PINTYPE_NUMBER, + "item" = IC_PINTYPE_ANY + ) + outputs = list( + "redacted list" = IC_PINTYPE_LIST + ) + icon_state = "addition" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/list/write/do_work() + var/list/input_list = get_pin_data(IC_INPUT, 1) + var/index = get_pin_data(IC_INPUT, 2) + var/item = get_pin_data(IC_INPUT, 3) + input_list[index] = item + set_pin_data(IC_OUTPUT, 1, input_list) + push_data() + activate_pin(2) + +obj/item/integrated_circuit/list/len + name = "len circuit" + desc = "This circuit will give length of the list." + inputs = list( + "list" = IC_PINTYPE_LIST, + ) + outputs = list( + "item" = IC_PINTYPE_NUMBER + ) + icon_state = "addition" + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + +/obj/item/integrated_circuit/list/len/do_work() + var/list/input_list = get_pin_data(IC_INPUT, 1) + set_pin_data(IC_OUTPUT, 1, input_list.len) + push_data() + activate_pin(2) + + /obj/item/integrated_circuit/list/jointext name = "join text circuit" desc = "This circuit will add all elements of a list into one string, seperated by a character." extended_desc = "Default settings will encode the entire list into a string." inputs = list( - "list to join" = IC_PINTYPE_LIST, + "list to join" = IC_PINTYPE_LIST,// "delimiter" = IC_PINTYPE_CHAR, "start" = IC_PINTYPE_NUMBER, "end" = IC_PINTYPE_NUMBER diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm index fa4fd9ded6..40f617e62e 100644 --- a/code/modules/integrated_electronics/subtypes/memory.dm +++ b/code/modules/integrated_electronics/subtypes/memory.dm @@ -40,8 +40,15 @@ O.push_data() activate_pin(2) +/obj/item/integrated_circuit/memory/tiny + name = "small memory circuit" + desc = "This circuit can store two pieces of data." + icon_state = "memory2" + power_draw_per_use = 2 + number_of_pins = 2 + /obj/item/integrated_circuit/memory/medium - name = "memory circuit" + name = "medium memory circuit" desc = "This circuit can store four pieces of data." icon_state = "memory4" power_draw_per_use = 2 diff --git a/code/modules/integrated_electronics/subtypes/power.dm b/code/modules/integrated_electronics/subtypes/power.dm index f528434129..e1e3f56c89 100644 --- a/code/modules/integrated_electronics/subtypes/power.dm +++ b/code/modules/integrated_electronics/subtypes/power.dm @@ -37,9 +37,7 @@ amount_to_move = 20000 /obj/item/integrated_circuit/power/transmitter/do_work() - set_pin_data(IC_OUTPUT, 1, null) - set_pin_data(IC_OUTPUT, 2, null) - set_pin_data(IC_OUTPUT, 3, null) + var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) if(AM) if(!assembly) @@ -72,7 +70,15 @@ set_pin_data(IC_OUTPUT, 2, cell.maxcharge) set_pin_data(IC_OUTPUT, 3, cell.percent()) activate_pin(2) + push_data() return TRUE + else + set_pin_data(IC_OUTPUT, 1, null) + set_pin_data(IC_OUTPUT, 2, null) + set_pin_data(IC_OUTPUT, 3, null) + activate_pin(2) + push_data() + return FALSE return FALSE /obj/item/integrated_circuit/power/transmitter/large/do_work() diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 25a80c2a28..e6d65bd07a 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -1,6 +1,8 @@ /obj/item/integrated_circuit/reagent 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() @@ -18,13 +20,23 @@ complexity = 20 cooldown_per_use = 30 SECONDS inputs = list() - outputs = list() - activators = list("create smoke" = IC_PINTYPE_PULSE_IN) + outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) + activators = list("create smoke" = IC_PINTYPE_PULSE_IN,"on smoked" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 3, TECH_DATA = 3, TECH_BIO = 3) volume = 100 power_draw_per_use = 20 +/obj/item/integrated_circuit/reagent/smoke/on_reagent_change() + set_pin_data(IC_OUTPUT, 1, reagents.total_volume) + push_data() + + +/obj/item/integrated_circuit/reagent/smoke/interact(mob/user) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + ..() + /obj/item/integrated_circuit/reagent/smoke/do_work() playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) var/datum/effect/effect/system/smoke_spread/chem/smoke_system = new() @@ -33,52 +45,141 @@ for(var/i = 1 to 8) smoke_system.start() reagents.clear_reagents() + activate_pin(2) /obj/item/integrated_circuit/reagent/injector name = "integrated hypo-injector" desc = "This scary looking thing is able to pump liquids into whatever it's pointed at." icon_state = "injector" extended_desc = "This autoinjector can push reagents into another container or someone else outside of the machine. The target \ - must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing." + must be adjacent to the machine, and if it is a person, they cannot be wearing thick clothing. A negative amount makes the injector draw out reagents." flags = OPENCONTAINER complexity = 20 cooldown_per_use = 6 SECONDS inputs = list("target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER) inputs_default = list("2" = 5) - outputs = list() - activators = list("inject" = IC_PINTYPE_PULSE_IN) + outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) + activators = list("inject" = IC_PINTYPE_PULSE_IN, "on injected" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH volume = 30 power_draw_per_use = 15 + var/direc = 1 + var/transfer_amount = 10 + +/obj/item/integrated_circuit/reagent/injector/interact(mob/user) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + ..() + + +/obj/item/integrated_circuit/reagent/injector/on_reagent_change() + set_pin_data(IC_OUTPUT, 1, reagents.total_volume) + push_data() + +/obj/item/integrated_circuit/reagent/injector/on_data_written() + var/new_amount = get_pin_data(IC_INPUT, 2) + if(new_amount < 0) + new_amount = -new_amount + direc = 0 + else + direc = 1 + if(isnum(new_amount)) + new_amount = Clamp(new_amount, 0, volume) + transfer_amount = new_amount -/obj/item/integrated_circuit/reagent/injector/proc/inject_amount() - var/amount = get_pin_data(IC_INPUT, 2) - if(isnum(amount)) - return Clamp(amount, 0, 30) /obj/item/integrated_circuit/reagent/injector/do_work() set waitfor = 0 // Don't sleep in a proc that is called by a processor without this set, otherwise it'll delay the entire thing - var/atom/movable/AM = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) if(!istype(AM)) //Invalid input + activate_pin(3) return - if(!reagents.total_volume) // Empty - return - if(AM.can_be_injected_by(src)) - if(isliving(AM)) - var/mob/living/L = AM - var/turf/T = get_turf(AM) - T.visible_message("[src] is trying to inject [L]!") - sleep(3 SECONDS) - if(!L.can_be_injected_by(src)) + + if(direc == 1) + + if(!istype(AM)) //Invalid input + activate_pin(3) + return + if(!reagents.total_volume) // Empty + activate_pin(3) + return + if(AM.can_be_injected_by(src)) + if(isliving(AM)) + var/mob/living/L = AM + var/turf/T = get_turf(AM) + T.visible_message("[src] is trying to inject [L]!") + sleep(3 SECONDS) + if(!L.can_be_injected_by(src)) + activate_pin(3) + return + var/contained = reagents.get_reagents() + var/trans = reagents.trans_to_mob(L, transfer_amount, CHEM_BLOOD) + message_admins("[src] injected \the [L] with [trans]u of [contained].") + to_chat(AM, "You feel a tiny prick!") + visible_message("[src] injects [L]!") + else + reagents.trans_to(AM, transfer_amount) + else + + if(reagents.total_volume >= volume) // Full + activate_pin(3) + return + var/obj/target = AM + if(!target.reagents) + activate_pin(3) + return + var/turf/TS = get_turf(src) + var/turf/TT = get_turf(AM) + if(!TS.Adjacent(TT)) + activate_pin(3) + return + var/tramount = Clamp(min(transfer_amount, reagents.maximum_volume - reagents.total_volume), 0, reagents.maximum_volume) + if(ismob(target))//Blood! + if(istype(target, /mob/living/carbon)) + var/mob/living/carbon/T = target + if(!T.dna) + if(T.reagents.trans_to_obj(src, tramount)) + activate_pin(2) + else + activate_pin(3) + return + if(NOCLONE in T.mutations) //target done been et, no more blood in him + if(T.reagents.trans_to_obj(src, tramount)) + activate_pin(2) + else + activate_pin(3) + return + return + var/datum/reagent/B + if(istype(T, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = T + if(H.species && !H.should_have_organ(O_HEART)) + H.reagents.trans_to_obj(src, tramount) + else + B = T.take_blood(src, tramount) + else + B = T.take_blood(src,tramount) + if (B) + reagents.reagent_list |= B + reagents.update_total() + on_reagent_change() + reagents.handle_reactions() + B = null + visible_message( "Machine takes a blood sample from [target].") + else + activate_pin(3) return - var/contained = reagents.get_reagents() - var/trans = reagents.trans_to_mob(L, inject_amount(), CHEM_BLOOD) - message_admins("[src] injected \the [L] with [trans]u of [contained].") - to_chat(AM, "You feel a tiny prick!") - visible_message("[src] injects [L]!") - else - reagents.trans_to(AM, inject_amount()) + + else //if not mob + if(!target.reagents.total_volume) + visible_message( "[target] is empty.") + activate_pin(3) + return + target.reagents.trans_to_obj(src, tramount) + activate_pin(2) + + + /obj/item/integrated_circuit/reagent/pump name = "reagent pump" @@ -96,11 +197,17 @@ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) var/transfer_amount = 10 + var/direc = 1 power_draw_per_use = 10 /obj/item/integrated_circuit/reagent/pump/on_data_written() var/new_amount = get_pin_data(IC_INPUT, 3) - if(!isnull(new_amount)) + if(new_amount < 0) + new_amount = -new_amount + direc = 0 + else + direc = 1 + if(isnum(new_amount)) new_amount = Clamp(new_amount, 0, 50) transfer_amount = new_amount @@ -111,17 +218,23 @@ if(!istype(source) || !istype(target)) //Invalid input return var/turf/T = get_turf(src) - if(source.Adjacent(T) && target.Adjacent(T)) + var/turf/TS = get_turf(source) + var/turf/TT = get_turf(target) + if(TS.Adjacent(T) && TT.Adjacent(T)) if(!source.reagents || !target.reagents) return if(ismob(source) || ismob(target)) return if(!source.is_open_container() || !target.is_open_container()) return - if(!target.reagents.get_free_space()) - return - - source.reagents.trans_to(target, transfer_amount) + if(direc) + if(!target.reagents.get_free_space()) + return + source.reagents.trans_to(target, transfer_amount) + else + if(!source.reagents.get_free_space()) + return + target.reagents.trans_to(source, transfer_amount) activate_pin(2) /obj/item/integrated_circuit/reagent/storage @@ -132,12 +245,18 @@ flags = OPENCONTAINER complexity = 4 inputs = list() - outputs = list("volume used" = IC_PINTYPE_NUMBER) + outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF) activators = list() spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) volume = 60 + +/obj/item/integrated_circuit/reagent/storage/interact(mob/user) + set_pin_data(IC_OUTPUT, 2, weakref(src)) + push_data() + ..() + /obj/item/integrated_circuit/reagent/storage/on_reagent_change() set_pin_data(IC_OUTPUT, 1, reagents.total_volume) push_data() @@ -150,4 +269,95 @@ flags = OPENCONTAINER | NOREACT complexity = 8 spawn_flags = IC_SPAWN_RESEARCH - origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) \ No newline at end of file + origin_tech = list(TECH_MATERIALS = 4, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + +/obj/item/integrated_circuit/reagent/storage/big + name = "big reagent storage" + desc = "Stores liquid inside, and away from electrical components. Can store up to 180u." + icon_state = "reagent_storage_big" + extended_desc = "This is effectively an internal beaker." + flags = OPENCONTAINER + complexity = 16 + volume = 180 + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_MATERIALS = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + +/obj/item/integrated_circuit/reagent/storage/scan + name = "reagent scanner" + desc = "Stores liquid inside, and away from electrical components. Can store up to 60u. On pulse this beaker will send list of contained reagents." + icon_state = "reagent_scan" + extended_desc = "Mostly useful for reagent filter." + flags = OPENCONTAINER + complexity = 8 + outputs = list("volume used" = IC_PINTYPE_NUMBER,"self reference" = IC_PINTYPE_REF,"list of reagents" = IC_PINTYPE_LIST) + activators = list("scan" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_RESEARCH + origin_tech = list(TECH_MATERIALS = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + +/obj/item/integrated_circuit/reagent/storage/scan/do_work() + var/cont[0] + for(var/datum/reagent/RE in reagents.reagent_list) + cont += RE.id + set_pin_data(IC_OUTPUT, 3, cont) + push_data() + + +/obj/item/integrated_circuit/reagent/filter + name = "reagent filter" + desc = "Filtering liquids by list of desired or unwanted reagents." + icon_state = "reagent_filter" + extended_desc = "This is a filter which will move liquids from the source ref to the target ref. \ + It will move all reagents, except list, given in fourth pin if amount value is positive.\ + Or it will move only desired reagents if amount is negative, The third pin determines \ + how much reagent is moved per pulse, between 0 and 50. Amount is given for each separate reagent." + flags = OPENCONTAINER + complexity = 8 + inputs = list("source" = IC_PINTYPE_REF, "target" = IC_PINTYPE_REF, "injection amount" = IC_PINTYPE_NUMBER, "list of reagents" = IC_PINTYPE_LIST) + inputs_default = list("3" = 5) + outputs = list() + activators = list("transfer reagents" = IC_PINTYPE_PULSE_IN, "on transfer" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) + var/transfer_amount = 10 + var/direc = 1 + power_draw_per_use = 10 + +/obj/item/integrated_circuit/reagent/filter/on_data_written() + var/new_amount = get_pin_data(IC_INPUT, 3) + if(new_amount < 0) + new_amount = -new_amount + direc = 0 + else + direc = 1 + if(isnum(new_amount)) + new_amount = Clamp(new_amount, 0, 50) + transfer_amount = new_amount + +/obj/item/integrated_circuit/reagent/filter/do_work() + var/atom/movable/source = get_pin_data_as_type(IC_INPUT, 1, /atom/movable) + var/atom/movable/target = get_pin_data_as_type(IC_INPUT, 2, /atom/movable) + var/list/demand = get_pin_data(IC_INPUT, 4) + if(!istype(source) || !istype(target)) //Invalid input + return + var/turf/T = get_turf(src) + if(source.Adjacent(T) && target.Adjacent(T)) + if(!source.reagents || !target.reagents) + return + if(ismob(source) || ismob(target)) + return + if(!source.is_open_container() || !target.is_open_container()) + return + if(!target.reagents.get_free_space()) + return + for(var/datum/reagent/G in source.reagents.reagent_list) + if (!direc) + if(G.id in demand) + source.reagents.trans_id_to(target, G.id, transfer_amount) + else + if(!(G.id in demand)) + source.reagents.trans_id_to(target, G.id, transfer_amount) + activate_pin(2) + push_data() + + + diff --git a/code/modules/mob/_modifiers/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm index ee6d914fa6..3facabe6f9 100644 --- a/code/modules/mob/_modifiers/modifiers.dm +++ b/code/modules/mob/_modifiers/modifiers.dm @@ -41,6 +41,7 @@ var/accuracy // Positive numbers makes hitting things with guns easier, negatives make it harder. Each point makes it 15% easier or harder, just like evasion. var/accuracy_dispersion // Positive numbers make gun firing cover a wider tile range, and therefore more inaccurate. Negatives help negate dispersion penalties. var/metabolism_percent // Adjusts the mob's metabolic rate, which affects reagent processing. Won't affect mobs without reagent processing. + var/icon_scale_percent // Makes the holder's icon get scaled up or down. /datum/modifier/New(var/new_holder, var/new_origin) holder = new_holder @@ -62,6 +63,8 @@ holder.modifiers.Remove(src) if(mob_overlay_state) // We do this after removing ourselves from the list so that the overlay won't remain. holder.update_modifier_visuals() + if(icon_scale_percent) // Correct the scaling. + holder.update_transform() qdel(src) // Override this for special effects when it gets removed. @@ -117,6 +120,8 @@ modifiers.Add(mod) if(mod.mob_overlay_state) update_modifier_visuals() + if(mod.icon_scale_percent) + update_transform() return mod @@ -198,6 +203,8 @@ effects += "Your metabolism is [metabolism_percent > 1.0 ? "faster" : "slower"], \ causing reagents in your body to process, and hunger to occur [multipler_to_percentage(metabolism_percent, TRUE)] [metabolism_percent > 1.0 ? "faster" : "slower"]." + if(!isnull(icon_scale_percent)) + effects += "Your appearance is [multipler_to_percentage(icon_scale_percent, TRUE)] [icon_scale_percent > 1 ? "larger" : "smaller"]." return jointext(effects, "
") diff --git a/code/modules/mob/_modifiers/traits.dm b/code/modules/mob/_modifiers/traits.dm index 824343c41c..3e9e8278e4 100644 --- a/code/modules/mob/_modifiers/traits.dm +++ b/code/modules/mob/_modifiers/traits.dm @@ -58,4 +58,28 @@ desc = "Your body's metabolism is slower than average." metabolism_percent = 0.5 - incoming_healing_percent = 0.6 \ No newline at end of file + incoming_healing_percent = 0.6 + +/datum/modifier/trait/larger + name = "Larger" + desc = "Your body is larger than average." + + icon_scale_percent = 1.2 + +/datum/modifier/trait/large + name = "Large" + desc = "Your body is a bit larger than average." + + icon_scale_percent = 1.1 + +/datum/modifier/trait/small + name = "Small" + desc = "Your body is a bit smaller than average." + + icon_scale_percent = 0.95 + +/datum/modifier/trait/smaller + name = "Smaller" + desc = "Your body is smaller than average." + + icon_scale_percent = 0.9 \ No newline at end of file diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 83bf724607..52426454e2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -201,6 +201,11 @@ Works together with spawning an observer, noted above. /mob/proc/ghostize(var/can_reenter_corpse = 1) if(key) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(H.vr_holder && !can_reenter_corpse) + H.exit_vr() + return 0 var/mob/observer/dead/ghost = new(src) //Transfer safety to observer spawning proc. ghost.can_reenter_corpse = can_reenter_corpse ghost.timeofdeath = src.timeofdeath //BS12 EDIT @@ -243,9 +248,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/turf/location = get_turf(src) message_admins("[key_name_admin(usr)] has ghosted. (JMP)") log_game("[key_name_admin(usr)] has ghosted.") - var/mob/observer/dead/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 - ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. - announce_ghost_joinleave(ghost) + var/mob/observer/dead/ghost = ghostize(0) // 0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 + if(ghost) + ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. + announce_ghost_joinleave(ghost) /mob/observer/dead/can_use_hands() return 0 /mob/observer/dead/is_active() return 0 @@ -310,19 +316,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!client) return - var/mentor = is_eventM(usr.client) - if(!config.antag_hud_allowed && (!client.holder || mentor)) + if(!config.antag_hud_allowed && !client.holder) src << "Admins have disabled this for this round." return var/mob/observer/dead/M = src if(jobban_isbanned(M, "AntagHUD")) src << "You have been banned from using this feature" return - if(config.antag_hud_restricted && !M.has_enabled_antagHUD && (!client.holder || mentor)) + if(config.antag_hud_restricted && !M.has_enabled_antagHUD && !client.holder) var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No") if(response == "No") return M.can_reenter_corpse = 0 - if(!M.has_enabled_antagHUD && (!client.holder || mentor)) + if(!M.has_enabled_antagHUD && !client.holder) M.has_enabled_antagHUD = 1 if(M.antagHUD) M.antagHUD = 0 diff --git a/code/modules/mob/living/carbon/alien/alien_attacks.dm b/code/modules/mob/living/carbon/alien/alien_attacks.dm index e201e85116..c120b9deef 100644 --- a/code/modules/mob/living/carbon/alien/alien_attacks.dm +++ b/code/modules/mob/living/carbon/alien/alien_attacks.dm @@ -15,7 +15,7 @@ if (I_GRAB) if (M == src) return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, src ) M.put_in_active_hand(G) @@ -56,4 +56,4 @@ for(var/mob/O in viewers(src, null)) if ((O.client && !( O.blinded ))) O.show_message(text("[] has attempted to punch []!", M, src), 1) - return \ No newline at end of file + return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 194864b7de..233f0f020f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -109,20 +109,28 @@ playsound(loc, "sparks", 50, 1, -1) if (shock_damage > 15) src.visible_message( - "[src] was shocked by \the [source]!", \ - "You feel a powerful shock course through your body!", \ - "You hear a heavy electrical crack." \ + "[src] was electrocuted[source ? " by the [source]" : ""]!", \ + "You feel a powerful shock course through your body!", \ + "You hear a heavy electrical crack." \ ) - if(stun) - Stun(10)//This should work for now, more is really silly and makes you lay there forever - Weaken(10) else src.visible_message( - "[src] was mildly shocked by \the [source].", \ - "You feel a mild shock course through your body.", \ - "You hear a light zapping." \ + "[src] was shocked[source ? " by the [source]" : ""].", \ + "You feel a shock course through your body.", \ + "You hear a zapping sound." \ ) + if(stun) + switch(shock_damage) + if(16 to 20) + Stun(2) + if(21 to 25) + Weaken(2) + if(26 to 30) + Weaken(5) + if(31 to INFINITY) + Weaken(10) //This should work for now, more is really silly and makes you lay there forever + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, loc) s.start() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 66ba7ecd51..08d0c9384e 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -25,7 +25,7 @@ weapon_edge = 0 hit_embed_chance = I.force/(I.w_class*3) - apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) + apply_damage(effective_force, I.damtype, hit_zone, blocked, soaked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) //Melee weapon embedded object code. if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I) && I.embed_chance > 0) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index ffac791a1f..8df0bd1605 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -1,5 +1,15 @@ /mob/living/carbon/human/gib() + if(vr_holder) + exit_vr() + // Delete the link, because this mob won't be around much longer + vr_holder.vr_link = null + + if(vr_link) + vr_link.exit_vr() + vr_link.vr_holder = null + vr_link = null + for(var/obj/item/organ/I in internal_organs) I.removed() if(istype(loc,/turf)) @@ -80,6 +90,20 @@ if(wearing_rig) wearing_rig.notify_ai("Warning: user death event. Mobility control passed to integrated intelligence system.") + // If the body is in VR, move the mind back to the real world + if(vr_holder) + src.exit_vr() + src.vr_holder.vr_link = null + for(var/obj/item/W in src) + src.drop_from_inventory(W) + + // If our mind is in VR, bring it back to the real world so it can die with its body + if(vr_link) + vr_link.exit_vr() + vr_link.vr_holder = null + vr_link = null + to_chat(src, "Everything abruptly stops.") + return ..(gibbed,species.get_death_message(src)) /mob/living/carbon/human/proc/ChangeToHusk() @@ -113,4 +137,4 @@ mutations.Add(SKELETON) status_flags |= DISFIGURED update_body(1) - return + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 615a3ecf53..81ea775ab9 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -18,17 +18,9 @@ var/skiparms = 0 var/skipfeet = 0 - - var/cloaked = 0 // 0 for normal, 1 for cloaked close - - if(mind && mind.changeling && mind.changeling.cloaked && !istype(user, /mob/observer)) - var/distance = get_dist(user, src) - if(distance > 2) - src.loc.examine(user) - return - else - cloaked = 1 - + if(alpha <= 50) + src.loc.examine(user) + return var/looks_synth = looksSynthetic() @@ -97,8 +89,6 @@ if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender T = gender_datums[PLURAL] - if(cloaked) - T = gender_datums[NEUTER] else if(species && species.ambiguous_genders) var/can_detect_gender = FALSE @@ -458,25 +448,18 @@ msg += "Medical records: \[View\] \[Add comment\]\n" - if(print_flavor_text() && !cloaked) + if(print_flavor_text()) msg += "[print_flavor_text()]\n" msg += "*---------*
" msg += applying_pressure - if (pose && !cloaked) + if (pose) if( findtext(pose,".",lentext(pose)) == 0 && findtext(pose,"!",lentext(pose)) == 0 && findtext(pose,"?",lentext(pose)) == 0 ) pose = addtext(pose,".") //Makes sure all emotes end with a period. msg += "[T.He] [pose]" user << jointext(msg, null) - -/mob/living/carbon/human/get_description_fluff() - if(mind && mind.changeling && mind.changeling.cloaked) - return "" - else - return ..() - //Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records. /proc/hasHUD(mob/M as mob, hudtype) if(istype(M, /mob/living/carbon/human)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index ab16e58263..92ea71f829 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -318,8 +318,6 @@ //repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere /mob/living/carbon/human/proc/get_visible_name() - if( mind && mind.changeling && mind.changeling.cloaked) - return "Unknown" if( wear_mask && (wear_mask.flags_inv&HIDEFACE) ) //Wearing a mask which hides our face, use id-name if possible return get_id_name("Unknown") if( head && (head.flags_inv&HIDEFACE) ) @@ -1136,6 +1134,9 @@ if(species.default_language) add_language(species.default_language) + if(species.icon_scale != 1) + update_transform() + if(species.base_color && default_colour) //Apply colour. r_skin = hex2num(copytext(species.base_color,2,4)) @@ -1523,4 +1524,55 @@ var/turf/T = get_turf(src) var/obj/item/clothing/accessory/permit/drone/permit = new(T) permit.set_name(real_name) - equip_to_appropriate_slot(permit) // If for some reason it can't find room, it'll still be on the floor. \ No newline at end of file + equip_to_appropriate_slot(permit) // If for some reason it can't find room, it'll still be on the floor. + +// enter_vr is called on the original mob, and puts the mind into the supplied vr mob +/mob/living/carbon/human/proc/enter_vr(var/mob/living/carbon/human/avatar) // Avatar is currently a human, because we have preexisting setup code for appearance manipulation, etc. + if(!istype(avatar)) + return + + // Link the two mobs for client transfer + avatar.vr_holder = src + src.teleop = avatar + src.vr_link = avatar // Can't reuse vr_holder so that death can automatically eject users from VR + + // Move the mind + avatar.Sleeping(1) + src.mind.transfer_to(avatar) + to_chat(avatar, "You have enterred Virtual Reality!\nAll normal gameplay rules still apply.\nWounds you suffer here won't persist when you leave VR, but some of the pain will.\nYou can leave VR at any time by using the \"Exit Virtual Reality\" verb in the Abilities tab, or by ghosting.\nYou can modify your appearance by using various \"Change \[X\]\" verbs in the Abilities tab.") + to_chat(avatar, " You black out for a moment, and wake to find yourself in a new body in virtual reality.") // So this is what VR feels like? + +// exit_vr is called on the vr mob, and puts the mind back into the original mob +/mob/living/carbon/human/verb/exit_vr() + set name = "Exit Virtual Reality" + set category = "Abilities" + + if(!vr_holder) + return + if(!mind) + return + + var/total_damage + // Tally human damage + if(ishuman(src)) + var/mob/living/carbon/human/H = src + total_damage = H.getBruteLoss() + H.getFireLoss() + H.getOxyLoss() + H.getToxLoss() + + // Move the mind back to the original mob +// vr_holder.Sleeping(1) + src.mind.transfer_to(vr_holder) + to_chat(vr_holder, "You black out for a moment, and wake to find yourself back in your own body.") + // Two-thirds damage is transferred as agony for /humans + // Getting hurt in VR doesn't damage the physical body, but you still got hurt. + if(ishuman(vr_holder) && total_damage) + var/mob/living/carbon/human/V = vr_holder + V.stun_effect_act(0, total_damage*2/3, null) // 200 damage leaves the user in paincrit for several seconds, agony reaches 0 after around 2m. + to_chat(vr_holder, "Pain from your time in VR lingers.") // 250 damage leaves the user unconscious for several seconds in addition to paincrit + + // Maintain a link with the mob, but don't use teleop + vr_holder.vr_link = src + vr_holder.teleop = null + + if(istype(vr_holder.loc, /obj/machinery/vr_sleeper)) + var/obj/machinery/vr_sleeper/V = vr_holder.loc + V.go_out() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 34ab2bf4bb..28bf5300cc 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -425,9 +425,9 @@ This function restores all organs. zone = BP_HEAD return organs_by_name[zone] -/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0, var/edge = 0, var/obj/used_weapon = null) +/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/sharp = 0, var/edge = 0, var/obj/used_weapon = null) if(Debug2) - world.log << "## DEBUG: human/apply_damage() was called on [src], with [damage] damage, and an armor value of [blocked]." + world.log << "## DEBUG: human/apply_damage() was called on [src], with [damage] damage, an armor value of [blocked], and a soak value of [soaked]." var/obj/item/organ/external/organ = null if(isorgan(def_zone)) @@ -442,7 +442,7 @@ This function restores all organs. if((damage > 25 && prob(20)) || (damage > 50 && prob(60))) if(organ && organ.organ_can_feel_pain()) emote("scream") - ..(damage, damagetype, def_zone, blocked) + ..(damage, damagetype, def_zone, blocked, soaked) return 1 //Handle BRUTE and BURN damage @@ -451,12 +451,18 @@ This function restores all organs. if(blocked >= 100) return 0 + if(soaked >= damage) + return 0 if(!organ) return 0 if(blocked) blocked = (100-blocked)/100 damage = (damage * blocked) + + if(soaked) + damage -= soaked + if(Debug2) world.log << "## DEBUG: [src] was hit for [damage]." diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a09dad7dba..fbb98c3f98 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -29,7 +29,6 @@ var/g_synth //Same as above var/b_synth //Same as above - var/size_multiplier = 1 //multiplier for the mob's icon size var/damage_multiplier = 1 //multiplies melee combat damage var/icon_update = 1 //whether icon updating shall take place @@ -103,3 +102,8 @@ var/step_count = 0 // Track how many footsteps have been taken to know when to play footstep sounds can_be_antagged = TRUE + +// Used by mobs in virtual reality to point back to the "real" mob the client belongs to. + var/mob/living/carbon/human/vr_holder = null + // Used by "real" mobs after they leave a VR session + var/mob/living/carbon/human/vr_link = null \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index bb5d989e45..61bded2e15 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -30,6 +30,8 @@ var/tail_animation // If set, the icon to obtain tail animation states from. var/tail_hair + var/icon_scale = 1 // Makes the icon larger/smaller. + var/race_key = 0 // Used for mob icon cache string. var/icon/icon_template // Used for mob icon generation for non-32x32 species. var/mob_size = MOB_MEDIUM @@ -275,11 +277,14 @@ var/t_him = "them" if(ishuman(target)) var/mob/living/carbon/human/T = target - switch(T.identifying_gender) - if(MALE) - t_him = "him" - if(FEMALE) - t_him = "her" + if(!T.species.ambiguous_genders || (T.species.ambiguous_genders && H.species == T.species)) + switch(T.identifying_gender) + if(MALE) + t_him = "him" + if(FEMALE) + t_him = "her" + else + t_him = "them" else switch(target.gender) if(MALE) diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm index 1fb7b6c300..11a50c1316 100644 --- a/code/modules/mob/living/carbon/human/species/species_shapeshift.dm +++ b/code/modules/mob/living/carbon/human/species/species_shapeshift.dm @@ -148,9 +148,16 @@ var/list/wrapped_species_by_ref = list() last_special = world.time + 50 - var/new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src) + var/new_species = null + new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src) + if(!new_species || !all_species[new_species] || wrapped_species_by_ref["\ref[src]"] == new_species) return + shapeshifter_change_shape(new_species) + +/mob/living/carbon/human/proc/shapeshifter_change_shape(var/new_species = null) + if(!new_species) + return wrapped_species_by_ref["\ref[src]"] = new_species visible_message("\The [src] shifts and contorts, taking the form of \a [new_species]!") diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm index 5ab786f8f6..a894ce52ee 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm @@ -85,7 +85,7 @@ var/datum/species/shapeshifter/promethean/prometheans /mob/living/carbon/human/proc/regenerate ) - valid_transform_species = list("Human", "Unathi", "Tajara", "Skrell", "Diona", "Teshari", "Monkey") + valid_transform_species = list("Human", "Vatborn", "Unathi", "Tajara", "Skrell", "Diona", "Teshari", "Monkey") monochromatic = 1 var/heal_rate = 0.5 // Temp. Regen per tick. diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index f07ff9b119..372451808e 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -39,6 +39,8 @@ burn_mod = 0.85 metabolic_rate = 0.85 item_slowdown_mod = 0.5 + mob_size = MOB_LARGE + blood_volume = 840 num_alternate_languages = 3 secondary_langs = list(LANGUAGE_UNATHI) name_language = LANGUAGE_UNATHI diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm new file mode 100644 index 0000000000..8fbf47022d --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm @@ -0,0 +1,32 @@ +// ### Wooo, inheritance. Basically copying everything I don't need to edit from prometheans, because they mostly work already. +// ### Any and all of this is open to change for balance or whatever. +// ### +// ### +// Species definition follows. +/datum/species/shapeshifter/promethean/avatar + + name = "Virtual Reality Avatar" + name_plural = "Virtual Reality Avatars" + blurb = "A 3-dimensional representation of some sort of animate object used to display the presence and actions of some-one or -thing using a virtual reality program." + show_ssd = "eerily still" + death_message = "flickers briefly, their gear falling in a heap on the floor around their motionless body." + knockout_message = "has been knocked unconscious!" + + spawn_flags = SPECIES_IS_RESTRICTED + + speech_bubble_appearance = "cyber" + + male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg') + female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg') + male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg' + female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg' + + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite) + has_organ = list(O_BRAIN = /obj/item/organ/internal/brain/slime, O_EYES = /obj/item/organ/internal/eyes) // Slime core. + heal_rate = 0 // Avatars don't naturally heal like prometheans, at least not for now + +/datum/species/shapeshifter/promethean/avatar/handle_death(var/mob/living/carbon/human/H) + return + +/datum/species/shapeshifter/promethean/avatar/handle_environment_special(var/mob/living/carbon/human/H) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 0909ed2575..ebaa6866e0 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -159,16 +159,29 @@ Please contact me on #coderbus IRC. ~Carn x for(var/inner_entry in entry) overlays += inner_entry + update_transform() + +/mob/living/carbon/human/update_transform() + // First, get the correct size. + var/desired_scale = icon_scale + + desired_scale *= species.icon_scale + + for(var/datum/modifier/M in modifiers) + if(!isnull(M.icon_scale_percent)) + desired_scale *= M.icon_scale_percent + + // Regular stuff again. if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. var/matrix/M = matrix() M.Turn(90) - M.Scale(size_multiplier) + M.Scale(desired_scale) M.Translate(1,-6) src.transform = M else var/matrix/M = matrix() - M.Scale(size_multiplier) - M.Translate(0, 16*(size_multiplier-1)) + M.Scale(desired_scale) + M.Translate(0, 16*(desired_scale-1)) src.transform = M var/global/list/damage_icon_parts = list() @@ -293,6 +306,8 @@ var/global/list/damage_icon_parts = list() base_icon = chest.get_icon() for(var/obj/item/organ/external/part in organs) + if(isnull(part) || part.is_stump()) + continue var/icon/temp = part.get_icon(skeleton) //That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST //And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part) @@ -381,11 +396,13 @@ var/global/list/damage_icon_parts = list() face_standing.Blend(facial_s, ICON_OVERLAY) if(h_style && !(head && (head.flags_inv & BLOCKHEADHAIR))) - var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + var/datum/sprite_accessory/hair/hair_style = hair_styles_list[h_style] if(hair_style && (src.species.get_bodytype(src) in hair_style.species_allowed)) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + var/icon/hair_s_add = new/icon("icon" = hair_style.icon_add, "icon_state" = "[hair_style.icon_state]_s") if(hair_style.do_colouration) - hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_MULTIPLY) + hair_s.Blend(hair_s_add, ICON_ADD) face_standing.Blend(hair_s, ICON_OVERLAY) @@ -503,7 +520,16 @@ var/global/list/damage_icon_parts = list() //need to append _s to the icon state for legacy compatibility var/image/standing = image(icon = under_icon, icon_state = "[under_state]_s") - standing.color = w_uniform.color + + if(w_uniform.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = w_uniform.addblends) + if(w_uniform.color) + base.Blend(w_uniform.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = w_uniform.color //apply blood overlay if(w_uniform.blood_DNA) @@ -567,7 +593,15 @@ var/global/list/damage_icon_parts = list() bloodsies.color = gloves.blood_color standing.overlays += bloodsies gloves.screen_loc = ui_gloves - standing.color = gloves.color + if(gloves.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = gloves.addblends) + if(gloves.color) + base.Blend(gloves.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = gloves.color overlays_standing[GLOVES_LAYER] = standing else if(blood_DNA) @@ -588,7 +622,15 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = glasses.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[glasses.icon_state]") else standing = image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]") - standing.color = glasses.color + if(glasses.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = glasses.addblends) + if(glasses.color) + base.Blend(glasses.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = glasses.color overlays_standing[GLASSES_LAYER] = standing else @@ -616,7 +658,15 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = l_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]") else standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") - standing.color = l_ear.color + if(l_ear.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = l_ear.addblends) + if(l_ear.color) + base.Blend(l_ear.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = l_ear.color both.overlays += standing if(r_ear) @@ -630,7 +680,15 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = r_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]") else standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") - standing.color = r_ear.color + if(r_ear.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = r_ear.addblends) + if(r_ear.color) + base.Blend(r_ear.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = r_ear.color both.overlays += standing overlays_standing[EARS_LAYER] = both @@ -664,8 +722,18 @@ var/global/list/damage_icon_parts = list() var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "shoeblood") bloodsies.color = shoes.blood_color standing.overlays += bloodsies - standing.color = shoes.color + + if(shoes.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = shoes.addblends) + if(shoes.color) + base.Blend(shoes.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = shoes.color overlays_standing[shoe_layer] = standing + else if(feet_blood_DNA) var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "shoeblood") @@ -731,7 +799,15 @@ var/global/list/damage_icon_parts = list() if(hat.on && light_overlay_cache[cache_key]) standing.overlays |= light_overlay_cache[cache_key] - standing.color = head.color + if(head.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = head.addblends) + if(head.color) + base.Blend(head.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = head.color overlays_standing[HEAD_LAYER] = standing else @@ -766,7 +842,15 @@ var/global/list/damage_icon_parts = list() if(!i_state) i_state = i.icon_state standing.overlays += image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[i_state]") - standing.color = belt.color + if(belt.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = belt.addblends) + if(belt.color) + base.Blend(belt.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = belt.color overlays_standing[belt_layer] = standing else @@ -791,7 +875,16 @@ var/global/list/damage_icon_parts = list() t_icon = wear_suit.item_icons[slot_wear_suit_str] standing = image("icon" = t_icon, "icon_state" = "[wear_suit.icon_state]") - standing.color = wear_suit.color + + if(wear_suit.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = wear_suit.addblends) + if(wear_suit.color) + base.Blend(wear_suit.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = wear_suit.color if( istype(wear_suit, /obj/item/clothing/suit/straight_jacket) ) drop_from_inventory(handcuffed) @@ -841,7 +934,15 @@ var/global/list/damage_icon_parts = list() standing = image("icon" = wear_mask.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[wear_mask.icon_state]") else standing = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]") - standing.color = wear_mask.color + if(wear_mask.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = wear_mask.addblends) + if(wear_mask.color) + base.Blend(wear_mask.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = wear_mask.color if( !istype(wear_mask, /obj/item/clothing/mask/smokable/cigarette) && wear_mask.blood_DNA ) var/image/bloodsies = image("icon" = species.get_blood_mask(src), "icon_state" = "maskblood") @@ -883,7 +984,15 @@ var/global/list/damage_icon_parts = list() //apply color var/image/standing = image(icon = overlay_icon, icon_state = overlay_state) - standing.color = back.color + if(back.addblends) + var/icon/base = new/icon("icon" = standing.icon, "icon_state" = standing.icon_state) + var/addblend_icon = new/icon("icon" = standing.icon, "icon_state" = back.addblends) + if(back.color) + base.Blend(back.color, ICON_MULTIPLY) + base.Blend(addblend_icon, ICON_ADD) + standing = image(base) + else + standing.color = back.color //create the image overlays_standing[BACK_LAYER] = standing diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 22289c6b43..07997851ef 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -34,6 +34,8 @@ adjustCloneLoss(damage * blocked) if(HALLOSS) adjustHalLoss(damage * blocked) + if(ELECTROCUTE) + electrocute_act(damage, used_weapon, 1.0, def_zone) flash_weak_pain() updatehealth() return 1 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b87eac5a1d..c6fd9b20e9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1004,3 +1004,17 @@ default behaviour is: // Called by job_controller. /mob/living/proc/equip_post_job() return + + +/mob/living/update_transform() + // First, get the correct size. + var/desired_scale = icon_scale + for(var/datum/modifier/M in modifiers) + if(!isnull(M.icon_scale_percent)) + desired_scale *= M.icon_scale_percent + + // Now for the regular stuff. + var/matrix/M = matrix() + M.Scale(desired_scale) + M.Translate(0, 16*(desired_scale-1)) + src.transform = M \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index ad3a41fbc8..b48a1609d9 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -17,10 +17,6 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/show_laws_verb, /mob/living/silicon/ai/proc/toggle_acceleration, /mob/living/silicon/ai/proc/toggle_hologram_movement, - /mob/living/silicon/ai/proc/toggle_hidden_verbs, -) - -var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.com/1172/, /mob/living/silicon/ai/proc/ai_announcement, /mob/living/silicon/ai/proc/ai_call_shuttle, /mob/living/silicon/ai/proc/ai_camera_track, @@ -160,6 +156,7 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c add_language(LANGUAGE_EAL, 1) add_language(LANGUAGE_SCHECHI, 1) add_language(LANGUAGE_SIGN, 1) + add_language(LANGUAGE_ROOTLOCAL, 1) if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. @@ -794,16 +791,5 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c if(rig) rig.force_rest(src) -/mob/living/silicon/ai/proc/toggle_hidden_verbs() - set name = "Toggle Hidden Verbs" - set category = "AI Settings" - - if(/mob/living/silicon/ai/proc/ai_announcement in verbs) - src << "Extra verbs toggled off." - verbs -= ai_verbs_hidden - else - src << "Extra verbs toggled on." - verbs |= ai_verbs_hidden - #undef AI_CHECK_WIRELESS #undef AI_CHECK_RADIO diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index f516486f02..6c3cd7f1db 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -9,7 +9,7 @@ health = 200 mob_bump_flag = ROBOT - mob_swap_flags = ROBOT|MONKEY|SLIME|SIMPLE_ANIMAL + mob_swap_flags = ~HEAVY mob_push_flags = ~HEAVY //trundle trundle var/lights_on = 0 // Is our integrated light on? @@ -394,6 +394,11 @@ C.toggled = 1 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" + set name = "Emit Sparks" + spark_system.start() + // this function displays jetpack pressure in the stat panel /mob/living/silicon/robot/proc/show_jetpack_pressure() // if you have a jetpack, show the internal tank pressure @@ -637,7 +642,8 @@ else if( !(istype(W, /obj/item/device/robotanalyzer) || istype(W, /obj/item/device/healthanalyzer)) ) - spark_system.start() + if(W.force > 0) + spark_system.start() return ..() /mob/living/silicon/robot/attack_hand(mob/user) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 32a5a9cb35..c21ab59def 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -90,6 +90,7 @@ var/assist_distance = 25 // Radius in which I'll ask my comrades for help. var/supernatural = 0 // If the mob is supernatural (used in null-rod stuff for banishing?) var/grab_resist = 75 // Chance of me resisting a grab attempt. + var/taser_kill = 1 // Is the mob weak to tasers //Attack ranged settings var/ranged = 0 // Do I attack at range? @@ -107,7 +108,9 @@ var/friendly = "nuzzles" // What mobs do to people when they aren't really hostile var/attack_sound = null // Sound to play when I attack var/environment_smash = 0 // How much environment damage do I do when I hit stuff? - var/melee_miss_chance = 25 // percent chance to miss a melee attack. + var/melee_miss_chance = 15 // percent chance to miss a melee attack. + var/melee_attack_minDelay = 5 // How long between attacks at least + var/melee_attack_maxDelay = 10 // How long between attacks at most //Special attacks var/spattack_prob = 0 // Chance of the mob doing a special attack (0 for never) @@ -1168,7 +1171,7 @@ if(!Adjacent(target_mob)) return if(!client) - sleep(rand(8) + 8) + sleep(rand(melee_attack_minDelay, melee_attack_maxDelay)) if(isliving(target_mob)) var/mob/living/L = target_mob @@ -1437,16 +1440,30 @@ //Shot with taser/stunvolver /mob/living/simple_animal/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) - var/stunDam = 0 - var/agonyDam = 0 + if(taser_kill) + var/stunDam = 0 + var/agonyDam = 0 - if(stun_amount) - stunDam += stun_amount * 0.5 - adjustFireLoss(stunDam) + if(stun_amount) + stunDam += stun_amount * 0.5 + adjustFireLoss(stunDam) - if(agony_amount) - agonyDam += agony_amount * 0.5 - adjustFireLoss(agonyDam) + if(agony_amount) + agonyDam += agony_amount * 0.5 + adjustFireLoss(agonyDam) + +/mob/living/simple_animal/emp_act(severity) + if(!isSynthetic()) + return + switch(severity) + if(1) + adjustFireLoss(rand(15, 25)) + if(2) + adjustFireLoss(rand(10, 18)) + if(3) + adjustFireLoss(rand(5, 12)) + if(4) + adjustFireLoss(rand(1, 6)) // Force it to target something /mob/living/simple_animal/proc/taunt(var/mob/living/new_target, var/forced = FALSE) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 92a8b3bdeb..6063526c89 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -534,6 +534,7 @@ if(M != usr) return if(usr == src) return if(!Adjacent(usr)) return + if(usr.incapacitated(INCAPACITATION_STUNNED | INCAPACITATION_FORCELYING | INCAPACITATION_KNOCKOUT | INCAPACITATION_RESTRAINED)) return //Incapacitated. if(istype(M,/mob/living/silicon/ai)) return show_inv(usr) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 56104d34f4..b7fdd7714d 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -400,7 +400,7 @@ proc/is_blind(A) return // Can't talk in deadchat if you can't see it. for(var/mob/M in player_list) - if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && !is_eventM(M.client))) && M.is_preference_enabled(/datum/client_preference/show_dsay)) + if(M.client && (!istype(M, /mob/new_player) && M.stat == DEAD) && M.is_preference_enabled(/datum/client_preference/show_dsay)) var/follow var/lname if(M.forbid_seeing_deadchat && !M.client.holder) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 5fa306b7b9..a96524f1f1 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -258,7 +258,7 @@ mannequin.delete_inventory(TRUE) dress_preview_mob(mannequin) - preview_icon = icon('icons/effects/effects.dmi', "nothing") + preview_icon = icon('icons/effects/128x48.dmi', bgstate) preview_icon.Scale(48+32, 16+32) mannequin.dir = NORTH diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 42bc1280e2..4b729f0a70 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -45,7 +45,8 @@ /datum/sprite_accessory/hair - icon = 'icons/mob/Human_face.dmi' // default icon for all hairs + icon = 'icons/mob/Human_face_m.dmi' // default icon for all hairs + var/icon_add = 'icons/mob/human_face.dmi' bald name = "Bald" @@ -323,7 +324,7 @@ name = "Overeye Long" icon_state = "hair_longovereye" - fag + flowhair name = "Flow Hair" icon_state = "hair_f" diff --git a/code/modules/organs/internal/appendix.dm b/code/modules/organs/internal/appendix.dm index f756b71efa..01d7008a09 100644 --- a/code/modules/organs/internal/appendix.dm +++ b/code/modules/organs/internal/appendix.dm @@ -18,6 +18,8 @@ return 0 /obj/item/organ/internal/appendix/process() + ..() + if(!inflamed || !owner) return diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 28fbf62f1e..7dd2bd948e 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -44,21 +44,6 @@ tmp_owner.internal_organs_by_name[organ_tag] = new replace_path(tmp_owner, 1) tmp_owner = null -/obj/item/organ/internal/pariah_brain - name = "brain remnants" - desc = "Did someone tread on this? It looks useless for cloning or cyborgification." - organ_tag = "brain" - parent_organ = BP_HEAD - icon = 'icons/mob/alien.dmi' - icon_state = "chitin" - vital = 1 - -/obj/item/organ/internal/brain/xeno - name = "thinkpan" - desc = "It looks kind of like an enormous wad of purple bubblegum." - icon = 'icons/mob/alien.dmi' - icon_state = "chitin" - /obj/item/organ/internal/brain/New() ..() health = config.default_brain_health @@ -127,6 +112,21 @@ target.key = brainmob.key ..() +/obj/item/organ/internal/pariah_brain + name = "brain remnants" + desc = "Did someone tread on this? It looks useless for cloning or cyborgification." + organ_tag = "brain" + parent_organ = BP_HEAD + icon = 'icons/mob/alien.dmi' + icon_state = "chitin" + vital = 1 + +/obj/item/organ/internal/brain/xeno + name = "thinkpan" + desc = "It looks kind of like an enormous wad of purple bubblegum." + icon = 'icons/mob/alien.dmi' + icon_state = "chitin" + /obj/item/organ/internal/brain/slime name = "slime core" desc = "A complex, organic knot of jelly and crystalline particles." diff --git a/code/modules/organs/internal/kidneys.dm b/code/modules/organs/internal/kidneys.dm index a547a2539f..19652a6376 100644 --- a/code/modules/organs/internal/kidneys.dm +++ b/code/modules/organs/internal/kidneys.dm @@ -9,6 +9,7 @@ /obj/item/organ/internal/kidneys/process() ..() + if(!owner) return // Coffee is really bad for you with busted kidneys. diff --git a/code/modules/organs/internal/organ_internal.dm b/code/modules/organs/internal/organ_internal.dm index a3fdc511fc..43b3a4c4d7 100644 --- a/code/modules/organs/internal/organ_internal.dm +++ b/code/modules/organs/internal/organ_internal.dm @@ -58,5 +58,7 @@ if (prob(3)) take_damage(1,silent=prob(30)) - //if(. >= 3 && antibiotics < 30) //INFECTION_LEVEL_THREE, others are handled on each specific organ - //Nothing that generic internal organs do for this + if(. >= 3 && antibiotics < 30) //INFECTION_LEVEL_THREE + if (prob(50)) + take_damage(1,silent=prob(15)) + diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 915258e112..77706b9517 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -91,6 +91,9 @@ var/list/organ_cache = list() if(owner && vital) owner.death() +/obj/item/organ/proc/adjust_germ_level(var/amount) // Unless you're setting germ level directly to 0, use this proc instead + germ_level = Clamp(germ_level + amount, 0, INFECTION_LEVEL_MAX) + /obj/item/organ/process() if(loc != owner) @@ -117,9 +120,9 @@ var/list/organ_cache = list() if(config.organs_decay) damage += rand(1,3) if(damage >= max_damage) damage = max_damage - germ_level += rand(2,6) + adjust_germ_level(rand(2,6)) if(germ_level >= INFECTION_LEVEL_TWO) - germ_level += rand(2,6) + adjust_germ_level(rand(2,6)) if(germ_level >= INFECTION_LEVEL_THREE) die() @@ -158,12 +161,12 @@ var/list/organ_cache = list() owner.adjustToxLoss(infection_damage) if (germ_level > 0 && germ_level < INFECTION_LEVEL_ONE/2 && prob(30)) - germ_level-- + adjust_germ_level(-1) if (germ_level >= INFECTION_LEVEL_ONE/2) //aiming for germ level to go from ambient to INFECTION_LEVEL_TWO in an average of 15 minutes if(antibiotics < 5 && prob(round(germ_level/6))) - germ_level++ + adjust_germ_level(1) if(germ_level >= INFECTION_LEVEL_ONE) . = 1 //Organ qualifies for effect-specific processing @@ -179,7 +182,7 @@ var/list/organ_cache = list() if (germ_level >= INFECTION_LEVEL_THREE && antibiotics < 30) . = 3 //Organ qualifies for effect-specific processing - germ_level++ //Germ_level increases without overdose of antibiotics + adjust_germ_level(rand(5,10)) //Germ_level increases without overdose of antibiotics /obj/item/organ/proc/handle_rejection() // Process unsuitable transplants. TODO: consider some kind of @@ -193,13 +196,13 @@ var/list/organ_cache = list() if(rejecting % 10 == 0) //Only fire every ten rejection ticks. switch(rejecting) if(1 to 50) - germ_level++ + adjust_germ_level(1) if(51 to 200) - germ_level += rand(1,2) + adjust_germ_level(rand(1,2)) if(201 to 500) - germ_level += rand(2,3) + adjust_germ_level(rand(2,3)) if(501 to INFINITY) - germ_level += rand(3,5) + adjust_germ_level(rand(3,5)) owner.reagents.add_reagent("toxin", rand(1,2)) /obj/item/organ/proc/receive_chem(chemical as obj) @@ -238,9 +241,11 @@ var/list/organ_cache = list() if (germ_level < INFECTION_LEVEL_ONE) germ_level = 0 //cure instantly else if (germ_level < INFECTION_LEVEL_TWO) - germ_level -= 6 //at germ_level == 500, this should cure the infection in a minute + adjust_germ_level(-6) //at germ_level < 500, this should cure the infection in a minute + else if (germ_level < INFECTION_LEVEL_THREE) + adjust_germ_level(-2) //at germ_level < 1000, this will cure the infection in 5 minutes else - germ_level -= 2 //at germ_level == 1000, this will cure the infection in 5 minutes + adjust_germ_level(-1) // You waited this long to get treated, you don't really deserve this organ //Adds autopsy data for used_weapon. /obj/item/organ/proc/add_autopsy_data(var/used_weapon, var/damage) diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index 48759ae1cf..3c986b16fd 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -71,7 +71,7 @@ var/global/list/limb_icon_cache = list() overlays |= lip_icon mob_icon.Blend(lip_icon, ICON_OVERLAY) - //Head markings, duplicated (sadly) below. + //Head markings. for(var/M in markings) var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") @@ -89,11 +89,13 @@ var/global/list/limb_icon_cache = list() overlays |= facial_s if(owner.h_style && !(owner.head && (owner.head.flags_inv & BLOCKHEADHAIR))) - var/datum/sprite_accessory/hair_style = hair_styles_list[owner.h_style] + var/datum/sprite_accessory/hair/hair_style = hair_styles_list[owner.h_style] if(hair_style && (species.get_bodytype(owner) in hair_style.species_allowed)) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + var/icon/hair_s_add = new/icon("icon" = hair_style.icon_add, "icon_state" = "[hair_style.icon_state]_s") if(hair_style.do_colouration && islist(h_col) && h_col.len >= 3) - hair_s.Blend(rgb(h_col[1], h_col[2], h_col[3]), ICON_ADD) + hair_s.Blend(rgb(h_col[1], h_col[2], h_col[3]), ICON_MULTIPLY) + hair_s.Blend(hair_s_add, ICON_ADD) overlays |= hair_s return mob_icon @@ -130,14 +132,15 @@ var/global/list/limb_icon_cache = list() mob_icon = new /icon(species.get_icobase(owner, (status & ORGAN_MUTATED)), "[icon_name][gender ? "_[gender]" : ""]") apply_colouration(mob_icon) - //Body markings, does not include head, duplicated (sadly) above. - for(var/M in markings) - var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] - var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") - mark_s.Blend(markings[M]["color"], ICON_ADD) - overlays |= mark_s //So when it's not on your body, it has icons - mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons - icon_cache_key += "[M][markings[M]["color"]]" + //Body markings, actually does not include head this time. Done separately above. + if(!istype(src,/obj/item/organ/external/head)) + for(var/M in markings) + var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] + var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]") + mark_s.Blend(markings[M]["color"], ICON_ADD) + overlays |= mark_s //So when it's not on your body, it has icons + mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons + icon_cache_key += "[M][markings[M]["color"]]" if(body_hair && islist(h_col) && h_col.len >= 3) var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]" diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm new file mode 100644 index 0000000000..bb37a380b6 --- /dev/null +++ b/code/modules/paperwork/paperplane.dm @@ -0,0 +1,102 @@ +// Ported from TG. Known issue: Throw hit can possibly double-proc. Seems to be throw code. +/obj/item/weapon/paperplane + name = "paper plane" + desc = "Paper folded into the shape of a plane." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paperplane" + throw_range = 7 + throw_speed = 1 + throwforce = 0 + w_class = ITEMSIZE_TINY + + var/obj/item/weapon/paper/internalPaper + +/obj/item/weapon/paperplane/New(loc, obj/item/weapon/paper/newPaper) + . = ..() + pixel_y = rand(-8, 8) + pixel_x = rand(-9, 9) + if(newPaper) + internalPaper = newPaper + flags = newPaper.flags + color = newPaper.color + newPaper.forceMove(src) + else + internalPaper = new /obj/item/weapon/paper(src) + update_icon() + +/obj/item/weapon/paperplane/Destroy() + if(internalPaper) + qdel(internalPaper) + internalPaper = null + return ..() + +/obj/item/weapon/paperplane/update_icon() + overlays.Cut() + var/list/stamped = internalPaper.stamped + if(!stamped) + stamped = new + else if(stamped) + for(var/S in stamped) + var/obj/item/weapon/stamp/ = S + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[initial(stamp.icon_state)]") + overlays += stampoverlay + +/obj/item/weapon/paperplane/attack_self(mob/user) + to_chat(user, "You unfold [src].") + var/atom/movable/internal_paper_tmp = internalPaper + internal_paper_tmp.forceMove(loc) + internalPaper = null + qdel(src) + user.put_in_hands(internal_paper_tmp) + +/obj/item/weapon/paperplane/attackby(obj/item/P, mob/living/carbon/human/user, params) + ..() + if(istype(P, /obj/item/weapon/pen)) + to_chat(user, "You should unfold [src] before changing it.") + return + + else if(istype(P, /obj/item/weapon/stamp)) //we don't randomize stamps on a paperplane + internalPaper.attackby(P, user) //spoofed attack to update internal paper. + update_icon() + + else if(is_hot(P)) + if(user.disabilities & CLUMSY && prob(10)) + user.visible_message("[user] accidentally ignites themselves!", \ + "You miss the [src] and accidentally light yourself on fire!") + user.unEquip(P) + user.adjust_fire_stacks(1) + user.IgniteMob() + return + + if(!(in_range(user, src))) //to prevent issues as a result of telepathically lighting a paper + return + user.unEquip(src) + user.visible_message("[user] lights [src] ablaze with [P]!", "You light [src] on fire!") + fire_act() + + add_fingerprint(user) + +/obj/item/weapon/paperplane/throw_impact(atom/hit_atom) + if(..() || !ishuman(hit_atom))//if the plane is caught or it hits a nonhuman + return + var/mob/living/carbon/human/H = hit_atom + if(prob(2)) + if((H.head && H.head.body_parts_covered & EYES) || (H.wear_mask && H.wear_mask.body_parts_covered & EYES) || (H.glasses && H.glasses.body_parts_covered & EYES)) + return + visible_message("\The [src] hits [H] in the eye!") + H.eye_blurry += 10 + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES] + if(E) + E.damage += 2.5 + H.emote("scream") + +/obj/item/weapon/paper/AltClick(mob/living/carbon/user, obj/item/I) + if ( istype(user) ) + if( (!in_range(src, user)) || user.stat || user.restrained() ) + return + to_chat(user, "You fold [src] into the shape of a plane!") + user.unEquip(src) + I = new /obj/item/weapon/paperplane(user, src) + user.put_in_hands(I) + else + to_chat(user, " You lack the dexterity to fold \the [src]. ") diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 990c97b1c2..1de92fe743 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -119,8 +119,8 @@ /obj/item/weapon/pen/reagent/paralysis/New() ..() - reagents.add_reagent("zombiepowder", 10) - reagents.add_reagent("cryptobiolin", 15) + reagents.add_reagent("zombiepowder", 5) + reagents.add_reagent("cryptobiolin", 10) /* * Chameleon pen diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index eb142aac1e..39ce99d188 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -681,13 +681,10 @@ else flick("apc-spark", src) if (do_after(user,6)) - if(prob(50)) - emagged = 1 - locked = 0 - to_chat(user,"You emag the APC interface.") - update_icon() - else - to_chat(user,"The APC interface refused to unlock.") + emagged = 1 + locked = 0 + to_chat(user,"You emag the APC interface.") + update_icon() return 1 /obj/machinery/power/apc/attack_hand(mob/user) diff --git a/code/modules/power/grid_checker.dm b/code/modules/power/grid_checker.dm index b8a123e02f..8127383651 100644 --- a/code/modules/power/grid_checker.dm +++ b/code/modules/power/grid_checker.dm @@ -4,6 +4,8 @@ than the alternative." icon_state = "gridchecker_on" circuit = /obj/item/weapon/circuitboard/grid_checker + density = 1 + anchored = 1 var/power_failing = FALSE // Turns to TRUE when the grid check event is fired by the Game Master, or perhaps a cheeky antag. // Wire stuff below. var/datum/wires/grid_checker/wires diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 342e10db84..10a4b5ead9 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -159,6 +159,34 @@ name = "ammo clip (.45 flash)" ammo_type = /obj/item/ammo_casing/a45f +/obj/item/ammo_magazine/s45 + name = "speedloader (.45)" + icon_state = "45s" + ammo_type = /obj/item/ammo_casing/a45 + matter = list(DEFAULT_WALL_MATERIAL = 525) //metal costs are very roughly based around 1 .45 casing = 75 metal + caliber = ".45" + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/s45/empty + initial_ammo = 0 + +/obj/item/ammo_magazine/s45/rubber + name = "speedloader (.45 rubber)" + ammo_type = /obj/item/ammo_casing/a45r + +/obj/item/ammo_magazine/s45/practice + name = "speedloader (.45 practice)" + ammo_type = /obj/item/ammo_casing/a45p + +/obj/item/ammo_magazine/s45/flash + name = "speedloader (.45 flash)" + ammo_type = /obj/item/ammo_casing/a45f + +/obj/item/ammo_magazine/s45/ap + name = "speedloader (.45 AP)" + ammo_type = /obj/item/ammo_casing/a45ap + ///////// 9mm ///////// /obj/item/ammo_magazine/m9mm diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index e545ebb848..9a9f0b4bd6 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -23,7 +23,7 @@ icon_state = "[initial(icon_state)]-e" /obj/item/weapon/gun/projectile/colt/detective - desc = "A Martian recreation of an old Terran pistol. Uses .45 rounds." + desc = "A Martian recreation of an old pistol. Uses .45 rounds." magazine_type = /obj/item/ammo_magazine/m45/rubber /obj/item/weapon/gun/projectile/colt/detective/verb/rename_gun() @@ -60,7 +60,8 @@ options["H&K VP"] = "VP78" options["P08 Luger"] = "p08" options["P08 Luger, Brown"] = "p08b" - var/choice = input(M,"What do you want the gun's sprite to be?","Resprite Gun") in options + options["Glock 37"] = "enforcer_black" + var/choice = input(M,"Choose your sprite!","Resprite Gun") in options if(src && choice && !M.stat && in_range(M,src)) icon_state = options[choice] unique_reskin = options[choice] diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index 81355d1031..20671d6fd5 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -66,6 +66,58 @@ M << "You name the gun [input]. Say hello to your new friend." return 1 +/obj/item/weapon/gun/projectile/revolver/detective45 + name = ".45 revolver" + desc = "A fancy replica of an old revolver, modified for .45 rounds and a seven-shot cylinder." + icon_state = "detective" + caliber = ".45" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + fire_sound = 'sound/weapons/gunshot_heavy.ogg' + ammo_type = /obj/item/ammo_casing/a45r + max_shells = 7 + + +obj/item/weapon/gun/projectile/revolver/detective45/verb/rename_gun() + set name = "Name Gun" + set category = "Object" + set desc = "Rename your gun. If you're the Detective." + + var/mob/M = usr + if(!M.mind) return 0 + var/job = M.mind.assigned_role + if(job != "Detective") + M << "You don't feel cool enough to name this gun, chump." + return 0 + + var/input = sanitizeSafe(input("What do you want to name the gun?", ,""), MAX_NAME_LEN) + + if(src && input && !M.stat && in_range(M,src)) + name = input + M << "You name the gun [input]. Say hello to your new friend." + return 1 + +/obj/item/weapon/gun/projectile/revolver/detective45/verb/reskin_gun() + set name = "Resprite gun" + set category = "Object" + set desc = "Click to choose a sprite for your gun." + + var/mob/M = usr + var/list/options = list() + options["Colt Detective Special"] = "detective" + options["Ruger GP100"] = "GP100" + options["Colt Single Action Army"] = "detective_peacemaker" + options["Colt Single Action Army, Dark"] = "detective_peacemaker_dark" + options["H&K PT"] = "detective_panther" + options["Vintage LeMat"] = "lemat_old" + options["Webley MKVI "] = "webley" + var/choice = input(M,"Choose your sprite!","Resprite Gun") in options + if(src && choice && !M.stat && in_range(M,src)) + icon_state = options[choice] + M << "Your gun is now sprited as [choice]. Say hello to your new friend." + return 1 + + + // Blade Runner pistol. /obj/item/weapon/gun/projectile/revolver/deckard name = "\improper Deckard .38" diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 44dce0a7ad..1961b1feb3 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -210,6 +210,7 @@ icon_state = "vial" matter = list("glass" = 250) volume = 30 + w_class = ITEMSIZE_TINY amount_per_transfer_from_this = 10 possible_transfer_amounts = list(5,10,15,25) flags = OPENCONTAINER diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 5c5d0cc3a6..604eaa6a3a 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -60,7 +60,57 @@ used = !used return +//A vial-loaded hypospray. Cartridge-based! +/obj/item/weapon/reagent_containers/hypospray/vial + name = "hypospray mkII" + desc = "A new development from DeForest Medical, this new hypospray takes 30-unit vials as the drug supply for easy swapping." + var/obj/item/weapon/reagent_containers/glass/beaker/vial/loaded_vial //Wow, what a name. + volume = 0 +/obj/item/weapon/reagent_containers/hypospray/vial/New() + ..() + loaded_vial = new /obj/item/weapon/reagent_containers/glass/beaker/vial(src) //Comes with an empty vial + volume = loaded_vial.volume + reagents.maximum_volume = loaded_vial.reagents.maximum_volume + +/obj/item/weapon/reagent_containers/hypospray/vial/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + if(loaded_vial) + reagents.trans_to_holder(loaded_vial.reagents,volume) + reagents.maximum_volume = 0 + loaded_vial.update_icon() + user.put_in_hands(loaded_vial) + loaded_vial = null + user << "You remove the vial from the [src]." + update_icon() + playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1) + return + ..() + else + return ..() + +/obj/item/weapon/reagent_containers/hypospray/vial/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/reagent_containers/glass/beaker/vial)) + if(!loaded_vial) + user.visible_message("[user] begins loading [W] into \the [src].","You start loading [W] into \the [src].") + if(!do_after(user,30) || loaded_vial || !(W in user)) + return 0 + if(W.is_open_container()) + W.flags ^= OPENCONTAINER + W.update_icon() + user.drop_item() + W.loc = src + loaded_vial = W + reagents.maximum_volume = loaded_vial.reagents.maximum_volume + loaded_vial.reagents.trans_to_holder(reagents,volume) + user.visible_message("[user] has loaded [W] into \the [src].","You have loaded [W] into \the [src].") + update_icon() + playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) + else + user << "\The [src] already has a vial." + else + ..() + /obj/item/weapon/reagent_containers/hypospray/autoinjector name = "autoinjector" desc = "A rapid and safe way to administer small amounts of drugs by untrained or trained personnel." diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 6312d08d84..88b6d9d064 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -76,6 +76,13 @@ ..() reagents.add_reagent("water",1000) +/obj/structure/reagent_dispensers/watertank/high/New() + name = "high-capacity water tank" + desc = "A highly-pressurized water tank made to hold vast amounts of water.." + icon_state = "watertank_high" + ..() + reagents.add_reagent("water",4000) + /obj/structure/reagent_dispensers/fueltank name = "fueltank" desc = "A fueltank." diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 8e531ad687..db06449d18 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -405,7 +405,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, return /obj/machinery/computer/rdconsole/proc/GetResearchLevelsInfo() - var/dat + var/list/dat = list() dat += "" - return dat + return dat.Join() /obj/machinery/computer/rdconsole/proc/GetResearchListInfo() - var/dat + var/list/dat = list() dat += "" - return dat + return dat.Join() /obj/machinery/computer/rdconsole/attack_hand(mob/user as mob) if(stat & (BROKEN|NOPOWER)) return user.set_machine(src) - var/dat = "" + var/list/dat = list() files.RefreshResearch() switch(screen) //A quick check to make sure you get the right screen when a device is disconnected. if(2 to 2.9) @@ -774,7 +774,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, dat += "List of Researched Technologies and Designs:" dat += GetResearchListInfo() - user << browse("Research and Development Console
[dat]", "window=rdconsole;size=850x600") + user << browse("Research and Development Console
[dat.Join()]", "window=rdconsole;size=850x600") onclose(user, "rdconsole") /obj/machinery/computer/rdconsole/robotics diff --git a/code/modules/shieldgen/shield_capacitor.dm b/code/modules/shieldgen/shield_capacitor.dm index 2bddb5af32..f1988ee8c6 100644 --- a/code/modules/shieldgen/shield_capacitor.dm +++ b/code/modules/shieldgen/shield_capacitor.dm @@ -4,7 +4,7 @@ /obj/machinery/shield_capacitor name = "shield capacitor" - desc = "Machine that charges a shield generator." + desc = "A machine that charges a shield generator." icon = 'icons/obj/machines/shielding.dmi' icon_state = "capacitor" var/active = 0 @@ -19,6 +19,12 @@ var/charge_rate = 100000 //100 kW var/obj/machinery/shield_gen/owned_gen +/obj/machinery/shield_capacitor/advanced + name = "advanced shield capacitor" + desc = "A machine that charges a shield generator. This version can store, input, and output more electricity." + max_charge = 12e6 + max_charge_rate = 600000 + /obj/machinery/shield_capacitor/emag_act(var/remaining_charges, var/mob/user) if(prob(75)) src.locked = !src.locked diff --git a/code/modules/shieldgen/shield_gen.dm b/code/modules/shieldgen/shield_gen.dm index 32d34365b4..6100dda029 100644 --- a/code/modules/shieldgen/shield_gen.dm +++ b/code/modules/shieldgen/shield_gen.dm @@ -1,11 +1,11 @@ /obj/machinery/shield_gen name = "bubble shield generator" - desc = "Machine that generates an impenetrable field of energy when activated." + desc = "A machine that generates a field of energy optimized for blocking meteorites when activated." icon = 'icons/obj/machines/shielding.dmi' icon_state = "generator0" var/active = 0 var/field_radius = 3 - var/max_field_radius = 100 + var/max_field_radius = 150 var/list/field = list() density = 1 var/locked = 0 @@ -20,10 +20,15 @@ var/target_field_strength = 10 var/max_field_strength = 10 var/time_since_fail = 100 - var/energy_conversion_rate = 0.0002 //how many renwicks per watt? + var/energy_conversion_rate = 0.0002 //how many renwicks per watt? Higher numbers equals more effiency. var/z_range = 0 // How far 'up and or down' to extend the shield to, in z-levels. Only works on MultiZ supported z-levels. use_power = 0 //doesn't use APC power +/obj/machinery/shield_gen/advanced + name = "advanced bubble shield generator" + desc = "A machine that generates a field of energy optimized for blocking meteorites when activated. This version comes with a more efficent shield matrix." + energy_conversion_rate = 0.0004 + /obj/machinery/shield_gen/New() spawn(1 SECOND) if(anchored) @@ -259,11 +264,14 @@ /obj/machinery/shield_gen/update_icon() if(stat & BROKEN) icon_state = "broke" + set_light(0) else if (src.active) icon_state = "generator1" + set_light(4, 2, "#00CCFF") else icon_state = "generator0" + set_light(0) //grab the border tiles in a circle around this machine /obj/machinery/shield_gen/proc/get_shielded_turfs() @@ -315,4 +323,4 @@ T = locate(gen_turf.x + field_radius, gen_turf.y + y_offset, gen_turf.z) if (T) out += T - return out \ No newline at end of file + return out diff --git a/code/modules/shieldgen/shield_gen_external.dm b/code/modules/shieldgen/shield_gen_external.dm index 27b1def271..fa4702feee 100644 --- a/code/modules/shieldgen/shield_gen_external.dm +++ b/code/modules/shieldgen/shield_gen_external.dm @@ -7,8 +7,11 @@ /turf/space, /turf/simulated/floor/outdoors, ) -/obj/machinery/shield_gen/external/New() - ..() + +/obj/machinery/shield_gen/external/advanced + name = "advanced hull shield generator" + desc = "A machine that generates a field of energy optimized for blocking meteorites when activated. This version comes with a more efficent shield matrix." + energy_conversion_rate = 0.0004 //Search for space turfs within range that are adjacent to a simulated turf. /obj/machinery/shield_gen/external/get_shielded_turfs_on_z_level(var/turf/gen_turf) diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 5b3cb80b15..f42f2dcf05 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -24,6 +24,7 @@ em {font-style: normal;font-weight: bold;} .ooc .moderator {color: #184880;} .ooc .developer {color: #1b521f;} .ooc .admin {color: #b82e00;} +.ooc .event_manager {color: #660033;} .ooc .aooc {color: #960018;} /* Admin: Private Messages */ @@ -36,7 +37,7 @@ em {font-style: normal;font-weight: bold;} .mod_channel {color: #735638; font-weight: bold;} .mod_channel .admin {color: #b82e00; font-weight: bold;} .admin_channel {color: #9611D4; font-weight: bold;} -.event_channel {color: #009933; font-weight: bold;} +.event_channel {color: #cc3399; font-weight: bold;} /* Radio: Misc */ .deadsay {color: #530FAD;} diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm index f8f735f867..eb0e41e117 100644 --- a/code/unit_tests/map_tests.dm +++ b/code/unit_tests/map_tests.dm @@ -12,7 +12,8 @@ /area/holodeck, /area/supply/station, /area/mine, - /area/vacant/vacant_shop + /area/vacant/vacant_shop, + /area/turbolift ) var/list/exempt_from_atmos = typesof(/area/maintenance, @@ -33,6 +34,11 @@ /area/vacant/vacant_shop ) + // Some maps have areas specific to the map, so include those. + exempt_areas += using_map.unit_test_exempt_areas + exempt_from_atmos += using_map.unit_test_exempt_from_atmos + exempt_from_apc += using_map.unit_test_exempt_from_apc + for(var/area/A in world) if(A.z == 1 && !(A.type in exempt_areas)) area_test_count++ diff --git a/html/changelog.html b/html/changelog.html index cb2923c0f1..610d80aa38 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,20 @@ -->
+

06 November 2017

+

Atermonera updated:

+ +

Woodrat updated:

+ +

24 September 2017

Belsima updated:

diff --git a/polaris.dme b/polaris.dme index 4079f32e0c..ec7394071b 100644 --- a/polaris.dme +++ b/polaris.dme @@ -616,6 +616,7 @@ #include "code\game\machinery\teleporter.dm" #include "code\game\machinery\turret_control.dm" #include "code\game\machinery\vending.dm" +#include "code\game\machinery\vr_console.dm" #include "code\game\machinery\wall_frames.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\wishgranter.dm" @@ -804,6 +805,7 @@ #include "code\game\objects\items\contraband.dm" #include "code\game\objects\items\crayons.dm" #include "code\game\objects\items\glassjar.dm" +#include "code\game\objects\items\gunbox.dm" #include "code\game\objects\items\latexballoon.dm" #include "code\game\objects\items\paintkit.dm" #include "code\game\objects\items\shooting_range.dm" @@ -992,6 +994,7 @@ #include "code\game\objects\structures\door_assembly.dm" #include "code\game\objects\structures\electricchair.dm" #include "code\game\objects\structures\extinguisher.dm" +#include "code\game\objects\structures\fitness.dm" #include "code\game\objects\structures\flora.dm" #include "code\game\objects\structures\girders.dm" #include "code\game\objects\structures\gravemarker.dm" @@ -1730,6 +1733,7 @@ #include "code\modules\mob\living\carbon\human\species\station\prometheans.dm" #include "code\modules\mob\living\carbon\human\species\station\seromi.dm" #include "code\modules\mob\living\carbon\human\species\station\station.dm" +#include "code\modules\mob\living\carbon\human\species\virtual_reality\avatar.dm" #include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_powers.dm" #include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_species.dm" #include "code\modules\mob\living\carbon\human\species\xenomorphs\xenomorphs.dm" @@ -1922,6 +1926,7 @@ #include "code\modules\paperwork\paper.dm" #include "code\modules\paperwork\paper_bundle.dm" #include "code\modules\paperwork\paperbin.dm" +#include "code\modules\paperwork\paperplane.dm" #include "code\modules\paperwork\papershredder.dm" #include "code\modules\paperwork\pen.dm" #include "code\modules\paperwork\photocopier.dm" diff --git a/sound/effects/weightdrop.ogg b/sound/effects/weightdrop.ogg new file mode 100644 index 0000000000..07945daaf8 Binary files /dev/null and b/sound/effects/weightdrop.ogg differ diff --git a/sound/effects/weightlifter.ogg b/sound/effects/weightlifter.ogg new file mode 100644 index 0000000000..51a0d49785 Binary files /dev/null and b/sound/effects/weightlifter.ogg differ diff --git a/sound/items/geiger1.ogg b/sound/items/geiger1.ogg new file mode 100644 index 0000000000..b822085659 Binary files /dev/null and b/sound/items/geiger1.ogg differ diff --git a/sound/items/geiger2.ogg b/sound/items/geiger2.ogg new file mode 100644 index 0000000000..4c0d734463 Binary files /dev/null and b/sound/items/geiger2.ogg differ diff --git a/sound/items/geiger3.ogg b/sound/items/geiger3.ogg new file mode 100644 index 0000000000..a9a5924d80 Binary files /dev/null and b/sound/items/geiger3.ogg differ diff --git a/sound/items/geiger4.ogg b/sound/items/geiger4.ogg new file mode 100644 index 0000000000..dfad69866c Binary files /dev/null and b/sound/items/geiger4.ogg differ diff --git a/sound/items/geiger5.ogg b/sound/items/geiger5.ogg new file mode 100644 index 0000000000..1e5f20913c Binary files /dev/null and b/sound/items/geiger5.ogg differ diff --git a/sound/items/geiger_weak1.ogg b/sound/items/geiger_weak1.ogg new file mode 100644 index 0000000000..cadfcde746 Binary files /dev/null and b/sound/items/geiger_weak1.ogg differ diff --git a/sound/items/geiger_weak2.ogg b/sound/items/geiger_weak2.ogg new file mode 100644 index 0000000000..12f54ae669 Binary files /dev/null and b/sound/items/geiger_weak2.ogg differ diff --git a/sound/items/geiger_weak3.ogg b/sound/items/geiger_weak3.ogg new file mode 100644 index 0000000000..c935711aac Binary files /dev/null and b/sound/items/geiger_weak3.ogg differ diff --git a/sound/items/geiger_weak4.ogg b/sound/items/geiger_weak4.ogg new file mode 100644 index 0000000000..2b17311a82 Binary files /dev/null and b/sound/items/geiger_weak4.ogg differ