diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 5aa0301bf6..3979274951 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -62,9 +62,10 @@ #define INIT_ORDER_JOBS 65 #define INIT_ORDER_QUIRKS 60 #define INIT_ORDER_TICKER 55 -#define INIT_ORDER_INSTRUMENTS 53 +#define INIT_ORDER_INSTRUMENTS 53 #define INIT_ORDER_MAPPING 50 #define INIT_ORDER_NETWORKS 45 +#define INIT_ORDER_HOLODECK 35 #define INIT_ORDER_ATOMS 30 #define INIT_ORDER_LANGUAGE 25 #define INIT_ORDER_MACHINES 20 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 0c45a746d8..38e25b04c5 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -89,14 +89,6 @@ INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL() - for(var/path in subtypesof(/area/holodeck)) - var/area/holodeck/A = path - var/list/compatibles = initial(A.compatible_holodeck_comps) - if(!compatibles || initial(A.abstract_type) == path) - continue - for(var/comp in compatibles) - LAZYADD(GLOB.holodeck_areas_prototypes[comp], A) - //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. /proc/init_subtypes(prototype, list/L) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index bcf35859c3..fb8863ebe7 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -50,5 +50,3 @@ GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area) GLOBAL_LIST_EMPTY(all_abstract_markers) GLOBAL_LIST_EMPTY(stationroom_landmarks) //List of all spawns for stationrooms - -GLOBAL_LIST_EMPTY(holodeck_areas_prototypes) //List of holodeck area prototypes per holodeck computer type \ No newline at end of file diff --git a/code/controllers/subsystem/holodeck.dm b/code/controllers/subsystem/holodeck.dm new file mode 100644 index 0000000000..ecf8d67dbb --- /dev/null +++ b/code/controllers/subsystem/holodeck.dm @@ -0,0 +1,56 @@ +SUBSYSTEM_DEF(holodeck) + name = "Holodeck" + init_order = INIT_ORDER_HOLODECK + flags = SS_NO_FIRE + var/list/program_cache = list() //list of safe holodeck programs. + var/list/emag_program_cache = list() //like above, but dangerous. + var/list/offline_programs = list() //default when offline. + var/list/target_holodeck_area = list() + var/list/rejected_areas = list() + +/datum/controller/subsystem/holodeck/Initialize() + . = ..() + //generates the list of available holodeck programs. + for(var/path in subtypesof(/datum/holodeck_cache)) + new path + for(var/path in typesof(/obj/machinery/computer/holodeck)) //The istances will be handled by SSatoms. + var/obj/machinery/computer/holodeck/H = path + offline_programs[path] = pop(get_areas(initial(H.offline_program)), FALSE) + target_holodeck_area[path] = pop(get_areas(initial(H.holodeck_type)), FALSE) + + + /* + * The sole scope of this datum is to generate lists of holodeck programs caches per holodeck computer type. + */ + +/datum/holodeck_cache + var/area/holodeck/master_type //the /area/holodeck typepath we'll be using for typesof loop. + var/skip_types //Areas that won't be added to the global list category. + var/list/compatible_holodeck_comps //list of typepaths of holodeck computers that can access this category. + +/datum/holodeck_cache/New() + if(!master_type || !compatible_holodeck_comps) + return + var/list/to_add = typesof(master_type) - skip_types + var/list/programs + var/list/emag_programs + for(var/typekey in to_add) + var/area/holodeck/A = GLOB.areas_by_type[typekey] + if(!A || !A.contents.len) + LAZYOR(SSholodeck.rejected_areas[typekey], compatible_holodeck_comps) + continue + var/list/info_this = list("name" = A.name, "type" = A.type) + if(A.restricted) + LAZYADD(emag_programs, list(info_this)) + else + LAZYADD(programs, list(info_this)) + for(var/comp in compatible_holodeck_comps) + if(programs) + LAZYADD(SSholodeck.program_cache[comp], programs) + if(emag_programs) + LAZYADD(SSholodeck.emag_program_cache[comp], emag_programs) + +/datum/holodeck_cache/standard + master_type = /area/holodeck/rec_center + skip_types = /area/holodeck/rec_center + compatible_holodeck_comps = list(/obj/machinery/computer/holodeck) diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm index c0bdb09014..4e0dfb343f 100644 --- a/code/datums/components/riding.dm +++ b/code/datums/components/riding.dm @@ -26,7 +26,6 @@ RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle) RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved) - RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/vehicle_dir_changed) /datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE) restore_position(M) @@ -48,11 +47,6 @@ /datum/component/riding/proc/set_vehicle_dir_layer(dir, layer) directional_vehicle_layers["[dir]"] = layer -/datum/component/riding/proc/vehicle_dir_changed(from_dir, to_dir) - spawn - handle_vehicle_offsets() - handle_vehicle_layer() - /datum/component/riding/proc/vehicle_moved(datum/source) var/atom/movable/AM = parent for(var/i in AM.buckled_mobs) @@ -72,6 +66,9 @@ var/atom/movable/AM = parent AM.unbuckle_mob(M) +/datum/component/riding/proc/additional_offset_checks() + return TRUE + /datum/component/riding/proc/handle_vehicle_offsets() var/atom/movable/AM = parent var/AM_dir = "[AM.dir]" @@ -83,16 +80,19 @@ var/list/offsets = get_offsets(passindex) var/rider_dir = get_rider_dir(passindex) buckled_mob.setDir(rider_dir) - dir_loop: - for(var/offsetdir in offsets) - if(offsetdir == AM_dir) - var/list/diroffsets = offsets[offsetdir] - buckled_mob.pixel_x = diroffsets[1] - if(diroffsets.len >= 2) - buckled_mob.pixel_y = diroffsets[2] - if(diroffsets.len == 3) - buckled_mob.layer = diroffsets[3] - break dir_loop + for(var/offsetdir in offsets) + if(offsetdir == AM_dir) + var/list/diroffsets = offsets[offsetdir] + buckled_mob.pixel_x = diroffsets[1] + message_admins(diroffsets[1]) + if(diroffsets.len >= 2) + buckled_mob.pixel_y = diroffsets[2] + message_admins(diroffsets[2]) + if(diroffsets.len == 3) + buckled_mob.layer = diroffsets[3] + break + if (!additional_offset_checks()) + return var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0)) var/px = default_vehicle_pixel_offsets[AM_dir] var/py = default_vehicle_pixel_offsets[AM_dir] @@ -153,7 +153,6 @@ if(user.incapacitated()) Unbuckle(user) return - if(world.time < last_vehicle_move + ((last_move_diagonal? 2 : 1) * vehicle_move_delay)) return last_vehicle_move = world.time @@ -175,8 +174,8 @@ else last_move_diagonal = FALSE - handle_vehicle_layer() handle_vehicle_offsets() + handle_vehicle_layer() else to_chat(user, "You'll need the keys in one of your hands to [drive_verb] [AM].") @@ -226,6 +225,7 @@ force_dismount(target) /datum/component/riding/human/handle_vehicle_layer() + . = ..() var/atom/movable/AM = parent if(AM.buckled_mobs && AM.buckled_mobs.len) for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied @@ -250,6 +250,10 @@ else return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4)) +/datum/component/riding/human/additional_offset_checks() + var/mob/living/carbon/human/H = parent + return !H.buckled + /datum/component/riding/human/force_dismount(mob/living/user) var/atom/movable/AM = parent AM.unbuckle_mob(user) diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 8d57f3d9c2..e474272326 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -108,7 +108,6 @@ message = replacetext(message," drink "," liquid ") message = replacetext(message," feminist "," empowered woman ") message = replacetext(message," i hate you "," you're a mean ") - message = replacetext(message," jew "," jewish ") message = replacetext(message," shit "," shiz ") message = replacetext(message," crap "," poo ") message = replacetext(message," slut "," tease ") diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm index 5dce5791c2..fe018a8761 100644 --- a/code/datums/radiation_wave.dm +++ b/code/datums/radiation_wave.dm @@ -117,10 +117,10 @@ continue contam_atoms += thing var/did_contam = 0 - if(can_contam) + if(can_contam && contam_atoms.len) var/rad_strength = ((strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT)/contam_atoms.len - for(var/k in 1 to contam_atoms.len) - var/atom/thing = contam_atoms[k] + for(var/A in contam_atoms) + var/atom/thing = A thing.AddComponent(/datum/component/radioactive, rad_strength, source) did_contam = 1 return did_contam diff --git a/code/game/area/areas/holodeck.dm b/code/game/area/areas/holodeck.dm index 75ed2b656c..9eec00460a 100644 --- a/code/game/area/areas/holodeck.dm +++ b/code/game/area/areas/holodeck.dm @@ -6,8 +6,6 @@ hidden = TRUE var/obj/machinery/computer/holodeck/linked - var/list/compatible_holodeck_comps - var/abstract_type = /area/holodeck var/restricted = 0 // if true, program goes on emag list /* @@ -15,6 +13,16 @@ Asserts are to avoid the inevitable infinite loops */ +/area/holodeck/Initialize() + . = ..() + var/list/update_holodeck_cache = SSholodeck?.rejected_areas[type] + if(update_holodeck_cache) + var/list/info_this = list("name" = name, "type" = type) + var/list/target = restricted ? SSholodeck.emag_program_cache : SSholodeck.program_cache + for(var/A in update_holodeck_cache) + LAZYADD(target[A], info_this) + SSholodeck.rejected_areas -= type + /area/holodeck/powered(var/chan) if(!requires_power) return 1 @@ -55,8 +63,6 @@ */ /area/holodeck/rec_center name = "\improper Recreational Holodeck" - compatible_holodeck_comps = list(/obj/machinery/computer/holodeck) - abstract_type = /area/holodeck/rec_center /area/holodeck/rec_center/offline name = "Holodeck - Offline" diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 22c9bdc451..1e0a6ce6dc 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -163,7 +163,6 @@ color = pick(cable_colors) /obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params) - ..() if(istype(I, /obj/item/stack/rods)) var/obj/item/stack/rods/R = I if (R.use(1)) @@ -197,12 +196,15 @@ name = "zipties" desc = "Plastic, disposable zipties that can be used to restrain temporarily but are destroyed after use." item_state = "zipties" + color = "white" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' custom_materials = null breakouttime = 450 //Deciseconds = 45s trashtype = /obj/item/restraints/handcuffs/cable/zipties/used - color = null + +/obj/item/restraints/handcuffs/cable/zipties/attack_self() //Zipties arent cable + return /obj/item/restraints/handcuffs/cable/zipties/used desc = "A pair of broken zipties." diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index dc11e55754..22767a66ea 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -1,6 +1,6 @@ /obj/item/shield name = "shield" - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'icons/obj/shields.dmi' block_chance = 50 armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 70) /// Shield flags @@ -163,6 +163,7 @@ custom_materials = list(/datum/material/glass=7500, /datum/material/iron=1000) attack_verb = list("shoved", "bashed") var/cooldown = 0 //shield bash cooldown. based on world.time + var/repair_material = /obj/item/stack/sheet/mineral/titanium shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_TRANSPARENT max_integrity = 75 @@ -185,7 +186,7 @@ user.visible_message("[user] bashes [src] with [W]!") playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) cooldown = world.time - else if(istype(W, /obj/item/stack/sheet/mineral/titanium)) + else if(istype(W, repair_material)) if(obj_integrity >= max_integrity) to_chat(user, "[src] is already in perfect condition.") else @@ -221,6 +222,23 @@ take_damage(damage) return ..() +/obj/item/shield/riot/laser_proof + name = "laser resistant shield" + desc = "A far more frail shield made of dark glass meant to block lasers but suffers from being being weak to ballistic projectiles." + armor = list("melee" = 30, "bullet" = -10, "laser" = 80, "energy" = 80, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) + icon_state = "riot_laser" + item_state = "riot_laser" + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + shield_flags = SHIELD_FLAGS_DEFAULT + max_integrity = 55 //Weak + +obj/item/shield/riot/bullet_proof + name = "bullet resistant shield" + desc = "A far more frail shield made of resistant plastics and kevlar meant to block ballistics." + armor = list("melee" = 30, "bullet" = 80, "laser" = 0, "energy" = 0, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) + max_integrity = 55 //Weaker + /obj/item/shield/riot/roman name = "\improper Roman shield" desc = "Bears an inscription on the inside: \"Romanes venio domus\"." @@ -228,6 +246,7 @@ item_state = "roman_shield" lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + repair_material = /obj/item/stack/sheet/mineral/wood shield_flags = SHIELD_FLAGS_DEFAULT max_integrity = 65 @@ -250,6 +269,7 @@ righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' custom_materials = null resistance_flags = FLAMMABLE + repair_material = /obj/item/stack/sheet/mineral/wood block_chance = 30 shield_flags = SHIELD_FLAGS_DEFAULT max_integrity = 55 @@ -258,58 +278,6 @@ playsound(owner, 'sound/effects/bang.ogg', 50) new /obj/item/stack/sheet/mineral/wood(get_turf(src)) - -/obj/item/shield/energy - name = "energy combat shield" - desc = "A shield that reflects almost all energy projectiles, but is useless against physical attacks. It can be retracted, expanded, and stored anywhere." - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - w_class = WEIGHT_CLASS_TINY - attack_verb = list("shoved", "bashed") - throw_range = 5 - force = 3 - throwforce = 3 - throw_speed = 3 - var/base_icon_state = "eshield" // [base_icon_state]1 for expanded, [base_icon_state]0 for contracted - var/on_force = 10 - var/on_throwforce = 8 - var/on_throw_speed = 2 - var/active = 0 - var/clumsy_check = TRUE - -/obj/item/shield/energy/Initialize() - . = ..() - icon_state = "[base_icon_state]0" - -/obj/item/shield/energy/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) - if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) - block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT - return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT - return ..() - -/obj/item/shield/energy/attack_self(mob/living/carbon/human/user) - if(clumsy_check && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) - to_chat(user, "You beat yourself in the head with [src]!") - user.take_bodypart_damage(5) - active = !active - icon_state = "[base_icon_state][active]" - - if(active) - force = on_force - throwforce = on_throwforce - throw_speed = on_throw_speed - w_class = WEIGHT_CLASS_BULKY - playsound(user, 'sound/weapons/saberon.ogg', 35, TRUE) - to_chat(user, "[src] is now active.") - else - force = initial(force) - throwforce = initial(throwforce) - throw_speed = initial(throw_speed) - w_class = WEIGHT_CLASS_TINY - playsound(user, 'sound/weapons/saberoff.ogg', 35, TRUE) - to_chat(user, "[src] can now be concealed.") - add_fingerprint(user) - /obj/item/shield/riot/tele name = "telescopic shield" desc = "An advanced riot shield made of lightweight materials that collapses for easy storage." @@ -362,6 +330,7 @@ custom_materials = list(/datum/material/iron = 18000) slot_flags = null block_chance = 35 + max_integrity = 100 //Made of metal welded together its strong but not unkillable force = 10 throwforce = 7 @@ -380,6 +349,12 @@ item_flags = SLOWS_WHILE_IN_HAND shield_flags = SHIELD_FLAGS_DEFAULT +/obj/item/shield/riot/tower/swat + name = "swat shield" + desc = "A massive, heavy shield that can block a lot of attacks, can take a lot of abuse before breaking." + max_integrity = 175 + block_chance = 50 + /obj/item/shield/riot/implant name = "riot tower shield" desc = "A massive shield that can block a lot of attacks and can take a lot of abuse before breaking." //It cant break unless it is removed from the implant @@ -395,3 +370,55 @@ if(attack_type & ATTACK_TYPE_PROJECTILE) final_block_chance = 60 //Massive shield return ..() + + +/obj/item/shield/energy + name = "energy combat shield" + desc = "A shield that reflects almost all energy projectiles, but is useless against physical attacks. It can be retracted, expanded, and stored anywhere." + lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' + w_class = WEIGHT_CLASS_TINY + attack_verb = list("shoved", "bashed") + throw_range = 5 + force = 3 + throwforce = 3 + throw_speed = 3 + var/base_icon_state = "eshield" // [base_icon_state]1 for expanded, [base_icon_state]0 for contracted + var/on_force = 10 + var/on_throwforce = 8 + var/on_throw_speed = 2 + var/active = 0 + var/clumsy_check = TRUE + +/obj/item/shield/energy/Initialize() + . = ..() + icon_state = "[base_icon_state]0" + +/obj/item/shield/energy/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) + if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object)) + block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT + return BLOCK_SUCCESS | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT + return ..() + +/obj/item/shield/energy/attack_self(mob/living/carbon/human/user) + if(clumsy_check && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) + to_chat(user, "You beat yourself in the head with [src]!") + user.take_bodypart_damage(5) + active = !active + icon_state = "[base_icon_state][active]" + + if(active) + force = on_force + throwforce = on_throwforce + throw_speed = on_throw_speed + w_class = WEIGHT_CLASS_BULKY + playsound(user, 'sound/weapons/saberon.ogg', 35, TRUE) + to_chat(user, "[src] is now active.") + else + force = initial(force) + throwforce = initial(throwforce) + throw_speed = initial(throw_speed) + w_class = WEIGHT_CLASS_TINY + playsound(user, 'sound/weapons/saberoff.ogg', 35, TRUE) + to_chat(user, "[src] can now be concealed.") + add_fingerprint(user) diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index 3bc90d3615..f32532537b 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -274,6 +274,7 @@ w_class = WEIGHT_CLASS_TINY icon = 'icons/obj/cigarettes.dmi' icon_state = "cig_paper_pack" +///The value in here has NOTHING to do with icons. It needs to be this for the proper examine. icon_type = "rolling paper" spawn_type = /obj/item/rollingpaper @@ -283,6 +284,10 @@ STR.max_items = 10 STR.can_hold = typecacheof(list(/obj/item/rollingpaper)) +///Overrides to do nothing because fancy boxes are fucking insane. +/obj/item/storage/fancy/rollingpapers/update_icon_state() + return + /obj/item/storage/fancy/rollingpapers/update_overlays() . = ..() if(!contents.len) diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm index 14828729cd..dfaa6f0027 100644 --- a/code/modules/cargo/packs/misc.dm +++ b/code/modules/cargo/packs/misc.dm @@ -330,7 +330,7 @@ /datum/supply_pack/misc/religious_supplies name = "Religious Supplies Crate" desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets." - cost = 4000 // it costs so much because the Space Church is ran by Space Jews + cost = 4000 // it costs so much because the Space Church needs funding to build a cathedral contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/book/bible/booze, diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 4bbb6ae23f..dfd0a0ef3b 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -996,7 +996,7 @@ item_state = "coatpoly" hoodtype = /obj/item/clothing/head/hooded/winterhood/polychromic -/obj/item/clothing/suit/hooded/wintercoat/ComponentInitialize() +/obj/item/clothing/suit/hooded/wintercoat/polychromic/ComponentInitialize() . = ..() AddElement(/datum/element/polychromic, list("#6A6964", "#C4B8A6", "#0000FF"), 3) diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index 4f29eab6ab..639f2d3bfb 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -37,7 +37,6 @@ ..() /obj/item/clothing/suit/hooded/proc/RemoveHood() - src.icon_state = "[initial(icon_state)]" suittoggled = FALSE if(ishuman(hood.loc)) var/mob/living/carbon/H = hood.loc @@ -45,9 +44,14 @@ H.update_inv_wear_suit() else hood.forceMove(src) - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() + update_icon() + +/obj/item/clothing/suit/hooded/update_icon_state() + icon_state = "[initial(icon_state)]" + if(ishuman(hood.loc)) + var/mob/living/carbon/human/H = hood.loc + if(H.head == hood) + icon_state += "_t" /obj/item/clothing/suit/hooded/dropped(mob/user) ..() @@ -65,11 +69,8 @@ return else if(H.equip_to_slot_if_possible(hood,SLOT_HEAD,0,0,1)) suittoggled = TRUE - src.icon_state = "[initial(icon_state)]_t" + update_icon() H.update_inv_wear_suit() - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() else RemoveHood() diff --git a/code/modules/clothing/under/jobs/cargo.dm b/code/modules/clothing/under/jobs/cargo.dm index 92afe238ef..aa4db2fd30 100644 --- a/code/modules/clothing/under/jobs/cargo.dm +++ b/code/modules/clothing/under/jobs/cargo.dm @@ -18,7 +18,7 @@ /obj/item/clothing/under/rank/cargo/tech name = "cargo technician's jumpsuit" desc = "Shooooorts! They're comfy and easy to wear!" - icon_state = "cargotech" + icon_state = "cargo" item_state = "lb_suit" body_parts_covered = CHEST|GROIN|ARMS alt_covers_chest = TRUE diff --git a/code/modules/food_and_drinks/food/snacks_burgers.dm b/code/modules/food_and_drinks/food/snacks_burgers.dm index 9a4ef2ce89..f8c85700c9 100644 --- a/code/modules/food_and_drinks/food/snacks_burgers.dm +++ b/code/modules/food_and_drinks/food/snacks_burgers.dm @@ -365,7 +365,7 @@ /obj/item/reagent_containers/food/snacks/burger/chicken name = "chicken sandwich" //Apparently the proud people of Americlapstan object to this thing being called a burger. Apparently McDonald's just calls it a burger in Europe as to not scare and confuse us. - desc = "A delicious chicken sandwich, it is said the proceeds from this treat helps criminalize homosexuality on the space frontier." + desc = "A delicious chicken sandwich, it is said the proceeds from this treat helps criminalize disarming people on the space frontier." icon_state = "chickenburger" tastes = list("bun" = 2, "chicken" = 4, "God's covenant" = 1) bonus_reagents = list(/datum/reagent/consumable/mayonnaise = 3, /datum/reagent/consumable/cooking_oil = 2, /datum/reagent/consumable/nutriment = 2) diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm index 316bdb8289..cb9965d34a 100644 --- a/code/modules/holodeck/area_copy.dm +++ b/code/modules/holodeck/area_copy.dm @@ -70,7 +70,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars_by_type, typecacheof_assoc_list(list( for (var/turf/T in turfs_src) src_min_x = min(src_min_x,T.x) src_min_y = min(src_min_y,T.y) - src_max_x = max(src_max_x,T.y) + src_max_x = max(src_max_x,T.x) src_max_y = max(src_max_y,T.y) for (var/turf/T in turfs_src) refined_src[T] = "[T.x - src_min_x].[T.y - src_min_y]" @@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars_by_type, typecacheof_assoc_list(list( for (var/turf/T in turfs_trg) trg_min_x = min(trg_min_x,T.x) trg_min_y = min(trg_min_y,T.y) - trg_max_x = max(trg_max_x,T.y) + trg_max_x = max(trg_max_x,T.x) trg_max_y = max(trg_max_y,T.y) var/diff_x = round(((src_max_x - src_min_x) - (trg_max_x - trg_min_x))/2) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 3c87082393..65c69b995f 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -31,12 +31,12 @@ var/area/holodeck/last_program var/area/offline_program = /area/holodeck/rec_center/offline - var/list/program_cache - var/list/emag_programs - // Splitting this up allows two holodecks of the same size // to use the same source patterns. Y'know, if you want to. - var/holodeck_type = /area/holodeck/rec_center // locate(this) to get the target holodeck + var/holodeck_type = /area/holodeck/rec_center + + var/list/program_cache + var/list/emag_programs var/active = FALSE var/damaged = FALSE @@ -49,16 +49,18 @@ return INITIALIZE_HINT_LATELOAD /obj/machinery/computer/holodeck/LateInitialize() - if(ispath(holodeck_type, /area)) - linked = pop(get_areas(holodeck_type, FALSE)) - if(ispath(offline_program, /area)) - offline_program = pop(get_areas(offline_program), FALSE) - // the following is necessary for power reasons + linked = SSholodeck.target_holodeck_area[type] + offline_program = SSholodeck.offline_programs[type] if(!linked || !offline_program) log_world("No matching holodeck area found") qdel(src) return - var/area/AS = get_area(src) + + program_cache = SSholodeck.program_cache[type] + emag_programs = SSholodeck.emag_program_cache[type] + + // the following is necessary for power reasons + var/area/AS = get_base_area(src) if(istype(AS, /area/holodeck)) log_mapping("Holodeck computer cannot be in a holodeck, This would cause circular power dependency.") qdel(src) @@ -66,7 +68,6 @@ else linked.linked = src - generate_program_list() load_program(offline_program, FALSE, FALSE) /obj/machinery/computer/holodeck/Destroy() @@ -181,19 +182,6 @@ emergency_shutdown() return ..() -/obj/machinery/computer/holodeck/proc/generate_program_list() - for(var/typekey in GLOB.holodeck_areas_prototypes[type]) - var/area/holodeck/A = GLOB.areas_by_type[typekey] - if(!A || !A.contents.len) - continue - var/list/info_this = list() - info_this["name"] = A.name - info_this["type"] = A.type - if(A.restricted) - LAZYADD(emag_programs, list(info_this)) - else - LAZYADD(program_cache, list(info_this)) - /obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = FALSE) if(active == toggleOn) return diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index b049b7e967..10a630e034 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -283,7 +283,7 @@ There are several things that need to be remembered: alt_icon = S.anthro_mob_worn_overlay || 'icons/mob/clothing/feet_digi.dmi' variation_flag |= STYLE_DIGITIGRADE - overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(SHOES_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, variation_flag, FALSE) + overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(SHOES_LAYER, alt_icon, FALSE, NO_FEMALE_UNIFORM, S.icon_state, variation_flag, FALSE) var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER] if(OFFSET_SHOES in dna.species.offset_features) shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1] diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 49848824e4..ed90ed407f 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -556,13 +556,12 @@ By design, d1 is the smallest direction and d2 is the highest new_cable.update_icon() /obj/item/stack/cable_coil/attack_self(mob/user) - if(!use(15)) - to_chat(user, "You dont have enough cable coil to make restraints out of them") + if(amount < 15) + to_chat(user, "You don't have enough cable coil to make restraints out of them") return to_chat(user, "You start making some cable restraints.") - if(!do_after(user, 30, TRUE, user, TRUE)) - to_chat(user, "You fail to make cable restraints, you need to stand still while doing so.") - give(15) + if(!do_after(user, 30, TRUE, user, TRUE) || !use(15)) + to_chat(user, "You fail to make cable restraints, you need to be standing still to do it") return var/obj/item/restraints/handcuffs/cable/result = new(get_turf(user)) user.put_in_hands(result) diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 658e108288..44b71a025f 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -435,9 +435,9 @@ category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY | DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE -////////// -//MISC//// -////////// +/////////// +//Shields// +/////////// /datum/design/tele_shield name = "Telescopic Riot Shield" @@ -449,6 +449,30 @@ category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY +/datum/design/laser_shield + name = "Laser Resistant Riot Shield" + desc = "An advanced riot shield made of darker glasses to prevent laser fire from passing through." + id = "laser_shield" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 4000, /datum/material/glass = 1000, /datum/material/plastic = 4000, /datum/material/silver = 800, /datum/material/titanium = 600, /datum/material/plasma = 5000) + build_path = /obj/item/shield/riot/laser_proof + category = list("Weapons") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/datum/design/bullet_shield + name = "Bullet Resistant Riot Shield" + desc = "An advanced riot shield made bullet resistant plastics and heavy metals to protect against projectile harm." + id = "bullet_shield" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 4000, /datum/material/glass = 1000, /datum/material/silver = 2000, /datum/material/titanium = 1200, /datum/material/plastic = 2500) + build_path = /obj/item/shield/riot/bullet_proof + category = list("Weapons") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +////////// +//MISC//// +////////// + /datum/design/suppressor name = "Suppressor" desc = "A reverse-engineered suppressor that fits on most small arms with threaded barrels." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index dafa119873..a34a82c156 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -535,7 +535,7 @@ display_name = "Combat Cybernetic Implants" description = "Military grade combat implants to improve performance." prereq_ids = list("adv_cyber_implants","weaponry","NVGtech","high_efficiency") - design_ids = list("ci-xray", "ci-thermals", "ci-antidrop", "ci-antistun", "ci-thrusters") + design_ids = list("ci-xray", "ci-thermals", "ci-antidrop", "ci-antistun", "ci-thrusters", "ci-shield") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) ////////////////////////Tools//////////////////////// @@ -609,7 +609,7 @@ display_name = "Advanced Weapon Development Technology" description = "Our weapons are breaking the rules of reality by now." prereq_ids = list("adv_engi", "weaponry") - design_ids = list("pin_loyalty") + design_ids = list("pin_loyalty", "laser_shield", "bullet_shield") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) /datum/techweb_node/electric_weapons diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 773048f838..7a92b39692 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -89,18 +89,23 @@ "You remove [I] from [M]'s [parse_zone(selected_zone)].") qdel(S) else if(S.can_cancel) - var/close_tool_type = /obj/item/cautery + var/required_tool_type = TOOL_CAUTERY var/obj/item/close_tool = user.get_inactive_held_item() var/is_robotic = S.requires_bodypart_type == BODYPART_ROBOTIC if(is_robotic) - close_tool_type = /obj/item/screwdriver - if(istype(close_tool, close_tool_type) || iscyborg(user)) - M.surgeries -= S - user.visible_message("[user] closes [M]'s [parse_zone(selected_zone)] with [close_tool] and removes [I].", \ - "You close [M]'s [parse_zone(selected_zone)] with [close_tool] and remove [I].") - qdel(S) - else + required_tool_type = TOOL_SCREWDRIVER + if(iscyborg(user)) + close_tool = locate(/obj/item/cautery) in user.held_items + if(!close_tool) + to_chat(user, "You need to equip a cautery in an inactive slot to stop [M]'s surgery!") + return + else if(!close_tool || close_tool.tool_behaviour != required_tool_type) to_chat(user, "You need to hold a [is_robotic ? "screwdriver" : "cautery"] in your inactive hand to stop [M]'s surgery!") + return + M.surgeries -= S + user.visible_message("[user] closes [M]'s [parse_zone(selected_zone)] with [close_tool] and removes [I].", \ + "You close [M]'s [parse_zone(selected_zone)] with [close_tool] and remove [I].") + qdel(S) /proc/get_location_modifier(mob/M) var/turf/T = get_turf(M) diff --git a/html/changelog.html b/html/changelog.html index d8e8b8404a..b02b2d74a5 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,79 @@ -->
+

19 April 2020

+

Anonymous updated:

+ +

Arturlang updated:

+ +

Detective-Google updated:

+ +

Ghommie updated:

+ +

Jake Park updated:

+ +

Putnam3145 updated:

+ +

Seris02 updated:

+ +

Trilbyspaceclone updated:

+ +

UristMcAstronaut updated:

+ +

kappa-sama updated:

+ +

kevinz000 updated:

+ +

necromanceranne updated:

+ +

16 April 2020

ForrestWick updated: