diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm new file mode 100644 index 0000000000..b1fb43baa1 --- /dev/null +++ b/code/ATMOSPHERICS/components/shutoff.dm @@ -0,0 +1,50 @@ +/obj/machinery/atmospherics/valve/shutoff + icon = 'icons/atmos/clamp.dmi' + icon_state = "map_vclamp0" + + name = "automatic shutoff valve" + desc = "An automatic valve with control circuitry and pipe integrity sensor, capable of automatically isolating damaged segments of the pipe network." + var/close_on_leaks = TRUE // If false it will be always open + level = 1 + connect_types = CONNECT_TYPE_SCRUBBER | CONNECT_TYPE_SUPPLY | CONNECT_TYPE_REGULAR + +/obj/machinery/atmospherics/valve/shutoff/update_icon() + icon_state = "vclamp[open]" + +/obj/machinery/atmospherics/valve/shutoff/examine(var/mob/user) + ..() + to_chat(user, "The automatic shutoff circuit is [close_on_leaks ? "enabled" : "disabled"].") + +/obj/machinery/atmospherics/valve/shutoff/Initialize() + . = ..() + open() + hide(1) + +/obj/machinery/atmospherics/valve/shutoff/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/atmospherics/valve/shutoff/attack_hand(var/mob/user) + src.add_fingerprint(usr) + update_icon(1) + close_on_leaks = !close_on_leaks + to_chat(user, "You [close_on_leaks ? "enable" : "disable"] the automatic shutoff circuit.") + return TRUE + +/obj/machinery/atmospherics/valve/shutoff/process() + ..() + + if (!network_node1 || !network_node2) + if(open) + close() + return + + if (!close_on_leaks) + if (!open) + open() + return + + if (network_node1.leaks.len || network_node2.leaks.len) + if (open) + close() + else if (!open) + open() diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm index eb5e89276e..a611e30a89 100644 --- a/code/ATMOSPHERICS/datum_pipe_network.dm +++ b/code/ATMOSPHERICS/datum_pipe_network.dm @@ -8,76 +8,83 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS var/list/datum/pipeline/line_members = list() //membership roster to go through for updates and what not + var/list/leaks = list() + var/update = 1 //var/datum/gas_mixture/air_transient = null - Destroy() - STOP_PROCESSING_PIPENET(src) - for(var/datum/pipeline/line_member in line_members) - line_member.network = null - for(var/obj/machinery/atmospherics/normal_member in normal_members) - normal_member.reassign_network(src, null) - gases.Cut() // Do not qdel the gases, we don't own them - return ..() +/datum/pipe_network/Destroy() + STOP_PROCESSING_PIPENET(src) + for(var/datum/pipeline/line_member in line_members) + line_member.network = null + for(var/obj/machinery/atmospherics/normal_member in normal_members) + normal_member.reassign_network(src, null) + gases.Cut() // Do not qdel the gases, we don't own them + leaks.Cut() + return ..() - process() - //Equalize gases amongst pipe if called for - if(update) - update = 0 - reconcile_air() //equalize_gases(gases) +/datum/pipe_network/process() + //Equalize gases amongst pipe if called for + if(update) + update = 0 + reconcile_air() //equalize_gases(gases) - //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport - //for(var/datum/pipeline/line_member in line_members) - // line_member.process() + listclearnulls(leaks) // Let's not have forever-seals. - proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference) - //Purpose: Generate membership roster - //Notes: Assuming that members will add themselves to appropriate roster in network_expand() + //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport + //for(var/datum/pipeline/line_member in line_members) + // line_member.process() - if(!start_normal) - qdel(src) - return +/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference) + //Purpose: Generate membership roster + //Notes: Assuming that members will add themselves to appropriate roster in network_expand() - start_normal.network_expand(src, reference) + if(!start_normal) + qdel(src) + return - update_network_gases() + start_normal.network_expand(src, reference) - if((normal_members.len>0)||(line_members.len>0)) - START_PROCESSING_PIPENET(src) - else - qdel(src) + update_network_gases() - proc/merge(datum/pipe_network/giver) - if(giver==src) return 0 + if((normal_members.len>0)||(line_members.len>0)) + START_PROCESSING_PIPENET(src) + else + qdel(src) - normal_members |= giver.normal_members +/datum/pipe_network/proc/merge(datum/pipe_network/giver) + if(giver==src) return 0 - line_members |= giver.line_members + normal_members |= giver.normal_members - for(var/obj/machinery/atmospherics/normal_member in giver.normal_members) - normal_member.reassign_network(giver, src) + line_members |= giver.line_members - for(var/datum/pipeline/line_member in giver.line_members) - line_member.network = src + leaks |= giver.leaks - update_network_gases() - return 1 + for(var/obj/machinery/atmospherics/normal_member in giver.normal_members) + normal_member.reassign_network(giver, src) - proc/update_network_gases() - //Go through membership roster and make sure gases is up to date + for(var/datum/pipeline/line_member in giver.line_members) + line_member.network = src - gases = list() - volume = 0 + update_network_gases() + return 1 - for(var/obj/machinery/atmospherics/normal_member in normal_members) - var/result = normal_member.return_network_air(src) - if(result) gases += result +/datum/pipe_network/proc/update_network_gases() + //Go through membership roster and make sure gases is up to date - for(var/datum/pipeline/line_member in line_members) - gases += line_member.air + gases = list() + volume = 0 - for(var/datum/gas_mixture/air in gases) - volume += air.volume + for(var/obj/machinery/atmospherics/normal_member in normal_members) + var/result = normal_member.return_network_air(src) + if(result) gases += result - proc/reconcile_air() - equalize_gases(gases) + for(var/datum/pipeline/line_member in line_members) + gases += line_member.air + + for(var/datum/gas_mixture/air in gases) + volume += air.volume + +/datum/pipe_network/proc/reconcile_air() + equalize_gases(gases) diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index fc47bca938..b53d722458 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -1,219 +1,234 @@ -datum/pipeline +/datum/pipeline var/datum/gas_mixture/air var/list/obj/machinery/atmospherics/pipe/members var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks + // Nodes that are leaking. Used for A.S. Valves. + var/list/leaks = list() + var/datum/pipe_network/network var/alert_pressure = 0 - Destroy() - QDEL_NULL(network) +/datum/pipeline/Destroy() + QDEL_NULL(network) - if(air && air.volume) - temporarily_store_air() - for(var/obj/machinery/atmospherics/pipe/P in members) - P.parent = null - members = null - edges = null - . = ..() + if(air && air.volume) + temporarily_store_air() + for(var/obj/machinery/atmospherics/pipe/P in members) + P.parent = null + members = null + edges = null + leaks = null + . = ..() - process()//This use to be called called from the pipe networks - - //Check to see if pressure is within acceptable limits - var/pressure = air.return_pressure() - if(pressure > alert_pressure) - for(var/obj/machinery/atmospherics/pipe/member in members) - if(!member.check_pressure(pressure)) - break //Only delete 1 pipe per process - - proc/temporarily_store_air() - //Update individual gas_mixtures by volume ratio +/datum/pipeline/process()//This use to be called called from the pipe networks + //Check to see if pressure is within acceptable limits + var/pressure = air.return_pressure() + if(pressure > alert_pressure) for(var/obj/machinery/atmospherics/pipe/member in members) - member.air_temporary = new - member.air_temporary.copy_from(air) - member.air_temporary.volume = member.volume - member.air_temporary.multiply(member.volume / air.volume) + if(!member.check_pressure(pressure)) + break //Only delete 1 pipe per process - proc/build_pipeline(obj/machinery/atmospherics/pipe/base) +/datum/pipeline/proc/temporarily_store_air() + //Update individual gas_mixtures by volume ratio + + for(var/obj/machinery/atmospherics/pipe/member in members) + member.air_temporary = new + member.air_temporary.copy_from(air) + member.air_temporary.volume = member.volume + member.air_temporary.multiply(member.volume / air.volume) + +/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base) + air = new + + var/list/possible_expansions = list(base) + members = list(base) + edges = list() + + var/volume = base.volume + base.parent = src + alert_pressure = base.alert_pressure + + if(base.air_temporary) + air = base.air_temporary + base.air_temporary = null + else air = new - var/list/possible_expansions = list(base) - members = list(base) - edges = list() + if(base.leaking) + leaks |= base - var/volume = base.volume - base.parent = src - alert_pressure = base.alert_pressure + while(possible_expansions.len>0) + for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions) - if(base.air_temporary) - air = base.air_temporary - base.air_temporary = null - else - air = new + var/list/result = borderline.pipeline_expansion() + var/edge_check = result.len - while(possible_expansions.len>0) - for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions) + if(result.len>0) + for(var/obj/machinery/atmospherics/pipe/item in result) - var/list/result = borderline.pipeline_expansion() - var/edge_check = result.len + if(item.in_stasis) + continue - if(result.len>0) - for(var/obj/machinery/atmospherics/pipe/item in result) - if(!members.Find(item)) - members += item - possible_expansions += item + if(!members.Find(item)) + members += item + possible_expansions += item - volume += item.volume - item.parent = src + volume += item.volume + item.parent = src - alert_pressure = min(alert_pressure, item.alert_pressure) + alert_pressure = min(alert_pressure, item.alert_pressure) - if(item.air_temporary) - air.merge(item.air_temporary) + if(item.air_temporary) + air.merge(item.air_temporary) - edge_check-- + if(item.leaking) + leaks |= item - if(edge_check>0) - edges += borderline + edge_check-- - possible_expansions -= borderline + if(edge_check>0) + edges += borderline - air.volume = volume + possible_expansions -= borderline - proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + air.volume = volume - if(new_network.line_members.Find(src)) - return 0 +/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) - new_network.line_members += src + if(new_network.line_members.Find(src)) + return 0 - network = new_network + new_network.line_members += src - for(var/obj/machinery/atmospherics/pipe/edge in edges) - for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion()) - if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference)) - result.network_expand(new_network, edge) + network = new_network + network.leaks |= leaks - return 1 + for(var/obj/machinery/atmospherics/pipe/edge in edges) + for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion()) + if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference)) + result.network_expand(new_network, edge) - proc/return_network(obj/machinery/atmospherics/reference) - if(!network) - network = new /datum/pipe_network() - network.build_network(src, null) - //technically passing these parameters should not be allowed - //however pipe_network.build_network(..) and pipeline.network_extend(...) - // were setup to properly handle this case + return 1 - return network +/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference) + if(!network) + network = new /datum/pipe_network() + network.build_network(src, null) + //technically passing these parameters should not be allowed + //however pipe_network.build_network(..) and pipeline.network_extend(...) + // were setup to properly handle this case - proc/mingle_with_turf(turf/simulated/target, mingle_volume) - var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume) - air_sample.volume = mingle_volume + return network - if(istype(target) && target.zone) - //Have to consider preservation of group statuses - var/datum/gas_mixture/turf_copy = new - var/datum/gas_mixture/turf_original = new +/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume) + var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume) + air_sample.volume = mingle_volume - turf_copy.copy_from(target.zone.air) - turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group - turf_original.copy_from(turf_copy) + if(istype(target) && target.zone) + //Have to consider preservation of group statuses + var/datum/gas_mixture/turf_copy = new + var/datum/gas_mixture/turf_original = new - equalize_gases(list(air_sample, turf_copy)) - air.merge(air_sample) + turf_copy.copy_from(target.zone.air) + turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group + turf_original.copy_from(turf_copy) + + equalize_gases(list(air_sample, turf_copy)) + air.merge(air_sample) - target.zone.air.remove(turf_original.total_moles) - target.zone.air.merge(turf_copy) + target.zone.air.remove(turf_original.total_moles) + target.zone.air.merge(turf_copy) - else - var/datum/gas_mixture/turf_air = target.return_air() + else + var/datum/gas_mixture/turf_air = target.return_air() - equalize_gases(list(air_sample, turf_air)) - air.merge(air_sample) - //turf_air already modified by equalize_gases() + equalize_gases(list(air_sample, turf_air)) + air.merge(air_sample) + //turf_air already modified by equalize_gases() - if(network) - network.update = 1 + if(network) + network.update = 1 - proc/temperature_interact(turf/target, share_volume, thermal_conductivity) - var/total_heat_capacity = air.heat_capacity() - var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume) +/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity) + var/total_heat_capacity = air.heat_capacity() + var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume) - if(istype(target, /turf/simulated)) - var/turf/simulated/modeled_location = target + if(istype(target, /turf/simulated)) + var/turf/simulated/modeled_location = target - if(modeled_location.blocks_air) + if(modeled_location.blocks_air) - if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0)) - var/delta_temperature = air.temperature - modeled_location.temperature - - var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity)) - - air.temperature -= heat/total_heat_capacity - modeled_location.temperature += heat/modeled_location.heat_capacity - - else - var/delta_temperature = 0 - var/sharer_heat_capacity = 0 - - if(modeled_location.zone) - delta_temperature = (air.temperature - modeled_location.zone.air.temperature) - sharer_heat_capacity = modeled_location.zone.air.heat_capacity() - else - delta_temperature = (air.temperature - modeled_location.air.temperature) - sharer_heat_capacity = modeled_location.air.heat_capacity() - - var/self_temperature_delta = 0 - var/sharer_temperature_delta = 0 - - if((sharer_heat_capacity>0) && (partial_heat_capacity>0)) - var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) - - self_temperature_delta = -heat/total_heat_capacity - sharer_temperature_delta = heat/sharer_heat_capacity - else - return 1 - - air.temperature += self_temperature_delta - - if(modeled_location.zone) - modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier - else - modeled_location.air.temperature += sharer_temperature_delta - - - else - if((target.heat_capacity>0) && (partial_heat_capacity>0)) - var/delta_temperature = air.temperature - target.temperature + if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - modeled_location.temperature var/heat = thermal_conductivity*delta_temperature* \ - (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity)) + (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity)) air.temperature -= heat/total_heat_capacity - if(network) - network.update = 1 + modeled_location.temperature += heat/modeled_location.heat_capacity - //surface must be the surface area in m^2 - proc/radiate_heat_to_space(surface, thermal_conductivity) - var/gas_density = air.total_moles/air.volume - thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio + else + var/delta_temperature = 0 + var/sharer_heat_capacity = 0 - // We only get heat from the star on the exposed surface area. - // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase. - var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity + if(modeled_location.zone) + delta_temperature = (air.temperature - modeled_location.zone.air.temperature) + sharer_heat_capacity = modeled_location.zone.air.heat_capacity() + else + delta_temperature = (air.temperature - modeled_location.air.temperature) + sharer_heat_capacity = modeled_location.air.heat_capacity() - // Previously, the temperature would enter equilibrium at 26C or 294K. - // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on. - // It currently should stabilise at 129.6K or -143.6C - heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4 + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 - air.add_thermal_energy(heat_gain) - if(network) - network.update = 1 + if((sharer_heat_capacity>0) && (partial_heat_capacity>0)) + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/total_heat_capacity + sharer_temperature_delta = heat/sharer_heat_capacity + else + return 1 + + air.temperature += self_temperature_delta + + if(modeled_location.zone) + modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier + else + modeled_location.air.temperature += sharer_temperature_delta + + + else + if((target.heat_capacity>0) && (partial_heat_capacity>0)) + var/delta_temperature = air.temperature - target.temperature + + var/heat = thermal_conductivity*delta_temperature* \ + (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity)) + + air.temperature -= heat/total_heat_capacity + if(network) + network.update = 1 + +//surface must be the surface area in m^2 +/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity) + var/gas_density = air.total_moles/air.volume + thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio + + // We only get heat from the star on the exposed surface area. + // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase. + var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity + + // Previously, the temperature would enter equilibrium at 26C or 294K. + // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on. + // It currently should stabilise at 129.6K or -143.6C + heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4 + + air.add_thermal_energy(heat_gain) + if(network) + network.update = 1 diff --git a/code/ATMOSPHERICS/pipes/he_pipes.dm b/code/ATMOSPHERICS/pipes/he_pipes.dm index 2d77e3a4ca..1b283e3ba4 100644 --- a/code/ATMOSPHERICS/pipes/he_pipes.dm +++ b/code/ATMOSPHERICS/pipes/he_pipes.dm @@ -67,8 +67,22 @@ return update_icon() + handle_leaking() return +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_leaking(var/new_leaking) // They already process, no need for manual processing toggles. + if(new_leaking && !leaking) + leaking = TRUE + if(parent) + parent.leaks |= src + if(parent.network) + parent.network.leaks |= src + else if (!new_leaking && leaking) + leaking = FALSE + if(parent) + parent.leaks -= src + if(parent.network) + parent.network.leaks -= src /obj/machinery/atmospherics/pipe/simple/heat_exchanging/process() if(!parent) @@ -180,4 +194,5 @@ return update_icon() + handle_leaking() return diff --git a/code/ATMOSPHERICS/pipes/he_pipes_vr.dm b/code/ATMOSPHERICS/pipes/he_pipes_vr.dm new file mode 100644 index 0000000000..d763f75b74 --- /dev/null +++ b/code/ATMOSPHERICS/pipes/he_pipes_vr.dm @@ -0,0 +1,2 @@ +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_leaking(var/new_leaking) + return //Nope \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm index 4b0df6f2ef..f44bfc5686 100644 --- a/code/ATMOSPHERICS/pipes/manifold.dm +++ b/code/ATMOSPHERICS/pipes/manifold.dm @@ -68,11 +68,10 @@ node3 = null update_icon() + handle_leaking() ..() -<<<<<<< HEAD -======= /obj/machinery/atmospherics/pipe/manifold/handle_leaking() if(node1 && node2 && node3) set_leaking(FALSE) @@ -87,7 +86,6 @@ else . = PROCESS_KILL ->>>>>>> 31518fe... Merge pull request #6344 from Mechoid/ManifoldLeaking /obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color) ..() //for updating connected atmos device pipes (i.e. vents, manifolds, etc) @@ -171,6 +169,7 @@ var/turf/T = get_turf(src) if(level == 1 && !T.is_plating()) hide(1) update_icon() + handle_leaking() /obj/machinery/atmospherics/pipe/manifold/visible icon_state = "map" diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm index 99274183b4..197c1a090b 100644 --- a/code/ATMOSPHERICS/pipes/manifold4w.dm +++ b/code/ATMOSPHERICS/pipes/manifold4w.dm @@ -66,11 +66,10 @@ node4 = null update_icon() + handle_leaking() ..() -<<<<<<< HEAD -======= /obj/machinery/atmospherics/pipe/manifold4w/handle_leaking() if(node1 && node2 && node3 && node4) set_leaking(FALSE) @@ -85,7 +84,6 @@ else . = PROCESS_KILL ->>>>>>> 31518fe... Merge pull request #6344 from Mechoid/ManifoldLeaking /obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color) ..() //for updating connected atmos device pipes (i.e. vents, manifolds, etc) @@ -173,6 +171,7 @@ var/turf/T = get_turf(src) if(level == 1 && !T.is_plating()) hide(1) update_icon() + handle_leaking() /obj/machinery/atmospherics/pipe/manifold4w/visible icon_state = "map_4way" diff --git a/code/ATMOSPHERICS/pipes/pipe_base.dm b/code/ATMOSPHERICS/pipes/pipe_base.dm index a035857e54..d1bb92fac7 100644 --- a/code/ATMOSPHERICS/pipes/pipe_base.dm +++ b/code/ATMOSPHERICS/pipes/pipe_base.dm @@ -6,6 +6,7 @@ var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke var/datum/pipeline/parent var/volume = 0 + var/leaking = FALSE // Do not set directly, use set_leaking(TRUE/FALSE) layer = PIPES_LAYER use_power = 0 @@ -13,6 +14,7 @@ pipe_flags = 0 // Does not have PIPING_DEFAULT_LAYER_ONLY flag. var/alert_pressure = 80*ONE_ATMOSPHERE + var/in_stasis = FALSE //minimum pressure before check_pressure(...) should be called can_buckle = 1 @@ -30,6 +32,31 @@ /obj/machinery/atmospherics/pipe/hides_under_flooring() return level != 2 +/obj/machinery/atmospherics/pipe/proc/set_leaking(var/new_leaking) + if(new_leaking && !leaking) + if(!speed_process) + START_MACHINE_PROCESSING(src) + else + START_PROCESSING(SSfastprocess, src) + leaking = TRUE + if(parent) + parent.leaks |= src + if(parent.network) + parent.network.leaks |= src + else if (!new_leaking && leaking) + if(!speed_process) + STOP_MACHINE_PROCESSING(src) + else + STOP_PROCESSING(SSfastprocess, src) + leaking = FALSE + if(parent) + parent.leaks -= src + if(parent.network) + parent.network.leaks -= src + +/obj/machinery/atmospherics/pipe/proc/handle_leaking() // Used specifically to update leaking status on different pipes. + return + /obj/machinery/atmospherics/pipe/proc/pipeline_expansion() return null diff --git a/code/ATMOSPHERICS/pipes/pipe_base_vr.dm b/code/ATMOSPHERICS/pipes/pipe_base_vr.dm new file mode 100644 index 0000000000..d20e73ae89 --- /dev/null +++ b/code/ATMOSPHERICS/pipes/pipe_base_vr.dm @@ -0,0 +1,2 @@ +/obj/machinery/atmospherics/pipe/set_leaking(var/new_leaking) + return // N O P E \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes/simple.dm b/code/ATMOSPHERICS/pipes/simple.dm index 6aee81807e..eb980c3b47 100644 --- a/code/ATMOSPHERICS/pipes/simple.dm +++ b/code/ATMOSPHERICS/pipes/simple.dm @@ -1,6 +1,6 @@ // // Simple Pipes - Just a tube, maybe bent -// +// /obj/machinery/atmospherics/pipe/simple icon = 'icons/atmos/pipes.dmi' icon_state = "" @@ -34,6 +34,14 @@ icon = null alpha = 255 +/obj/machinery/atmospherics/pipe/simple/process() + if(!parent) + ..() + else if(leaking) + parent.mingle_with_turf(loc, volume) + else + . = PROCESS_KILL + /obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) var/datum/gas_mixture/environment = loc.return_air() @@ -147,6 +155,7 @@ var/turf/T = loc if(level == 1 && !T.is_plating()) hide(1) update_icon() + handle_leaking() /obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference) if(reference == node1) @@ -160,9 +169,16 @@ node2 = null update_icon() + handle_leaking() return null +/obj/machinery/atmospherics/pipe/simple/handle_leaking() + if(node1 && node2) + set_leaking(FALSE) + else + set_leaking(TRUE) + /obj/machinery/atmospherics/pipe/simple/visible icon_state = "intact" level = 2 diff --git a/code/ATMOSPHERICS/pipes/universal.dm b/code/ATMOSPHERICS/pipes/universal.dm index 2d8bd09dff..00d2746947 100644 --- a/code/ATMOSPHERICS/pipes/universal.dm +++ b/code/ATMOSPHERICS/pipes/universal.dm @@ -48,7 +48,7 @@ construction_type = /obj/item/pipe/binary pipe_state = "universal" -/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0) +/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0) // Doesn't leak. It's a special pipe. if(!check_icon_cache()) return diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 0343fe4249..eb363c08cb 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -84,7 +84,6 @@ // 0 .. 9 if(48 to 57) //Numbers - if(!last_char_group) continue //suppress at start of string if(!allow_numbers) continue // If allow_numbers is 0, then don't do this. output += ascii2text(ascii_char) number_of_alphanumeric++ diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index e367769b07..3bd1a0afb2 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -2,6 +2,9 @@ /atom/proc/attack_generic(mob/user as mob) return 0 +/atom/proc/take_damage(var/damage) + return 0 + /* Humans: Adds an exception for gloves, to allow special glove types like the ninja ones. diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm index e3b9a148cc..e387309da7 100644 --- a/code/datums/supplypacks/engineering.dm +++ b/code/datums/supplypacks/engineering.dm @@ -21,6 +21,20 @@ containertype = /obj/structure/closet/crate/engineering containername = "Superconducting Magnetic Coil crate" +/datum/supply_pack/eng/smescoil/super_capacity + name = "Superconducting Capacitance Coil" + contains = list(/obj/item/weapon/smes_coil/super_capacity) + cost = 90 + containertype = /obj/structure/closet/crate/engineering + containername = "Superconducting Capacitance Coil crate" + +/datum/supply_pack/eng/smescoil/super_io + name = "Superconducting Transmission Coil" + contains = list(/obj/item/weapon/smes_coil/super_io) + cost = 90 + containertype = /obj/structure/closet/crate/engineering + containername = "Superconducting Transmission Coil crate" + /datum/supply_pack/eng/shield_capacitor name = "Shield Capacitor" contains = list(/obj/machinery/shield_capacitor) @@ -290,4 +304,4 @@ cost = 75 containername = "Tritium crate" containertype = /obj/structure/closet/crate/engineering - contains = list(/obj/fiftyspawner/tritium) \ No newline at end of file + contains = list(/obj/fiftyspawner/tritium) diff --git a/code/datums/supplypacks/recreation.dm b/code/datums/supplypacks/recreation.dm index 9c12c17a14..357f0eaead 100644 --- a/code/datums/supplypacks/recreation.dm +++ b/code/datums/supplypacks/recreation.dm @@ -87,4 +87,14 @@ contains = list( /obj/item/weapon/storage/box/wormcan, /obj/item/weapon/storage/box/wormcan/deluxe + ) + +/datum/supply_pack/recreation/ltagturrets + name = "Laser Tag Turrets" + cost = 40 + containername = "laser tag turret crate" + containertype = /obj/structure/closet/crate + contains = list( + /obj/machinery/porta_turret/lasertag/blue, + /obj/machinery/porta_turret/lasertag/red ) \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index c87427bc44..24c2ed5f52 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -35,6 +35,22 @@ /obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob) attackpylon(user, W.force) +/obj/structure/cult/pylon/take_damage(var/damage) + pylonhit(damage) + +/obj/structure/cult/pylon/bullet_act(var/obj/item/projectile/Proj) + pylonhit(Proj.get_structure_damage()) + +/obj/structure/cult/pylon/proc/pylonhit(var/damage) + if(!isbroken) + if(prob(1+ damage * 5)) + visible_message("The pylon shatters!") + playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1) + isbroken = 1 + density = 0 + icon_state = "pylon-broken" + set_light(0) + /obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage) if(!isbroken) if(prob(1+ damage * 5)) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index f7a454a7de..889e11c4e4 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -80,7 +80,7 @@ if(C == user) user.visible_message("[user] climbs on \the [src].","You climb on \the [src].") else - visible_message("\The [C] has been laid on \the [src] by [user].", 3) + visible_message("\The [C] has been laid on \the [src] by [user].") if(C.client) C.client.perspective = EYE_PERSPECTIVE C.client.eye = src diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index ed23884103..484678c942 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -448,4 +448,8 @@ update_flag ..() src.air_contents.adjust_gas("phoron", MolesForPressure()) src.update_icon() - return 1 \ No newline at end of file + return 1 + +/obj/machinery/portable_atmospherics/canister/take_damage(var/damage) + src.health -= damage + healthcheck() \ No newline at end of file diff --git a/code/game/machinery/atmoalter/clamp.dm b/code/game/machinery/atmoalter/clamp.dm new file mode 100644 index 0000000000..318145c229 --- /dev/null +++ b/code/game/machinery/atmoalter/clamp.dm @@ -0,0 +1,154 @@ +//Good luck. --BlueNexus + +//Static version of the clamp +/obj/machinery/clamp + name = "stasis clamp" + desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." + description_info = "Click-dragging this to yourself while adjacent will attempt to remove it from the pipe." + icon = 'icons/atmos/clamp.dmi' + icon_state = "pclamp0" + anchored = 1.0 + var/obj/machinery/atmospherics/pipe/simple/target = null + var/open = 1 + + var/datum/pipe_network/network_node1 + var/datum/pipe_network/network_node2 + +/obj/machinery/clamp/New(loc, var/obj/machinery/atmospherics/pipe/simple/to_attach = null) + ..() + if(istype(to_attach)) + target = to_attach + else + target = locate(/obj/machinery/atmospherics/pipe/simple) in loc + if(target) + update_networks() + dir = target.dir + return 1 + +/obj/machinery/clamp/proc/update_networks() + if(!target) + return + else + var/obj/machinery/atmospherics/pipe/node1 = target.node1 + var/obj/machinery/atmospherics/pipe/node2 = target.node2 + if(istype(node1)) + var/datum/pipeline/P1 = node1.parent + network_node1 = P1.network + if(istype(node2)) + var/datum/pipeline/P2 = node2.parent + network_node2 = P2.network + +/obj/machinery/clamp/attack_hand(var/mob/user) + if(!target) + return FALSE + if(!open) + open() + else + close() + to_chat(user, "You turn [open ? "off" : "on"] \the [src]") + return TRUE + +/obj/machinery/clamp/Destroy() + if(!open) + spawn(-1) open() + . = ..() + +/obj/machinery/clamp/proc/open() + if(open || !target) + return 0 + + target.build_network() + + + if(network_node1&&network_node2) + network_node1.merge(network_node2) + network_node2 = network_node1 + + if(network_node1) + network_node1.update = 1 + else if(network_node2) + network_node2.update = 1 + + update_networks() + + open = 1 + icon_state = "pclamp0" + target.in_stasis = 0 + return 1 + +/obj/machinery/clamp/proc/close() + if(!open) + return 0 + + qdel(target.parent) + + if(network_node1) + qdel(network_node1) + if(network_node2) + qdel(network_node2) + + var/obj/machinery/atmospherics/pipe/node1 = null + var/obj/machinery/atmospherics/pipe/node2 = null + + if(target.node1) + target.node1.build_network() + node1 = target.node1 + if(target.node2) + target.node2.build_network() + node2 = target.node2 + if(istype(node1) && node1.parent) + var/datum/pipeline/P1 = node1.parent + P1.build_pipeline(node1) + qdel(P1) + if(istype(node2) && node2.parent) + var/datum/pipeline/P2 = node2.parent + P2.build_pipeline(node2) + qdel(P2) +// P1.build_network() +// P2.build_network() + + open = 0 + icon_state = "pclamp1" + target.in_stasis = 1 + + return 1 + +/obj/machinery/clamp/MouseDrop(obj/over_object as obj) + if(!usr) + return + + if(open && over_object == usr && Adjacent(usr)) + to_chat(usr, "You begin to remove \the [src]...") + if (do_after(usr, 30, src)) + to_chat(usr, "You have removed \the [src].") + var/obj/item/clamp/C = new/obj/item/clamp(src.loc) + C.forceMove(usr.loc) + if(ishuman(usr)) + usr.put_in_hands(C) + qdel(src) + return + else + to_chat(usr, "You can't remove \the [src] while it's active!") + +/obj/item/clamp + name = "stasis clamp" + desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field." + icon = 'icons/atmos/clamp.dmi' + icon_state = "pclamp0" + origin_tech = list(TECH_ENGINEERING = 4, TECH_MAGNET = 4) + +/obj/item/clamp/afterattack(var/atom/A, mob/user as mob, proximity) + if(!proximity) + return + + if (istype(A, /obj/machinery/atmospherics/pipe/simple)) + to_chat(user, "You begin to attach \the [src] to \the [A]...") + var/C = locate(/obj/machinery/clamp) in get_turf(A) + if (do_after(user, 30, src) && !C) + if(!user.unEquip(src)) + return + to_chat(user, "You have attached \the [src] to \the [A].") + new/obj/machinery/clamp(A.loc, A) + qdel(src) + if(C) + to_chat(user, "\The [C] is already attached to the pipe at this location!") diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index b3d5af5f3e..34fda2bb06 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -113,7 +113,7 @@ triggerCameraAlarm() update_icon() update_coverage() - START_PROCESSING(SSobj, src) + START_PROCESSING(SSobj, src) /obj/machinery/camera/bullet_act(var/obj/item/projectile/P) take_damage(P.get_structure_damage()) @@ -283,7 +283,7 @@ icon_state = initial(icon_state) add_hiddenprint(user) -/obj/machinery/camera/proc/take_damage(var/force, var/message) +/obj/machinery/camera/take_damage(var/force, var/message) //prob(25) gives an average of 3-4 hits if (force >= toughness && (force > toughness*4 || prob(25))) destroy() diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 765ced8a39..42725bbe28 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -2,52 +2,6 @@ CONTAINS: Deployable items Barricades - -for reference: - access_security = 1 - access_brig = 2 - access_armory = 3 - access_forensics_lockers= 4 - access_medical = 5 - access_morgue = 6 - access_tox = 7 - access_tox_storage = 8 - access_genetics = 9 - access_engine = 10 - access_engine_equip= 11 - access_maint_tunnels = 12 - access_external_airlocks = 13 - access_emergency_storage = 14 - access_change_ids = 15 - access_ai_upload = 16 - access_teleporter = 17 - access_eva = 18 - access_heads = 19 - access_captain = 20 - access_all_personal_lockers = 21 - access_chapel_office = 22 - access_tech_storage = 23 - access_atmospherics = 24 - access_bar = 25 - access_janitor = 26 - access_crematorium = 27 - access_kitchen = 28 - access_robotics = 29 - access_rd = 30 - access_cargo = 31 - access_construction = 32 - access_chemistry = 33 - access_cargo_bot = 34 - access_hydroponics = 35 - access_manufacturing = 36 - access_library = 37 - access_lawyer = 38 - access_virology = 39 - access_cmo = 40 - access_qm = 41 - access_court = 42 - access_clown = 43 - access_mime = 44 */ //Barricades! @@ -80,6 +34,7 @@ for reference: return material /obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob) + user.setClickCooldown(user.get_attack_speed(W)) if(istype(W, /obj/item/stack)) var/obj/item/stack/D = W if(D.get_material_name() != material.name) @@ -96,37 +51,54 @@ for reference: return return else - user.setClickCooldown(user.get_attack_speed(W)) switch(W.damtype) if("fire") health -= W.force * 1 if("brute") health -= W.force * 0.75 - else - if(health <= 0) - visible_message("The barricade is smashed apart!") - dismantle() - qdel(src) - return + if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD))) + playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1) + else + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + CheckHealth() ..() +/obj/structure/barricade/proc/CheckHealth() + if(health <= 0) + dismantle() + return + +/obj/structure/barricade/take_damage(var/damage) + health -= damage + CheckHealth() + return + +/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + if(material == get_material_by_name("resin")) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD))) + playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1) + else + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + user.do_attack_animation(src) + health -= damage + CheckHealth() + return + /obj/structure/barricade/proc/dismantle() material.place_dismantled_product(get_turf(src)) + visible_message("\The [src] falls apart!") qdel(src) return /obj/structure/barricade/ex_act(severity) switch(severity) if(1.0) - visible_message("\The [src] is blown apart!") - qdel(src) - return + dismantle() if(2.0) health -= 25 - if(health <= 0) - visible_message("\The [src] is blown apart!") - dismantle() - return + CheckHealth() /obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. if(istype(mover) && mover.checkpass(PASSTABLE)) @@ -158,6 +130,7 @@ for reference: icon_state = "barrier[locked]" /obj/machinery/deployable/barrier/attackby(obj/item/weapon/W as obj, mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(istype(W, /obj/item/weapon/card/id/)) if(allowed(user)) if (emagged < 2.0) @@ -196,11 +169,28 @@ for reference: health -= W.force * 0.75 if("brute") health -= W.force * 0.5 - else - if(health <= 0) - explode() + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + CheckHealth() ..() +/obj/machinery/deployable/barrier/proc/CheckHealth() + if(health <= 0) + explode() + return + +/obj/machinery/deployable/barrier/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + user.do_attack_animation(src) + health -= damage + CheckHealth() + return + +/obj/machinery/deployable/barrier/take_damage(var/damage) + health -= damage + CheckHealth() + return + /obj/machinery/deployable/barrier/ex_act(severity) switch(severity) if(1.0) @@ -208,8 +198,7 @@ for reference: return if(2.0) health -= 25 - if(health <= 0) - explode() + CheckHealth() return /obj/machinery/deployable/barrier/emp_act(severity) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index d276efef35..c55a7d8345 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -308,7 +308,7 @@ operating = -1 return 1 -/obj/machinery/door/proc/take_damage(var/damage) +/obj/machinery/door/take_damage(var/damage) var/initialhealth = src.health src.health = max(0, src.health - damage) if(src.health <= 0 && initialhealth > 0) diff --git a/code/game/machinery/pipe/pipe_recipes.dm b/code/game/machinery/pipe/pipe_recipes.dm index f0ae483055..a54cdd4eee 100644 --- a/code/game/machinery/pipe/pipe_recipes.dm +++ b/code/game/machinery/pipe/pipe_recipes.dm @@ -27,6 +27,7 @@ var/global/list/atmos_pipe_recipes = null new /datum/pipe_recipe/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump), new /datum/pipe_recipe/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate), new /datum/pipe_recipe/pipe("High Power Gas Pump",/obj/machinery/atmospherics/binary/pump/high_power), + //new /datum/pipe_recipe/pipe("Automatic Shutoff Valve",/obj/machinery/atmospherics/valve/shutoff), //VOREStation Removal: Without leaks, those are just regular valves, new /datum/pipe_recipe/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber), new /datum/pipe_recipe/meter("Meter"), new /datum/pipe_recipe/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter), diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 12343bb343..ab77220281 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -36,83 +36,73 @@ name = "turret" catalogue_data = list(/datum/category_item/catalogue/technology/turret) icon = 'icons/obj/turrets.dmi' - icon_state = "turret_cover" - anchored = 1 + icon_state = "turret_cover_normal" + anchored = TRUE - density = 0 - use_power = 1 //this turret uses and requires power + density = FALSE + use_power = TRUE //this turret uses and requires power idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power power_channel = EQUIP //drains power from the EQUIPMENT channel req_one_access = list(access_security, access_heads) - // icon_states for turrets. - // These are for the turret covers. - var/closed_state = "turret_cover" // For when it is closed. - var/raising_state = "popup" // When turret is opening. - var/opened_state = "open" // When fully opened. - var/lowering_state = "popdown" // When closing. - var/gun_active_state = "target_prism" // The actual gun's icon_state when active. - var/gun_disabled_state = "grey_target_prism" // Gun sprite when depowered/disabled. - var/gun_destroyed_state = "destroyed_target_prism" // Turret sprite for when the turret dies. - - var/raised = 0 //if the turret cover is "open" and the turret is raised - var/raising= 0 //if the turret is currently opening or closing its cover - var/health = 80 //the turret's health - var/maxhealth = 80 //turrets maximal health. - var/auto_repair = 0 //if 1 the turret slowly repairs itself. - var/locked = 1 //if the turret's behaviour control access is locked - var/controllock = 0 //if the turret responds to control panels + var/raised = FALSE //if the turret cover is "open" and the turret is raised + var/raising= FALSE //if the turret is currently opening or closing its cover + var/health = 80 //the turret's health + var/maxhealth = 80 //turrets maximal health. + var/auto_repair = FALSE //if 1 the turret slowly repairs itself. + var/locked = TRUE //if the turret's behaviour control access is locked + var/controllock = FALSE //if the turret responds to control panels var/installation = /obj/item/weapon/gun/energy/gun //the type of weapon installed - var/gun_charge = 0 //the charge of the gun inserted - var/projectile = null //holder for bullettype - var/eprojectile = null //holder for the shot when emagged - var/reqpower = 500 //holder for power needed - var/iconholder = null //holder for the icon_state. 1 for sprite based on icon_color, null for blue. - var/icon_color = "orange" // When iconholder is set to 1, the icon_state changes based on what is in this variable. - var/egun = null //holder to handle certain guns switching bullettypes + var/gun_charge = 0 //the charge of the gun inserted + var/projectile = null //holder for bullettype + var/lethal_projectile = null //holder for the shot when emagged + var/reqpower = 500 //holder for power needed + var/turret_type = "normal" + var/icon_color = "blue" + var/lethal_icon_color = "blue" - var/last_fired = 0 //1: if the turret is cooling down from a shot, 0: turret is ready to fire + var/last_fired = FALSE //TRUE: if the turret is cooling down from a shot, FALSE: turret is ready to fire var/shot_delay = 1.5 SECONDS //1.5 seconds between each shot - var/check_arrest = 1 //checks if the perp is set to arrest - var/check_records = 1 //checks if a security record exists at all - var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have - var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements - var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos) - var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg - var/check_all = 0 //If active, will fire on anything, including synthetics. - var/ailock = 0 // AI cannot use this - var/faction = null //if set, will not fire at people in the same faction for any reason. + var/check_arrest = TRUE //checks if the perp is set to arrest + var/check_records = TRUE //checks if a security record exists at all + var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have + var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements + var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos) + var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg + var/check_all = FALSE //If active, will fire on anything, including synthetics. + var/ailock = FALSE // AI cannot use this + var/faction = null //if set, will not fire at people in the same faction for any reason. - var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!) + var/attacked = FALSE //if set to TRUE, the turret gets pissed off and shoots at people nearby (unless they have sec access!) - var/enabled = 1 //determines if the turret is on - var/lethal = 0 //whether in lethal or stun mode - var/disabled = 0 + var/enabled = TRUE //determines if the turret is on + var/lethal = FALSE //whether in lethal or stun mode + var/disabled = FALSE - var/shot_sound //what sound should play when the turret fires - var/eshot_sound //what sound should play when the emagged turret fires + var/shot_sound //what sound should play when the turret fires + var/lethal_shot_sound //what sound should play when the emagged turret fires var/datum/effect/effect/system/spark_spread/spark_system //the spark system, used for generating... sparks? - var/wrenching = 0 + var/wrenching = FALSE var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range var/timeout = 10 // When a turret pops up, then finds nothing to shoot at, this number decrements until 0, when it pops down. var/can_salvage = TRUE // If false, salvaging doesn't give you anything. /obj/machinery/porta_turret/crescent req_one_access = list(access_cent_specops) - enabled = 0 - ailock = 1 - check_synth = 0 - check_access = 1 - check_arrest = 1 - check_records = 1 - check_weapons = 1 - check_anomalies = 1 - check_all = 0 + enabled = FALSE + ailock = TRUE + check_synth = FALSE + check_access = TRUE + check_arrest = TRUE + check_records = TRUE + check_weapons = TRUE + check_anomalies = TRUE + check_all = FALSE /obj/machinery/porta_turret/can_catalogue(mob/user) // Dead turrets can't be scanned. if(stat & BROKEN) @@ -121,8 +111,8 @@ return ..() /obj/machinery/porta_turret/stationary - ailock = 1 - lethal = 1 + ailock = TRUE + lethal = TRUE installation = /obj/item/weapon/gun/energy/laser /obj/machinery/porta_turret/stationary/syndie // Generic turrets for POIs that need to not shoot their buddies. @@ -155,7 +145,7 @@ name = "interior anti-boarding turret" desc = "A very tough looking turret made by alien hands." catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_turret) - icon_state = "alien_turret_cover" + icon_state = "turret_cover_alien" req_one_access = list(access_alien) installation = /obj/item/weapon/gun/energy/alien enabled = TRUE @@ -164,19 +154,12 @@ check_all = TRUE health = 250 // Similar to the AI turrets. maxhealth = 250 - - closed_state = "alien_turret_cover" - raising_state = "alien_popup" - opened_state = "alien_open" - lowering_state = "alien_popdown" - gun_active_state = "alien_gun" - gun_disabled_state = "alien_gun_disabled" - gun_destroyed_state = "alien_gun_destroyed" + turret_type = "alien" /obj/machinery/porta_turret/alien/destroyed // Turrets that are already dead, to act as a warning of what the rest of the submap contains. name = "broken interior anti-boarding turret" desc = "A very tough looking turret made by alien hands. This one looks destroyed, thankfully." - icon_state = "alien_gun_destroyed" + icon_state = "destroyed_target_prism_alien" stat = BROKEN can_salvage = FALSE // So you need to actually kill a turret to get the alien gun. @@ -184,18 +167,11 @@ name = "industrial turret" desc = "This variant appears to be much more rugged." req_one_access = list(access_heads) + icon_state = "turret_cover_industrial" installation = /obj/item/weapon/gun/energy/phasegun health = 200 maxhealth = 200 - - icon_state = "turret_cover_industrial" - closed_state = "turret_cover_industrial" - raising_state = "popup_industrial" - opened_state = "open_industrial" - lowering_state = "popdown_industrial" - gun_active_state = "target_prism_industrial" - gun_disabled_state = "grey_target_prism_industrial" - gun_destroyed_state = "destroyed_target_prism_industrial" + turret_type = "industrial" /obj/machinery/porta_turret/industrial/bullet_act(obj/item/projectile/Proj) var/damage = round(Proj.get_structure_damage() * 1.33) @@ -205,10 +181,10 @@ if(enabled) if(!attacked && !emagged) - attacked = 1 + attacked = TRUE spawn() sleep(60) - attacked = 0 + attacked = FALSE take_damage(damage) @@ -230,6 +206,97 @@ check_all = TRUE can_salvage = FALSE // So you can't just twoshot a turret and get a fancy gun +/obj/machinery/porta_turret/lasertag + name = "lasertag turret" + turret_type = "normal" + req_one_access = list() + installation = /obj/item/weapon/gun/energy/lasertag/omni + + locked = FALSE + enabled = FALSE + anchored = FALSE + //These two are used for lasertag + check_synth = FALSE + check_weapons = FALSE + //These vars aren't used + check_access = FALSE + check_arrest = FALSE + check_records = FALSE + check_anomalies = FALSE + check_all = FALSE + +/obj/machinery/porta_turret/lasertag/red + turret_type = "red" + installation = /obj/item/weapon/gun/energy/lasertag/red + check_weapons = TRUE // Used to target blue players + +/obj/machinery/porta_turret/lasertag/blue + turret_type = "blue" + installation = /obj/item/weapon/gun/energy/lasertag/blue + check_synth = TRUE // Used to target red players + +/obj/machinery/porta_turret/lasertag/assess_living(var/mob/living/L) + if(!ishuman(L)) + return TURRET_NOT_TARGET + + if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var + return TURRET_NOT_TARGET + + if(get_dist(src, L) > 7) //if it's too far away, why bother? + return TURRET_NOT_TARGET + + if(!(L in check_trajectory(L, src))) //check if we have true line of sight + return TURRET_NOT_TARGET + + if(L.lying) //Don't need to stun-lock the players + return TURRET_NOT_TARGET + + if(ishuman(L)) + var/mob/living/carbon/human/M = L + if(istype(M.wear_suit, /obj/item/clothing/suit/redtag) && check_synth) // Checks if they are a red player + return TURRET_PRIORITY_TARGET + + if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag) && check_weapons) // Checks if they are a blue player + return TURRET_PRIORITY_TARGET + +/obj/machinery/porta_turret/lasertag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["access"] = !isLocked(user) + data["locked"] = locked + data["enabled"] = enabled + data["is_lethal"] = 1 + data["lethal"] = lethal + + if(data["access"]) + var/settings[0] + settings[++settings.len] = list("category" = "Target Red", "setting" = "check_synth", "value" = check_synth) // Could not get the UI to work with new vars specifically for lasertag turrets -Nalarac + settings[++settings.len] = list("category" = "Target Blue", "setting" = "check_weapons", "value" = check_weapons) // So I'm using these variables since they don't do anything else in this case + data["settings"] = settings + + ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/porta_turret/lasertag/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["command"] && href_list["value"]) + var/value = text2num(href_list["value"]) + if(href_list["command"] == "enable") + enabled = value + else if(href_list["command"] == "lethal") + lethal = value + else if(href_list["command"] == "check_synth") + check_synth = value + else if(href_list["command"] == "check_weapons") + check_weapons = value + + return 1 + /obj/machinery/porta_turret/Initialize() //Sets up a spark system spark_system = new /datum/effect/effect/system/spark_spread @@ -239,7 +306,7 @@ setup() // If turrets ever switch overlays, this will need to be cached and reapplied each time overlays_cut() is called. - var/image/turret_opened_overlay = image(icon, opened_state) + var/image/turret_opened_overlay = image(icon, "open_[turret_type]") turret_opened_overlay.layer = layer-0.1 add_overlay(turret_opened_overlay) return ..() @@ -251,99 +318,85 @@ /obj/machinery/porta_turret/update_icon() if(stat & BROKEN) // Turret is dead. - icon_state = gun_destroyed_state + icon_state = "destroyed_target_prism_[turret_type]" else if(raised || raising) // Turret is open. if(powered() && enabled) // Trying to shoot someone. - icon_state = gun_active_state + if(lethal) + icon_state = "[lethal_icon_color]_target_prism_[turret_type]" + else + icon_state = "[icon_color]_target_prism_[turret_type]" else // Disabled. - icon_state = gun_disabled_state + icon_state = "grey_target_prism_[turret_type]" else // Its closed. - icon_state = closed_state + icon_state = "turret_cover_[turret_type]" /obj/machinery/porta_turret/proc/setup() var/obj/item/weapon/gun/energy/E = installation //All energy-based weapons are applicable + var/obj/item/projectile/P = initial(E.projectile_type) //var/obj/item/ammo_casing/shottype = E.projectile_type - projectile = initial(E.projectile_type) - eprojectile = projectile - shot_sound = initial(E.fire_sound) - eshot_sound = shot_sound + projectile = P + lethal_projectile = projectile + shot_sound = initial(P.fire_sound) + lethal_shot_sound = shot_sound + + if(istype(P, /obj/item/projectile/energy)) + icon_color = "orange" + + else if(istype(P, /obj/item/projectile/beam/stun)) + icon_color = "blue" + + else if(istype(P, /obj/item/projectile/beam/lasertag)) + icon_color = "blue" + + else if(istype(P, /obj/item/projectile/beam)) + icon_color = "red" + + else + icon_color = "blue" + + lethal_icon_color = icon_color weapon_setup(installation) /obj/machinery/porta_turret/proc/weapon_setup(var/guntype) switch(guntype) - if(/obj/item/weapon/gun/energy/laser/practice) - iconholder = 1 - eprojectile = /obj/item/projectile/beam - -// if(/obj/item/weapon/gun/energy/laser/practice/sc_laser) -// iconholder = 1 -// eprojectile = /obj/item/projectile/beam - if(/obj/item/weapon/gun/energy/gun/burst) - iconholder = 1 - eprojectile = /obj/item/projectile/beam/burstlaser - eshot_sound = 'sound/weapons/Laser.ogg' - icon_color = "red" - projectile = /obj/item/projectile/beam/stun/weak - shot_sound = 'sound/weapons/Taser.ogg' + lethal_icon_color = "red" + lethal_projectile = /obj/item/projectile/beam/burstlaser + lethal_shot_sound = 'sound/weapons/Laser.ogg' shot_delay = 1 SECOND if(/obj/item/weapon/gun/energy/phasegun) - iconholder = 1 - eprojectile = /obj/item/projectile/energy/phase/heavy - eshot_sound = 'sound/weapons/gunshot_pathetic.ogg' icon_color = "orange" - projectile = /obj/item/projectile/energy/phase - shot_sound = 'sound/weapons/gunshot_pathetic.ogg' + lethal_icon_color = "orange" + lethal_projectile = /obj/item/projectile/energy/phase/heavy shot_delay = 1 SECOND - if(/obj/item/weapon/gun/energy/retro) - iconholder = 1 - -// if(/obj/item/weapon/gun/energy/retro/sc_retro) -// iconholder = 1 - - if(/obj/item/weapon/gun/energy/captain) - iconholder = 1 - - if(/obj/item/weapon/gun/energy/lasercannon) - iconholder = 1 - - if(/obj/item/weapon/gun/energy/taser) - eprojectile = /obj/item/projectile/beam - eshot_sound = 'sound/weapons/Laser.ogg' - - if(/obj/item/weapon/gun/energy/stunrevolver) - eprojectile = /obj/item/projectile/beam - eshot_sound = 'sound/weapons/Laser.ogg' - if(/obj/item/weapon/gun/energy/gun) - eprojectile = /obj/item/projectile/beam //If it has, going to kill mode - eshot_sound = 'sound/weapons/Laser.ogg' - egun = 1 + lethal_icon_color = "red" + lethal_projectile = /obj/item/projectile/beam //If it has, going to kill mode + lethal_shot_sound = 'sound/weapons/Laser.ogg' if(/obj/item/weapon/gun/energy/gun/nuclear) - eprojectile = /obj/item/projectile/beam //If it has, going to kill mode - eshot_sound = 'sound/weapons/Laser.ogg' - egun = 1 + lethal_icon_color = "red" + lethal_projectile = /obj/item/projectile/beam //If it has, going to kill mode + lethal_shot_sound = 'sound/weapons/Laser.ogg' if(/obj/item/weapon/gun/energy/xray) - eprojectile = /obj/item/projectile/beam/xray + lethal_icon_color = "green" + lethal_projectile = /obj/item/projectile/beam/xray projectile = /obj/item/projectile/beam/stun // Otherwise we fire xrays on both modes. - eshot_sound = 'sound/weapons/eluger.ogg' + lethal_shot_sound = 'sound/weapons/eluger.ogg' shot_sound = 'sound/weapons/Taser.ogg' - iconholder = 1 - icon_color = "green" /obj/machinery/porta_turret/proc/isLocked(mob/user) if(ailock && issilicon(user)) @@ -486,20 +539,20 @@ "You begin [anchored ? "un" : ""]securing the turret." \ ) - wrenching = 1 + wrenching = TRUE if(do_after(user, 50 * I.toolspeed)) //This code handles moving the turret around. After all, it's a portable turret! if(!anchored) playsound(loc, I.usesound, 100, 1) - anchored = 1 + anchored = TRUE update_icon() to_chat(user, "You secure the exterior bolts on the turret.") else if(anchored) playsound(loc, I.usesound, 100, 1) - anchored = 0 + anchored = FALSE to_chat(user, "You unsecure the exterior bolts on the turret.") update_icon() - wrenching = 0 + wrenching = FALSE else if(istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda)) //Behavior lock/unlock mangement @@ -540,15 +593,14 @@ //the turret shoot much, much faster. to_chat(user, "You short out [src]'s threat assessment circuits.") visible_message("[src] hums oddly...") - emagged = 1 - iconholder = 1 - controllock = 1 - enabled = 0 //turns off the turret temporarily + emagged = TRUE + controllock = TRUE + enabled = FALSE //turns off the turret temporarily sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit - enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here + enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here return 1 -/obj/machinery/porta_turret/proc/take_damage(var/force) +/obj/machinery/porta_turret/take_damage(var/force) if(!raised && !raising) force = force / 8 if(force < 5) @@ -571,7 +623,7 @@ attacked = 1 spawn() sleep(60) - attacked = 0 + attacked = FALSE ..() @@ -587,12 +639,12 @@ check_access = prob(20) // check_access is a pretty big deal, so it's least likely to get turned on check_anomalies = prob(50) if(prob(5)) - emagged = 1 + emagged = TRUE enabled=0 spawn(rand(60,600)) if(!enabled) - enabled=1 + enabled = TRUE ..() @@ -677,7 +729,7 @@ if(faction && L.faction == faction) return TURRET_NOT_TARGET - if(!emagged && issilicon(L) && check_all == 0) // Don't target silica, unless told to neutralize everything. + if(!emagged && issilicon(L) && check_all == FALSE) // Don't target silica, unless told to neutralize everything. return TURRET_NOT_TARGET if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really @@ -703,7 +755,7 @@ if(iscuffed(L)) // If the target is handcuffed, leave it alone return TURRET_NOT_TARGET - if(isanimal(L) || issmall(L)) // Animals are not so dangerous + if(isanimal(L)) // Animals are not so dangerous return check_anomalies ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET if(isxenomorph(L) || isalien(L)) // Xenos are dangerous @@ -750,7 +802,7 @@ var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc) flick_holder.layer = layer + 0.1 - flick(raising_state, flick_holder) + flick("popup_[turret_type]", flick_holder) sleep(10) qdel(flick_holder) @@ -771,7 +823,7 @@ var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc) flick_holder.layer = layer + 0.1 - flick(lowering_state, flick_holder) + flick("popdown_[turret_type]", flick_holder) sleep(10) qdel(flick_holder) @@ -802,10 +854,10 @@ if(!(emagged || attacked)) //if it hasn't been emagged or attacked, it has to obey a cooldown rate if(last_fired || !raised) //prevents rapid-fire shooting, unless it's been emagged return - last_fired = 1 + last_fired = TRUE spawn() sleep(shot_delay) - last_fired = 0 + last_fired = FALSE var/turf/T = get_turf(src) var/turf/U = get_turf(target) @@ -818,8 +870,8 @@ update_icon() var/obj/item/projectile/A if(emagged || lethal) - A = new eprojectile(loc) - playsound(loc, eshot_sound, 75, 1) + A = new lethal_projectile(loc) + playsound(loc, lethal_shot_sound, 75, 1) else A = new projectile(loc) playsound(loc, shot_sound, 75, 1) @@ -862,7 +914,6 @@ return enabled = TC.enabled lethal = TC.lethal - iconholder = TC.lethal check_synth = TC.check_synth check_access = TC.check_access @@ -898,7 +949,7 @@ if(I.is_wrench() && !anchored) playsound(loc, I.usesound, 100, 1) to_chat(user, "You secure the external bolts.") - anchored = 1 + anchored = TRUE build_step = 1 return @@ -923,7 +974,7 @@ else if(I.is_wrench()) playsound(loc, I.usesound, 75, 1) to_chat(user, "You unfasten the external bolts.") - anchored = 0 + anchored = FALSE build_step = 0 return diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 43911b54d8..663230b11f 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -1153,7 +1153,7 @@ /obj/item/toy/plushie/tabby_cat = 50) /obj/machinery/vending/fishing - name = "loot trawler" + name = "Loot Trawler" desc = "A special vendor for fishing equipment." product_ads = "Tired of trawling across the ocean floor? Get our loot!;Chum and rods.;Don't get baited into fishing without us!;Baby is your star-sign pisces? We'd make a perfect match.;Do not fear, plenty to catch around here.;Don't get reeled in helplessly, get your own rod today!" icon_state = "fishvendor" diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index a3532a1b32..b58956579a 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -2,7 +2,7 @@ force = 30 var/melee_cooldown = 10 var/melee_can_hit = 1 - var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall, /obj/structure/girder) + //var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall, /obj/structure/girder) internal_damage_threshold = 50 maint_access = 0 //add_req_access = 0 @@ -26,14 +26,15 @@ return */ -/obj/mecha/combat/melee_action(target as obj|mob|turf) +/obj/mecha/combat/melee_action(atom/T) if(internal_damage&MECHA_INT_CONTROL_LOST) - target = safepick(oview(1,src)) - if(!melee_can_hit || !istype(target, /atom)) return - if(istype(target, /mob/living)) - var/mob/living/M = target + T = safepick(oview(1,src)) + if(!melee_can_hit) + return + if(istype(T, /mob/living)) + var/mob/living/M = T if(src.occupant.a_intent == I_HURT || istype(src.occupant, /mob/living/carbon/brain)) //Brains cannot change intents; Exo-piloting brains lack any form of physical feedback for control, limiting the ability to 'play nice'. - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) + playsound(src, 'sound/weapons/heavysmash.ogg', 50, 1) if(damtype == "brute") step_away(M,src,15) /* @@ -44,8 +45,8 @@ melee_can_hit = 1 return */ - if(istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target + if(ishuman(T)) + var/mob/living/carbon/human/H = T // if (M.health <= 0) return var/obj/item/organ/external/temp = H.get_organ(pick(BP_TORSO, BP_TORSO, BP_TORSO, BP_HEAD)) @@ -86,12 +87,12 @@ else return M.updatehealth() - src.occupant_message("You hit [target].") - src.visible_message("[src.name] hits [target].") + src.occupant_message("You hit [T].") + src.visible_message("[src.name] hits [T].") else step_away(M,src) - src.occupant_message("You push [target] out of the way.") - src.visible_message("[src] pushes [target] out of the way.") + src.occupant_message("You push [T] out of the way.") + src.visible_message("[src] pushes [T] out of the way.") melee_can_hit = 0 if(do_after(melee_cooldown)) @@ -99,27 +100,23 @@ return else - if(damtype == "brute") - for(var/target_type in src.destroyable_obj) - if(istype(target, target_type) && hascall(target, "attackby")) - src.occupant_message("You hit [target].") - src.visible_message("[src.name] hits [target]") - if(!istype(target, /turf/simulated/wall) && !istype(target, /obj/structure/girder)) - target:attackby(src,src.occupant) - else if(prob(5)) - target:dismantle_wall(1) - src.occupant_message("You smash through the wall.") - src.visible_message("[src.name] smashes through the wall") - playsound(src, 'sound/weapons/smash.ogg', 50, 1) - else if(istype(target, /turf/simulated/wall)) - target:take_damage(force) - else if(istype(target, /obj/structure/girder)) - target:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without. - melee_can_hit = 0 + if(istype(T, /obj/machinery/disposal)) // Stops mechs from climbing into disposals + return + if(src.occupant.a_intent == I_HURT || istype(src.occupant, /mob/living/carbon/brain)) // Don't smash unless we mean it + if(damtype == "brute") + src.occupant_message("You hit [T].") + src.visible_message("[src.name] hits [T]") + playsound(src, 'sound/weapons/heavysmash.ogg', 50, 1) - if(do_after(melee_cooldown)) - melee_can_hit = 1 - break + if(istype(T, /obj/structure/girder)) + T:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without. + else + T:take_damage(force) + + melee_can_hit = 0 + + if(do_after(melee_cooldown)) + melee_can_hit = 1 return /* diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index e2ce2d3638..ee42467121 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -166,14 +166,7 @@ if(ore_box) for(var/obj/item/weapon/ore/ore in range(chassis,1)) if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - log_message("Drilled through [target]") - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) + ore.forceMove(ore_box) else if(target.loc == C) log_message("Drilled through [target]") target.ex_act(2) @@ -219,7 +212,7 @@ if(ore_box) for(var/obj/item/weapon/ore/ore in range(chassis,1)) if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) + ore.forceMove(ore_box) else if(target.loc == C) log_message("Drilled through [target]") target.ex_act(2) @@ -267,13 +260,7 @@ if(ore_box) for(var/obj/item/weapon/ore/ore in range(chassis,1)) if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) - if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) - var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo - if(ore_box) - for(var/obj/item/weapon/ore/ore in range(chassis,1)) - if(get_dir(chassis,ore)&chassis.dir) - ore.Move(ore_box) + ore.forceMove(ore_box) else if(target.loc == C) log_message("Drilled through [target]") target.ex_act(2) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index b556286292..5b783c8e50 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -535,7 +535,7 @@ //////// Health related procs //////// //////////////////////////////////////// -/obj/mecha/proc/take_damage(amount, type="brute") +/obj/mecha/take_damage(amount, type="brute") if(amount) var/damage = absorbDamage(amount,type) health -= damage diff --git a/code/game/mecha/micro/micro_equipment.dm b/code/game/mecha/micro/micro_equipment.dm index b8e4557b47..d36f9fa0a3 100644 --- a/code/game/mecha/micro/micro_equipment.dm +++ b/code/game/mecha/micro/micro_equipment.dm @@ -146,7 +146,7 @@ occupant_message("The ore compartment is full.") return 1 else - ore.Move(ore_box) + ore.forceMove(ore_box) else if(target.loc == C) log_message("Drilled through [target]") target.ex_act(2) diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm index 44963c31d2..0de8d332b7 100644 --- a/code/game/objects/effects/alien/aliens.dm +++ b/code/game/objects/effects/alien/aliens.dm @@ -64,6 +64,19 @@ healthcheck() return +/obj/effect/alien/resin/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + user.do_attack_animation(src) + health -= damage + healthcheck() + return + +/obj/effect/alien/resin/take_damage(var/damage) + health -= damage + healthcheck() + return + /obj/effect/alien/resin/ex_act(severity) switch(severity) if(1.0) @@ -246,6 +259,18 @@ Alien plants should do something if theres a lot of poison health -= damage healthcheck() +/obj/effect/alien/weeds/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + user.do_attack_animation(src) + health -= damage + healthcheck() + return + +/obj/effect/alien/weeds/take_damage(var/damage) + health -= damage + healthcheck() + return + /obj/effect/alien/weeds/proc/healthcheck() if(health <= 0) qdel(src) @@ -401,6 +426,18 @@ Alien plants should do something if theres a lot of poison healthcheck() return +/obj/effect/alien/egg/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + user.do_attack_animation(src) + health -= damage + healthcheck() + return + +/obj/effect/alien/egg/take_damage(var/damage) + health -= damage + healthcheck() + return + /obj/effect/alien/egg/attackby(var/obj/item/weapon/W, var/mob/user) if(health <= 0) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 93c70930d1..7c441e8169 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -202,4 +202,12 @@ name = "roofing" singular_name = "roofing" desc = "A section of roofing material. You can use it to repair the ceiling, or expand it." - icon_state = "techtile_grid" \ No newline at end of file + icon_state = "techtile_grid" + +/obj/item/stack/tile/roofing/cyborg + name = "roofing synthesizer" + desc = "A device that makes roofing tiles." + uses_charge = 1 + charge_costs = list(250) + stacktype = /obj/item/stack/tile/roofing + build_type = /obj/item/stack/tile/roofing \ No newline at end of file diff --git a/code/game/objects/mob_spawner_vr.dm b/code/game/objects/mob_spawner_vr.dm index 0422c408f8..23ec38c907 100644 --- a/code/game/objects/mob_spawner_vr.dm +++ b/code/game/objects/mob_spawner_vr.dm @@ -84,7 +84,7 @@ if(destructible) take_damage(Proj.get_structure_damage()) -/obj/structure/mob_spawner/proc/take_damage(var/damage) +/obj/structure/mob_spawner/take_damage(var/damage) health -= damage if(health <= 0) visible_message("\The [src] breaks apart!") diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 68b9ccc787..20fd025ea9 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -98,7 +98,7 @@ return 0 return 1 -/obj/structure/catwalk/proc/take_damage(amount) +/obj/structure/catwalk/take_damage(amount) health -= amount if(health <= 0) visible_message("\The [src] breaks down!") diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 4234c99391..95d38c4473 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -468,3 +468,10 @@ if(istype(src.loc, /obj/structure/closet)) return (loc.return_air_for_internal_lifeform(L)) return return_air() + +/obj/structure/closet/take_damage(var/damage) + if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD) + return + dump_contents() + spawn(1) qdel(src) + return 1 \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 8380c059ec..da686ad455 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -11,6 +11,8 @@ starts_with = list( /obj/item/clothing/accessory/storage/brown_vest, /obj/item/blueprints, + ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless, + ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless, /obj/item/clothing/under/rank/chief_engineer, /obj/item/clothing/under/rank/chief_engineer/skirt, /obj/item/clothing/head/hardhat/white, @@ -125,6 +127,7 @@ /obj/item/clothing/suit/fire/firefighter, /obj/item/device/flashlight, /obj/item/weapon/extinguisher, + ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless, /obj/item/device/radio/headset/headset_eng, /obj/item/device/radio/headset/headset_eng/alt, /obj/item/clothing/suit/storage/hazardvest, diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index a24f2868da..072dd43de6 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -212,7 +212,7 @@ else return ..() -/obj/structure/girder/proc/take_damage(var/damage) +/obj/structure/girder/take_damage(var/damage) health -= damage if(health <= 0) dismantle() diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index c4b91fc73a..1057a5094c 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -281,3 +281,8 @@ return TRUE return FALSE +/obj/structure/grille/take_damage(var/damage) + health -= damage + spawn(1) healthcheck() + return 1 + diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 2192b5690c..f5bebdf529 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -137,6 +137,13 @@ user.visible_message("[user] [attack_verb] at [src]!") return 1 +/obj/structure/inflatable/take_damage(var/damage) + health -= damage + if(health <= 0) + visible_message("The [src] deflates!") + spawn(1) puncture() + return 1 + /obj/item/inflatable/door/ name = "inflatable door" desc = "A folded membrane which rapidly expands into a simple door on activation." diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index 9d96f0cc25..8027b5db5e 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -52,7 +52,7 @@ if(0.5 to 1.0) to_chat(user, "It has a few scrapes and dents.") -/obj/structure/railing/proc/take_damage(amount) +/obj/structure/railing/take_damage(amount) health -= amount if(health <= 0) visible_message("\The [src] breaks down!") diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm index 17619c3158..431ef0cdbb 100644 --- a/code/game/objects/structures/simple_doors.dm +++ b/code/game/objects/structures/simple_doors.dm @@ -124,15 +124,22 @@ icon_state = material.door_icon_base /obj/structure/simple_door/attackby(obj/item/weapon/W as obj, mob/user as mob) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(istype(W,/obj/item/weapon/pickaxe)) var/obj/item/weapon/pickaxe/digTool = W - user << "You start digging the [name]." + visible_message("[user] starts digging [src]!") if(do_after(user,digTool.digspeed*hardness) && src) - user << "You finished digging." + visible_message("[user] finished digging [src]!") Dismantle() else if(istype(W,/obj/item/weapon)) //not sure, can't not just weapons get passed to this proc? hardness -= W.force/10 - user << "You hit the [name] with your [W.name]!" + visible_message("[user] hits [src] with [W]!") + if(material == get_material_by_name("resin")) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD))) + playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1) + else + playsound(src, 'sound/weapons/smash.ogg', 50, 1) CheckHardness() else if(istype(W,/obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W @@ -146,12 +153,29 @@ hardness -= Proj.force/10 CheckHardness() +/obj/structure/simple_door/take_damage(var/damage) + hardness -= damage/10 + CheckHardness() + +/obj/structure/simple_door/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message("[user] [attack_verb] the [src]!") + if(material == get_material_by_name("resin")) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD))) + playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1) + else + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + user.do_attack_animation(src) + hardness -= damage/10 + CheckHardness() + /obj/structure/simple_door/proc/CheckHardness() if(hardness <= 0) Dismantle(1) /obj/structure/simple_door/proc/Dismantle(devastated = 0) material.place_dismantled_product(get_turf(src)) + visible_message("The [src] is destroyed!") qdel(src) /obj/structure/simple_door/ex_act(severity = 1) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index cc3bcf1648..b2867d5ead 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -47,7 +47,7 @@ else to_chat(user, "There is a thick layer of silicate covering it.") -/obj/structure/window/proc/take_damage(var/damage = 0, var/sound_effect = 1) +/obj/structure/window/take_damage(var/damage = 0, var/sound_effect = 1) var/initialhealth = health if(silicate) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index cb1a0f631a..1847767083 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -153,7 +153,7 @@ visible_message("\The [src] spontaneously combusts!.") //!!OH SHIT!! return -/turf/simulated/wall/proc/take_damage(dam) +/turf/simulated/wall/take_damage(dam) if(dam) damage = max(0, damage + dam) update_damage() diff --git a/code/game/turfs/simulated_vr.dm b/code/game/turfs/simulated_vr.dm new file mode 100644 index 0000000000..6c7325305f --- /dev/null +++ b/code/game/turfs/simulated_vr.dm @@ -0,0 +1,5 @@ +/turf/simulated + can_start_dirty = FALSE // We have enough premapped dirt where needed + +/turf/simulated/floor/plating + can_start_dirty = TRUE // But let maints and decrepit areas have some randomness \ No newline at end of file diff --git a/code/modules/admin/verbs/adminhelp_vr.dm b/code/modules/admin/verbs/adminhelp_vr.dm index 9f3aee4a83..8d27022ae4 100644 --- a/code/modules/admin/verbs/adminhelp_vr.dm +++ b/code/modules/admin/verbs/adminhelp_vr.dm @@ -1,8 +1,8 @@ -/datum/admin_help/proc/send2adminchat() +/datum/admin_help/proc/send2adminchat() if(!config.chat_webhook_url) return - var/list/adm = get_admin_counts() + var/list/adm = get_admin_counts() var/list/afkmins = adm["afk"] var/list/allmins = adm["total"] @@ -14,3 +14,23 @@ query_string += "&admin_number=[allmins.len]" query_string += "&admin_number_afk=[afkmins.len]" world.Export("[config.chat_webhook_url]?[query_string]") + +/client/verb/adminspice() + set category = "Admin" + set name = "Request Spice" + + //handle muting and automuting + if(prefs.muted & MUTE_ADMINHELP) + to_chat(usr, "Error: You cannot request spice (muted from adminhelps).") + return + + if(alert(usr, "Are you sure you want to request the admins spice things up for you? You accept the consequences if you do.",,"No","Yes") != "No") + message_admins("[ADMIN_FULLMONTY(usr)] has requested the round be spiced up a little.") + else + to_chat(usr, "Spice request cancelled.") + return + + //if they requested spice, then remove spice verb temporarily to prevent spamming + usr.verbs -= /client/verb/adminspice + spawn(6000) + usr.verbs += /client/verb/adminspice // 10 minute cool-down for spice request diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm index c9ab387753..877c684b5e 100644 --- a/code/modules/blob/blob.dm +++ b/code/modules/blob/blob.dm @@ -40,7 +40,7 @@ else icon_state = "blob_damaged" -/obj/effect/blob/proc/take_damage(var/damage) +/obj/effect/blob/take_damage(var/damage) // VOREStation Edit health -= damage if(health < 0) playsound(loc, 'sound/effects/splat.ogg', 50, 1) diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 3cb84bcb81..1802d2c009 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -495,3 +495,11 @@ datum/gear/suit/duster display_name = "snowsuit, supply" path = /obj/item/clothing/suit/storage/snowsuit/cargo allowed_roles = list("Quartermaster","Shaft Miner","Cargo Technician","Head of Personnel") + +/datum/gear/suit/miscellaneous/cardigan + display_name = "cardigan" + path = /obj/item/clothing/suit/storage/toggle/cardigan + +/datum/gear/suit/miscellaneous/cardigan/New() + ..() + gear_tweaks = list(gear_tweak_free_color_choice) \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm index d3e70872c9..7de598fc83 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -506,3 +506,14 @@ display_name = "plain ascetic garb" path = /obj/item/clothing/under/ascetic +/datum/gear/uniform/pleated + display_name = "pleated skirt" + path = /obj/item/clothing/under/skirt/pleated + +/datum/gear/uniform/pleated/New() + ..() + gear_tweaks = list(gear_tweak_free_color_choice) + +/datum/gear/uniform/lilacdress + display_name = "lilac dress" + path = /obj/item/clothing/under/dress/lilacdress diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 0f8b999b4c..91f441fa37 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -323,7 +323,7 @@ obj/item/clothing/suit/kamishimo item_state_slots = list(slot_r_hand_str = "leather_jacket", slot_l_hand_str = "leather_jacket") flags_inv = HIDEHOLSTER -obj/item/clothing/suit/storage/toggle/peacoat +/obj/item/clothing/suit/storage/toggle/peacoat name = "peacoat" desc = "A well-tailored, stylish peacoat." icon_state = "peacoat" @@ -338,6 +338,14 @@ obj/item/clothing/suit/storage/toggle/peacoat blood_overlay_type = "coat" allowed = list(/obj/item/weapon/tank/emergency/oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter) flags_inv = HIDEHOLSTER + +/obj/item/clothing/suit/storage/toggle/cardigan + name = "cardigan" + desc = "A cozy cardigan in a classic style." + icon_state = "cardigan" + addblends = "cardigan_a" + flags_inv = HIDEHOLSTER + /* * stripper */ diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm index 66636aac6f..d5991e4f10 100644 --- a/code/modules/clothing/under/accessories/clothing.dm +++ b/code/modules/clothing/under/accessories/clothing.dm @@ -349,6 +349,25 @@ desc = "A really cheesy holiday sweater, it actually kinda itches." icon_state = "turtleneck_winterred" +/obj/item/clothing/accessory/sweater/uglyxmas + name = "ugly Christmas sweater" + desc = "A gift that probably should've stayed in the back of the closet." + icon_state = "uglyxmas" + +/obj/item/clothing/accessory/sweater/flowersweater + name = "flowery sweater" + desc = "An oversized and flowery pink sweater." + icon_state = "flowersweater" + +/obj/item/clothing/accessory/sweater/redneck + name = "red turtleneck" + desc = "A comfortable turtleneck in a dark red." + icon_state = "turtleneck_red" + +//*** +// End of sweaters +//*** + /obj/item/clothing/accessory/cowledvest name = "cowled vest" desc = "A body warmer for the 26th century." diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 943577663f..c90d575b98 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -453,6 +453,10 @@ icon_state = "sari_green" item_state_slots = list(slot_r_hand_str = "dress_green", slot_l_hand_str = "dress_green") +/obj/item/clothing/under/dress/lilacdress + name = "lilac dress" + desc = "A simple black dress adorned in fake purple lilacs." + icon_state = "lilacdress" /* * wedding stuff diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index 4ac2ad5f2e..26a00a4a63 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -130,6 +130,12 @@ desc = "A piece of cloth wrapped around the waist." icon_state = "loincloth" +/obj/item/clothing/under/skirt/pleated + name = "pleated skirt" + desc = "A simple pleated skirt. It's like high school all over again." + icon_state = "pleated" + addblends = "pleated_a" + /obj/item/clothing/under/skirt/outfit name = "black skirt" desc = "A black skirt, very fancy!" diff --git a/code/modules/food/drinkingglass/metaglass.dm b/code/modules/food/drinkingglass/metaglass.dm index 0b64df0af9..1980c58873 100644 --- a/code/modules/food/drinkingglass/metaglass.dm +++ b/code/modules/food/drinkingglass/metaglass.dm @@ -312,7 +312,7 @@ Drinks Data glass_icon_state = "atomicbombglass" glass_center_of_mass = list("x"=15, "y"=7) -/datum/reagent/ethanol/b52 +/datum/reagent/ethanol/coffee/b52 glass_icon_state = "b52glass" /datum/reagent/ethanol/bahama_mama diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index c2c70985c5..871051a258 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -44,7 +44,7 @@ if(num < 1) to_chat(user, span("warning", "\The [src] is too full to add more metal.")) return - if(stack.use(num)) + if(stack.use(max(1, round(num)))) // We don't want to create stacks that aren't whole numbers to_chat(user, span("notice", "You add [num] sheet\s to \the [src].")) metal += num * metal_per_sheet interact(user) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index ff35a795b5..81557f597c 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -88,13 +88,13 @@ /mob/living/bot/attackby(var/obj/item/O, var/mob/user) if(O.GetID()) - if(access_scanner.allowed(user) && !open && !emagged) + if(access_scanner.allowed(user) && !open) locked = !locked to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]") attack_hand(user) - else if(emagged) - to_chat(user, "ERROR") + to_chat(user, "ERROR! SYSTEMS COMPROMISED!") + else if(open) to_chat(user, "Please close the access panel before locking it.") else @@ -111,7 +111,15 @@ else if(istype(O, /obj/item/weapon/weldingtool)) if(health < getMaxHealth()) if(open) - health = min(getMaxHealth(), health + 10) + if(getBruteLoss() < 10) + bruteloss = 0 + else + bruteloss = bruteloss - 10 + if(getFireLoss() < 10) + fireloss = 0 + else + fireloss = fireloss - 10 + updatehealth() user.visible_message("[user] repairs [src].","You repair [src].") playsound(src, O.usesound, 50, 1) else @@ -119,6 +127,13 @@ else to_chat(user, "[src] does not need a repair.") return + else if(istype(O, /obj/item/device/assembly/prox_sensor) && emagged) + if(open) + to_chat(user, "You repair the bot's systems.") + emagged = 0 + qdel(O) + else + to_chat(user, "Unable to repair with the maintenance panel closed.") else ..() diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 28de4d6d93..1f211fe95b 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -1,5 +1,6 @@ //Updates the mob's health from organs and mob damage variables /mob/living/carbon/human/updatehealth() + var/huskmodifier = 1.5 // With 1.5, you need 250 burn instead of 200 to husk a human. if(status_flags & GODMODE) health = getMaxHealth() @@ -17,7 +18,7 @@ health = getMaxHealth() - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute //TODO: fix husking - if( ((getMaxHealth() - total_burn) < config.health_threshold_dead) && stat == DEAD) + if( ((getMaxHealth() - total_burn) < config.health_threshold_dead * huskmodifier) && stat == DEAD) ChangeToHusk() return diff --git a/code/modules/mob/living/carbon/human/species/station/station_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_vr.dm index 92819aae65..aaa29f1286 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_vr.dm @@ -359,6 +359,7 @@ spawn_flags = SPECIES_CAN_JOIN icobase = 'icons/mob/human_races/r_seromi_vr.dmi' deform = 'icons/mob/human_races/r_seromi_vr.dmi' + icobase_tail = 1 color_mult = 1 min_age = 18 push_flags = ~HEAVY //Allows them to use micro step code. diff --git a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm index 9bf2c932ec..2398a032bb 100644 --- a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm +++ b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm @@ -59,6 +59,16 @@ autohiss_exempt = list("Siik")) excludes = list(/datum/trait/autohiss_unathi) +/datum/trait/autohiss_awootism + name = "Autohiss (Disability)" + desc = "You can't speak r's and l's properly." + cost = 0 + var_changes = list( + autohiss_basic_map = list( + "l" = list("w", "ww"), + "r" = list("w", "ww") + )) + /datum/trait/bloodsucker name = "Bloodsucker" desc = "Makes you unable to gain nutrition from anything but blood. To compenstate, you get fangs that can be used to drain blood from prey." diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm index 68308efc66..312d7f06db 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm @@ -42,6 +42,10 @@ flags |= NOBLUDGEON //No more attack messages files = new /datum/research/techonly(src) +/obj/item/device/dogborg/sleeper/Destroy() + go_out() + ..() + /obj/item/device/dogborg/sleeper/Exit(atom/movable/O) return 0 diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 080196f0aa..2959616130 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -153,6 +153,7 @@ /mob/living/silicon/robot/handle_regular_hud_updates() var/fullbright = FALSE + var/seemeson = FALSE if (src.stat == 2 || (XRAY in mutations) || (src.sight_mode & BORGXRAY)) src.sight |= SEE_TURFS src.sight |= SEE_MOBS @@ -170,6 +171,7 @@ src.see_in_dark = 8 see_invisible = SEE_INVISIBLE_MINIMUM fullbright = TRUE + seemeson = TRUE else if (src.sight_mode & BORGMATERIAL) src.sight |= SEE_OBJS src.see_in_dark = 8 @@ -194,6 +196,7 @@ src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness // has a "invisible" value of 15 plane_holder.set_vis(VIS_FULLBRIGHT,fullbright) + plane_holder.set_vis(VIS_MESONS,seemeson) ..() if (src.healths) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index b820451adf..17d659fb0b 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -470,6 +470,10 @@ var/global/list/robot_modules = list( S.synths = list(metal) src.modules += S + var/obj/item/stack/tile/roofing/cyborg/CT = new /obj/item/stack/tile/roofing/cyborg(src) + CT.synths = list(metal) + src.modules += CT + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) RG.synths = list(metal, glass) src.modules += RG diff --git a/code/modules/modular_computers/computers/modular_computer/damage.dm b/code/modules/modular_computers/computers/modular_computer/damage.dm index d63bf39fdf..9084bad735 100644 --- a/code/modules/modular_computers/computers/modular_computer/damage.dm +++ b/code/modules/modular_computers/computers/modular_computer/damage.dm @@ -16,7 +16,7 @@ H.take_damage(rand(10,30)) qdel() -/obj/item/modular_computer/proc/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1) +/obj/item/modular_computer/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1) if(randomize) // 75%-125%, rand() works with integers, apparently. amount *= (rand(75, 125) / 100.0) diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm index 90150bc547..fb73609d84 100644 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -81,7 +81,7 @@ to_chat(user, "It seems to be slightly damaged.") // Damages the component. Contains necessary checks. Negative damage "heals" the component. -/obj/item/weapon/computer_hardware/proc/take_damage(var/amount) +/obj/item/weapon/computer_hardware/take_damage(var/amount) damage += round(amount) // We want nice rounded numbers here. damage = between(0, damage, max_damage) // Clamp the value. diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index b0aadff2a2..579e7776b7 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -292,7 +292,7 @@ var/list/organ_cache = list() W.time_inflicted = world.time //Note: external organs have their own version of this proc -/obj/item/organ/proc/take_damage(amount, var/silent=0) +/obj/item/organ/take_damage(amount, var/silent=0) if(src.robotic >= ORGAN_ROBOT) src.damage = between(0, src.damage + (amount * 0.8), max_damage) else diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index af58edc78f..542fe3153d 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -389,6 +389,16 @@ var/global/list/light_type_cache = list() broken() return 1 +/obj/machinery/light/take_damage(var/damage) + if(!damage) + return + if(status == LIGHT_EMPTY||status == LIGHT_BROKEN) + return + if(!(status == LIGHT_OK||status == LIGHT_BURNED)) + return + broken() + return 1 + /obj/machinery/light/blob_act() broken() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e657876b7d..7d46fcd73f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -693,7 +693,7 @@ if (istype(in_chamber)) user.visible_message("[user] pulls the trigger.") play_fire_sound() - if(istype(in_chamber, /obj/item/projectile/beam/lastertag)) + if(istype(in_chamber, /obj/item/projectile/beam/lasertag)) user.show_message("You feel rather silly, trying to commit suicide with a toy.") mouthshoot = 0 return diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 266df1f358..eeb8d779d2 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -1,261 +1,261 @@ -/obj/item/weapon/gun/energy/laser - name = "laser rifle" - desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \ - switch between standard fire and a more efficent but weaker 'suppressive' fire." - icon_state = "laser" - item_state = "laser" - wielded_item_state = "laser-wielded" - fire_delay = 8 - slot_flags = SLOT_BELT|SLOT_BACK - w_class = ITEMSIZE_LARGE - force = 10 - origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) - matter = list(DEFAULT_WALL_MATERIAL = 2000) - projectile_type = /obj/item/projectile/beam/midlaser -// one_handed_penalty = 30 - - firemodes = list( - list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240), - list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60), - ) - -/obj/item/weapon/gun/energy/laser/mounted - self_recharge = 1 - use_external_power = 1 - one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry. - -/obj/item/weapon/gun/energy/laser/practice - name = "practice laser carbine" - desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice." - projectile_type = /obj/item/projectile/beam/practice - charge_cost = 48 - - cell_type = /obj/item/weapon/cell/device - - firemodes = list( - list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48), - list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12), - ) - -/obj/item/weapon/gun/energy/retro - name = "retro laser" - icon_state = "retro" - item_state = "retro" - desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." - slot_flags = SLOT_BELT - w_class = ITEMSIZE_NORMAL - projectile_type = /obj/item/projectile/beam - fire_delay = 10 //old technology - -/obj/item/weapon/gun/energy/retro/mounted - self_recharge = 1 - use_external_power = 1 - -/obj/item/weapon/gun/energy/retro/empty - icon_state = "retro" - cell_type = null - - -/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol - name = "Precursor Alpha Weapon - Appendageheld Laser" - desc = "This object strongly resembles a weapon, and if one were to pull the \ - trigger located on the handle of the object, it would fire a deadly \ - laser at whatever it was pointed at. The beam fired appears to cause too \ - much damage to whatever it would hit to have served as a long ranged repair tool, \ - therefore this object was most likely designed to be a deadly weapon. If so, this \ - has several implications towards its creators;\ -

\ - Firstly, it implies that these precursors, at some point during their development, \ - had needed to defend themselves, or otherwise had a need to utilize violence, and \ - as such created better tools to do so. It is unclear if violence was employed against \ - themselves as a form of in-fighting, or if violence was exclusive to outside species.\ -

\ - Secondly, the shape and design of the weapon implies that the creators of this \ - weapon were able to grasp objects, and be able to manipulate the trigger independently \ - from merely holding onto the weapon, making certain types of appendages like tentacles be \ - unlikely.\ -

\ - An interesting note about this weapon, when compared to contemporary energy weapons, is \ - that this gun appears to be inferior to modern laser weapons. The beam fired has less \ - of an ability to harm, and the power consumption appears to be higher than average for \ - a human-made energy side-arm. One possible explaination is that the creators of this \ - weapon, in their later years, had less of a need to optimize their capability for war, \ - and instead focused on other endeavors. Another explaination is that vast age of the weapon \ - may have caused it to degrade, yet still remain functional at a reduced capability." - value = CATALOGUER_REWARD_MEDIUM - -/obj/item/weapon/gun/energy/alien - name = "alien pistol" - desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages." - catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol) - icon_state = "alienpistol" - item_state = "alienpistol" - fire_sound = 'sound/weapons/eLuger.ogg' - fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose. - charge_cost = 480 // Five shots. - - projectile_type = /obj/item/projectile/beam/cyan - cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges. - origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7) - modifystate = "alienpistol" - - -/obj/item/weapon/gun/energy/captain - name = "antique laser gun" - icon_state = "caplaser" - item_state = "caplaser" - desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well." - force = 5 - slot_flags = SLOT_BELT - w_class = ITEMSIZE_NORMAL - projectile_type = /obj/item/projectile/beam - origin_tech = null - fire_delay = 10 //Old pistol - charge_cost = 480 //to compensate a bit for self-recharging - cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain - battery_lock = 1 - -/obj/item/weapon/gun/energy/lasercannon - name = "laser cannon" - desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \ - flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" - icon_state = "lasercannon" - item_state = null - origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) - slot_flags = SLOT_BELT|SLOT_BACK - projectile_type = /obj/item/projectile/beam/heavylaser/cannon - battery_lock = 1 - fire_delay = 20 - w_class = ITEMSIZE_LARGE -// one_handed_penalty = 90 // The thing's heavy and huge. - accuracy = 45 - charge_cost = 600 - -/obj/item/weapon/gun/energy/lasercannon/mounted - name = "mounted laser cannon" - self_recharge = 1 - use_external_power = 1 - recharge_time = 10 - accuracy = 0 // Mounted cannons are just fine the way they are. - one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry. - projectile_type = /obj/item/projectile/beam/heavylaser - charge_cost = 400 - fire_delay = 20 - -/obj/item/weapon/gun/energy/xray - name = "xray laser gun" - desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \ - standard photonic beams, resulting in an effective 'anti-armor' energy weapon." - icon_state = "xray" - item_state = "xray" - origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2) - projectile_type = /obj/item/projectile/beam/xray - charge_cost = 200 - -/obj/item/weapon/gun/energy/sniperrifle - name = "marksman energy rifle" - desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \ - ionized beams, this is a weapon to kill from a distance." - icon_state = "sniper" - item_state = "sniper" - item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder - origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4) - projectile_type = /obj/item/projectile/beam/sniper - slot_flags = SLOT_BACK - battery_lock = 1 - charge_cost = 600 - fire_delay = 35 - force = 10 - w_class = ITEMSIZE_HUGE // So it can't fit in a backpack. - accuracy = -45 //shooting at the hip - scoped_accuracy = 0 -// requires_two_hands = 1 -// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand. - -/obj/item/weapon/gun/energy/sniperrifle/verb/scope() - set category = "Object" - set name = "Use Scope" - set popup_menu = 1 - - toggle_scope(2.0) - -/obj/item/weapon/gun/energy/monorifle - name = "antique mono-rifle" - desc = "An old laser rifle. This one can only fire once before requiring recharging." - description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say." - icon_state = "eshotgun" - item_state = "shotgun" - origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3) - projectile_type = /obj/item/projectile/beam/sniper - slot_flags = SLOT_BACK - charge_cost = 1300 - fire_delay = 20 - force = 8 - w_class = ITEMSIZE_LARGE - accuracy = 10 - scoped_accuracy = 15 - var/scope_multiplier = 1.5 - -/obj/item/weapon/gun/energy/monorifle/verb/sights() - set category = "Object" - set name = "Aim Down Sights" - set popup_menu = 1 - - toggle_scope(scope_multiplier) - -/obj/item/weapon/gun/energy/monorifle/combat - name = "combat mono-rifle" - desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging." - description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design." - icon_state = "ecshotgun" - item_state = "cshotgun" - charge_cost = 1000 - force = 12 - accuracy = 0 - scoped_accuracy = 20 - -////////Laser Tag//////////////////// - -/obj/item/weapon/gun/energy/lasertag - name = "laser tag gun" - item_state = "laser" - desc = "Standard issue weapon of the Imperial Guard" - origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2) - matter = list(DEFAULT_WALL_MATERIAL = 2000) - projectile_type = /obj/item/projectile/beam/lastertag/blue - cell_type = /obj/item/weapon/cell/device/weapon/recharge - battery_lock = 1 - var/required_vest - -/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(!istype(M.wear_suit, required_vest)) - M << "You need to be wearing your laser tag vest!" - return 0 - return ..() - -/obj/item/weapon/gun/energy/lasertag/blue - icon_state = "bluetag" - item_state = "bluetag" - projectile_type = /obj/item/projectile/beam/lastertag/blue - required_vest = /obj/item/clothing/suit/bluetag - -/obj/item/weapon/gun/energy/lasertag/red - icon_state = "redtag" - item_state = "redtag" - projectile_type = /obj/item/projectile/beam/lastertag/red - required_vest = /obj/item/clothing/suit/redtag - -/* - * Laser scattergun, proof of concept. - */ - -/obj/item/weapon/gun/energy/lasershotgun - name = "laser scattergun" - icon = 'icons/obj/energygun.dmi' - item_state = "laser" - icon_state = "scatter" - desc = "A strange Almachi weapon, utilizing a refracting prism to turn a single laser blast into a diverging cluster." - origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 1, TECH_MATERIAL = 4) - - projectile_type = /obj/item/projectile/scatter/laser +/obj/item/weapon/gun/energy/laser + name = "laser rifle" + desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \ + switch between standard fire and a more efficent but weaker 'suppressive' fire." + icon_state = "laser" + item_state = "laser" + wielded_item_state = "laser-wielded" + fire_delay = 8 + slot_flags = SLOT_BELT|SLOT_BACK + w_class = ITEMSIZE_LARGE + force = 10 + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/midlaser +// one_handed_penalty = 30 + + firemodes = list( + list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240), + list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60), + ) + +/obj/item/weapon/gun/energy/laser/mounted + self_recharge = 1 + use_external_power = 1 + one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry. + +/obj/item/weapon/gun/energy/laser/practice + name = "practice laser carbine" + desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice." + projectile_type = /obj/item/projectile/beam/practice + charge_cost = 48 + + cell_type = /obj/item/weapon/cell/device + + firemodes = list( + list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48), + list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12), + ) + +/obj/item/weapon/gun/energy/retro + name = "retro laser" + icon_state = "retro" + item_state = "retro" + desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." + slot_flags = SLOT_BELT + w_class = ITEMSIZE_NORMAL + projectile_type = /obj/item/projectile/beam + fire_delay = 10 //old technology + +/obj/item/weapon/gun/energy/retro/mounted + self_recharge = 1 + use_external_power = 1 + +/obj/item/weapon/gun/energy/retro/empty + icon_state = "retro" + cell_type = null + + +/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol + name = "Precursor Alpha Weapon - Appendageheld Laser" + desc = "This object strongly resembles a weapon, and if one were to pull the \ + trigger located on the handle of the object, it would fire a deadly \ + laser at whatever it was pointed at. The beam fired appears to cause too \ + much damage to whatever it would hit to have served as a long ranged repair tool, \ + therefore this object was most likely designed to be a deadly weapon. If so, this \ + has several implications towards its creators;\ +

\ + Firstly, it implies that these precursors, at some point during their development, \ + had needed to defend themselves, or otherwise had a need to utilize violence, and \ + as such created better tools to do so. It is unclear if violence was employed against \ + themselves as a form of in-fighting, or if violence was exclusive to outside species.\ +

\ + Secondly, the shape and design of the weapon implies that the creators of this \ + weapon were able to grasp objects, and be able to manipulate the trigger independently \ + from merely holding onto the weapon, making certain types of appendages like tentacles be \ + unlikely.\ +

\ + An interesting note about this weapon, when compared to contemporary energy weapons, is \ + that this gun appears to be inferior to modern laser weapons. The beam fired has less \ + of an ability to harm, and the power consumption appears to be higher than average for \ + a human-made energy side-arm. One possible explaination is that the creators of this \ + weapon, in their later years, had less of a need to optimize their capability for war, \ + and instead focused on other endeavors. Another explaination is that vast age of the weapon \ + may have caused it to degrade, yet still remain functional at a reduced capability." + value = CATALOGUER_REWARD_MEDIUM + +/obj/item/weapon/gun/energy/alien + name = "alien pistol" + desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages." + catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol) + icon_state = "alienpistol" + item_state = "alienpistol" + fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose. + charge_cost = 480 // Five shots. + + projectile_type = /obj/item/projectile/beam/cyan + cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges. + origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7) + modifystate = "alienpistol" + + +/obj/item/weapon/gun/energy/captain + name = "antique laser gun" + icon_state = "caplaser" + item_state = "caplaser" + desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well." + force = 5 + slot_flags = SLOT_BELT + w_class = ITEMSIZE_NORMAL + projectile_type = /obj/item/projectile/beam + origin_tech = null + fire_delay = 10 //Old pistol + charge_cost = 480 //to compensate a bit for self-recharging + cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain + battery_lock = 1 + +/obj/item/weapon/gun/energy/lasercannon + name = "laser cannon" + desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \ + flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" + icon_state = "lasercannon" + item_state = null + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3) + slot_flags = SLOT_BELT|SLOT_BACK + projectile_type = /obj/item/projectile/beam/heavylaser/cannon + battery_lock = 1 + fire_delay = 20 + w_class = ITEMSIZE_LARGE +// one_handed_penalty = 90 // The thing's heavy and huge. + accuracy = 45 + charge_cost = 600 + +/obj/item/weapon/gun/energy/lasercannon/mounted + name = "mounted laser cannon" + self_recharge = 1 + use_external_power = 1 + recharge_time = 10 + accuracy = 0 // Mounted cannons are just fine the way they are. + one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry. + projectile_type = /obj/item/projectile/beam/heavylaser + charge_cost = 400 + fire_delay = 20 + +/obj/item/weapon/gun/energy/xray + name = "xray laser gun" + desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \ + standard photonic beams, resulting in an effective 'anti-armor' energy weapon." + icon_state = "xray" + item_state = "xray" + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2) + projectile_type = /obj/item/projectile/beam/xray + charge_cost = 200 + +/obj/item/weapon/gun/energy/sniperrifle + name = "marksman energy rifle" + desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \ + ionized beams, this is a weapon to kill from a distance." + icon_state = "sniper" + item_state = "sniper" + item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4) + projectile_type = /obj/item/projectile/beam/sniper + slot_flags = SLOT_BACK + battery_lock = 1 + charge_cost = 600 + fire_delay = 35 + force = 10 + w_class = ITEMSIZE_HUGE // So it can't fit in a backpack. + accuracy = -45 //shooting at the hip + scoped_accuracy = 0 +// requires_two_hands = 1 +// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand. + +/obj/item/weapon/gun/energy/sniperrifle/verb/scope() + set category = "Object" + set name = "Use Scope" + set popup_menu = 1 + + toggle_scope(2.0) + +/obj/item/weapon/gun/energy/monorifle + name = "antique mono-rifle" + desc = "An old laser rifle. This one can only fire once before requiring recharging." + description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say." + icon_state = "eshotgun" + item_state = "shotgun" + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3) + projectile_type = /obj/item/projectile/beam/sniper + slot_flags = SLOT_BACK + charge_cost = 1300 + fire_delay = 20 + force = 8 + w_class = ITEMSIZE_LARGE + accuracy = 10 + scoped_accuracy = 15 + var/scope_multiplier = 1.5 + +/obj/item/weapon/gun/energy/monorifle/verb/sights() + set category = "Object" + set name = "Aim Down Sights" + set popup_menu = 1 + + toggle_scope(scope_multiplier) + +/obj/item/weapon/gun/energy/monorifle/combat + name = "combat mono-rifle" + desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging." + description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design." + icon_state = "ecshotgun" + item_state = "cshotgun" + charge_cost = 1000 + force = 12 + accuracy = 0 + scoped_accuracy = 20 + +////////Laser Tag//////////////////// + +/obj/item/weapon/gun/energy/lasertag + name = "laser tag gun" + item_state = "laser" + desc = "Standard issue weapon of the Imperial Guard" + origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/lasertag/blue + cell_type = /obj/item/weapon/cell/device/weapon/recharge + battery_lock = 1 + var/required_vest + +/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M) + if(ishuman(M)) + if(!istype(M.wear_suit, required_vest)) + M << "You need to be wearing your laser tag vest!" + return 0 + return ..() + +/obj/item/weapon/gun/energy/lasertag/blue + icon_state = "bluetag" + item_state = "bluetag" + projectile_type = /obj/item/projectile/beam/lasertag/blue + required_vest = /obj/item/clothing/suit/bluetag + +/obj/item/weapon/gun/energy/lasertag/red + icon_state = "redtag" + item_state = "redtag" + projectile_type = /obj/item/projectile/beam/lasertag/red + required_vest = /obj/item/clothing/suit/redtag + +/obj/item/weapon/gun/energy/lasertag/omni + projectile_type = /obj/item/projectile/beam/lasertag/omni + +// Laser scattergun, proof of concept. + +/obj/item/weapon/gun/energy/lasershotgun + name = "laser scattergun" + icon = 'icons/obj/energygun.dmi' + item_state = "laser" + icon_state = "scatter" + desc = "A strange Almachi weapon, utilizing a refracting prism to turn a single laser blast into a diverging cluster." + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 1, TECH_MATERIAL = 4) + + projectile_type = /obj/item/projectile/scatter/laser \ No newline at end of file diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index f1a1f28e6c..ec2670c61d 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -89,6 +89,7 @@ /obj/item/projectile/beam/cyan name = "cyan beam" icon_state = "cyan" + fire_sound = 'sound/weapons/eluger.ogg' damage = 40 light_color = "#00C6FF" @@ -125,62 +126,52 @@ tracer_type = /obj/effect/projectile/tracer/emitter impact_type = /obj/effect/projectile/impact/emitter -/obj/item/projectile/beam/lastertag/blue +/obj/item/projectile/beam/lasertag name = "lasertag beam" - icon_state = "bluelaser" damage = 0 + eyeblur = 0 no_attack_log = 1 damage_type = BURN check_armour = "laser" - light_color = "#0066FF" combustion = FALSE +/obj/item/projectile/beam/lasertag/blue + icon_state = "bluelaser" + light_color = "#0066FF" + muzzle_type = /obj/effect/projectile/muzzle/laser_blue tracer_type = /obj/effect/projectile/tracer/laser_blue impact_type = /obj/effect/projectile/impact/laser_blue -/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) +/obj/item/projectile/beam/lasertag/blue/on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) var/mob/living/carbon/human/M = target if(istype(M.wear_suit, /obj/item/clothing/suit/redtag)) M.Weaken(5) return 1 -/obj/item/projectile/beam/lastertag/red - name = "lasertag beam" +/obj/item/projectile/beam/lasertag/red icon_state = "laser" - damage = 0 - no_attack_log = 1 - damage_type = BURN - check_armour = "laser" light_color = "#FF0D00" - combustion = FALSE - -/obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) +/obj/item/projectile/beam/lasertag/red/on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) var/mob/living/carbon/human/M = target if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag)) M.Weaken(5) return 1 -/obj/item/projectile/beam/lastertag/omni//A laser tag bolt that stuns EVERYONE - name = "lasertag beam" +/obj/item/projectile/beam/lasertag/omni//A laser tag bolt that stuns EVERYONE icon_state = "omnilaser" - damage = 0 - damage_type = BURN - check_armour = "laser" light_color = "#00C6FF" - combustion = FALSE - muzzle_type = /obj/effect/projectile/muzzle/laser_omni tracer_type = /obj/effect/projectile/tracer/laser_omni impact_type = /obj/effect/projectile/impact/laser_omni -/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) +/obj/item/projectile/beam/lasertag/omni/on_hit(var/atom/target, var/blocked = 0) + if(ishuman(target)) var/mob/living/carbon/human/M = target if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag))) M.Weaken(5) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index d2b4dc149d..4ccd444d0e 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -158,7 +158,7 @@ message_admins("[key_name_admin(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).") log_game("[key_name(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]).") - if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) + if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) explode() /obj/structure/reagent_dispensers/fueltank/ex_act() diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm index 65eb6dc363..5b7d7f2118 100644 --- a/code/modules/shieldgen/energy_field.dm +++ b/code/modules/shieldgen/energy_field.dm @@ -60,6 +60,9 @@ user.do_attack_animation(src) user.setClickCooldown(user.get_attack_speed()) +/obj/effect/energy_field/take_damage(var/damage) + adjust_strength(-damage / 20) + /obj/effect/energy_field/attack_hand(var/mob/living/user) impact_effect(3) // Harmless, but still produces the 'impact' effect. ..() diff --git a/code/modules/surgery/external_repair.dm b/code/modules/surgery/external_repair.dm index b26d803b34..e54352f536 100644 --- a/code/modules/surgery/external_repair.dm +++ b/code/modules/surgery/external_repair.dm @@ -9,8 +9,10 @@ req_open = 1 /datum/surgery_step/repairflesh/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work. - return 0 +/* VOREStation Removal for Mlem Reasons(TM) + if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work. + return 0 +*/ if (isslime(target)) return 0 if (target_zone == O_EYES || target_zone == O_MOUTH) diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm index 06fca65138..5d568d440e 100644 --- a/code/modules/tables/presets.dm +++ b/code/modules/tables/presets.dm @@ -75,6 +75,15 @@ material = get_material_by_name("glass") ..() +/obj/structure/table/borosilicate + icon_state = "plain_preview" + color = "#4D3EAC" + alpha = 77 + +/obj/structure/table/borosilicate/New() + material = get_material_by_name("borosilicate glass") + ..() + /obj/structure/table/holotable icon_state = "holo_preview" color = "#EEEEEE" diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm index 514c3b2036..c5b7bde70e 100644 --- a/code/modules/tables/tables.dm +++ b/code/modules/tables/tables.dm @@ -44,7 +44,7 @@ var/list/table_icon_cache = list() health += maxhealth - old_maxhealth -/obj/structure/table/proc/take_damage(amount) +/obj/structure/table/take_damage(amount) // If the table is made of a brittle material, and is *not* reinforced with a non-brittle material, damage is multiplied by TABLE_BRITTLE_MATERIAL_MULTIPLIER if(material && material.is_brittle()) if(reinforced) diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index 606735f36f..87a1b72466 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -424,3 +424,12 @@ new /obj/effect/decal/cleanable/blood/oil(src.loc) spawn(1) healthcheck() return 1 + +/obj/vehicle/take_damage(var/damage) + if(!damage) + return + src.health -= damage + if(mechanical && prob(10)) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + spawn(1) healthcheck() + return 1 diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index fc1fe9d0ff..2dc626b801 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -1848,4 +1848,15 @@ Departamental Swimsuits, for general use icon_state = "goldenstring" item_state = "goldenstring" w_class = ITEMSIZE_TINY - slot_flags = SLOT_TIE \ No newline at end of file + slot_flags = SLOT_TIE + +//Chaoko99: Aika Hisakawa +/obj/item/clothing/suit/fluff/blue_trimmed_coat + name = "blue-trimmed greatcoat" + desc = "A heavy, form-obscuring coat with gilded buttons and azure trim." + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_state = "aika_coat" + + icon_override = 'icons/vore/custom_clothes_vr.dmi' + item_state = "aika_coat" + flags_inv = HIDEJUMPSUIT | HIDETIE \ No newline at end of file diff --git a/code/modules/xenoarcheaology/tools/coolant_tank.dm b/code/modules/xenoarcheaology/tools/coolant_tank.dm index df6c901517..9f5172b3de 100644 --- a/code/modules/xenoarcheaology/tools/coolant_tank.dm +++ b/code/modules/xenoarcheaology/tools/coolant_tank.dm @@ -11,7 +11,7 @@ /obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj) if(Proj.get_structure_damage()) - if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) // TODO: make this not terrible + if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) // TODO: make this not terrible explode() /obj/structure/reagent_dispensers/coolanttank/ex_act() diff --git a/config/custom_items.txt b/config/custom_items.txt index 9438ff8d22..a46362b3f9 100644 --- a/config/custom_items.txt +++ b/config/custom_items.txt @@ -974,3 +974,10 @@ ckey: zodiacshadow character_name: Nehi Maximus item_path: /obj/item/device/radio/headset/fluff/zodiacshadow } + +{ +ckey: chaoko99 +character_name: Aika Hisakawa +item_path: /obj/item/clothing/suit/fluff/blue_trimmed_coat +} + diff --git a/html/changelog.html b/html/changelog.html index fab075d8ed..31766527d1 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,47 @@ -->
+

27 July 2019

+

Atermonera updated:

+ +

Mechoid updated:

+ +

Nalarac updated:

+ +

Schnayy updated:

+ +

19 July 2019

Nalarac updated: