diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 3892de00acdf..fea25a714d73 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -248,6 +248,16 @@ time = 4 SECONDS category = CAT_ROBOT +/datum/crafting_recipe/Atmosbot + name = "Automatic Station Stabilizer Bot" + result = /mob/living/simple_animal/bot/atmosbot + reqs = list(/obj/item/analyzer = 1, + /obj/item/bodypart/r_arm/robot = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/grenade/chem_grenade/smart_metal_foam = 1) + time = 6 SECONDS + category = CAT_ROBOT + /datum/crafting_recipe/improvised_pneumatic_cannon //Pretty easy to obtain but name = "Pneumatic Cannon" result = /obj/item/pneumatic_cannon/ghetto diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index 6bd9e304cd8b..12315ff83940 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -476,3 +476,10 @@ /obj/effect/temp_visual/dir_setting/space_wind/Initialize(mapload, set_dir, set_alpha = 255) . = ..() alpha = set_alpha + +/obj/effect/temp_visual/vent_wind + icon = 'icons/effects/atmospherics.dmi' + icon_state = "vent_wind" + layer = FLY_LAYER + duration = 0.48 SECONDS + mouse_opacity = 0 diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 1c19a96cd32b..160f19d9606e 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -478,6 +478,15 @@ GENE SCANNER user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!") return BRUTELOSS +/obj/item/analyzer/attackby(obj/O, mob/living/user) + if(istype(O, /obj/item/bodypart/l_arm/robot) || istype(O, /obj/item/bodypart/r_arm/robot)) + to_chat(user, "You add [O] to [src].") + qdel(O) + qdel(src) + user.put_in_hands(new /obj/item/bot_assembly/atmosbot) + else + ..() + /obj/item/analyzer/attack_self(mob/user) add_fingerprint(user) scangasses(user) //yogs start: Makes the gas scanning able to be used elseware diff --git a/code/modules/mob/living/simple_animal/bot/atmosbot.dm b/code/modules/mob/living/simple_animal/bot/atmosbot.dm new file mode 100644 index 000000000000..868674d90709 --- /dev/null +++ b/code/modules/mob/living/simple_animal/bot/atmosbot.dm @@ -0,0 +1,219 @@ +#define ATMOSBOT_MAX_AREA_SCAN 100 +#define ATMOSBOT_HOLOBARRIER_COOLDOWN 150 + +#define ATMOSBOT_CHECK_BREACH 0 +#define ATMOSBOT_LOW_OXYGEN 1 +#define ATMOSBOT_AREA_STABLE 4 + +#define ATMOSBOT_NOTHING 0 +#define ATMOSBOT_DEPLOY_FOAM 1 +#define ATMOSBOT_SPRAY_MIASMA 5 + +//Floorbot +/mob/living/simple_animal/bot/atmosbot + name = "\improper Automatic Station Stabilizer Bot" + desc = "Or the A.S.S. Bot for short." + icon = 'icons/mob/aibots.dmi' + icon_state = "atmosbot0" + density = FALSE + anchored = FALSE + health = 25 + maxHealth = 25 + spacewalk = TRUE + + radio_key = /obj/item/encryptionkey/headset_eng + radio_channel = RADIO_CHANNEL_ENGINEERING + bot_type = FLOOR_BOT + model = "Floorbot" + bot_core = /obj/machinery/bot_core/floorbot + window_id = "autofloor" + window_name = "Automatic Station Atmospherics Restabilizer v1.1" + path_image_color = "#FFA500" + + auto_patrol = TRUE + + var/action + var/turf/target + //The pressure at which the bot scans for breaches + var/breached_pressure = 20 + //Weakref of deployed barrier + var/datum/weakref/deployed_smartmetal + //Deployment time of last barrier + var/last_barrier_tick + //Gasses + + +/mob/living/simple_animal/bot/atmosbot/Initialize(mapload, new_toolbox_color) + . = ..() + var/datum/job/engineer/J = new/datum/job/engineer + access_card.access += J.get_access() + prev_access = access_card.access + +/mob/living/simple_animal/bot/atmosbot/turn_on() + . = ..() + update_icon() + +/mob/living/simple_animal/bot/atmosbot/turn_off() + . = ..() + update_icon() + +/mob/living/simple_animal/bot/atmosbot/set_custom_texts() + text_hack = "You corrupt [name]'s safety protocols." + text_dehack = "You detect errors in [name] and reset his programming." + text_dehack_fail = "[name] is not responding to reset commands!" + +/mob/living/simple_animal/bot/atmosbot/emag_act(mob/user) + . = ..() + if(emagged == 2) + audible_message("[src] ominously whirs....") + playsound(src, "sparks", 75, TRUE) + +/mob/living/simple_animal/bot/atmosbot/handle_automated_action() + if(!..()) + return + + if(prob(5)) + audible_message("[src] makes an excited whirring sound!") + + action = ATMOSBOT_NOTHING + if(!isspaceturf(get_turf(src))) + switch(check_area_atmos()) + if(ATMOSBOT_CHECK_BREACH) + if(last_barrier_tick + ATMOSBOT_HOLOBARRIER_COOLDOWN < world.time) + target = return_nearest_breach() + action = ATMOSBOT_DEPLOY_FOAM + update_icon() + + if(!target) + if(auto_patrol) + if(mode == BOT_IDLE || mode == BOT_START_PATROL) + start_patrol() + + if(mode == BOT_PATROL) + bot_patrol() + + if(target) + if(loc == get_turf(target)) + if(check_bot(target)) + if(prob(50)) + target = null + path = list() + return + //Do foam here + deploy_smartmetal() + + + if(!LAZYLEN(path)) + var/turf/target_turf = get_turf(target) + path = get_path_to(src, target_turf, /turf/proc/Distance_cardinal, 0, 30, id=access_card, simulated_only = FALSE) + + if(!bot_move(target)) + add_to_ignore(target) + target = null + mode = BOT_IDLE + return + + else if(!bot_move(target)) + target = null + mode = BOT_IDLE + return + + +/mob/living/simple_animal/bot/atmosbot/proc/deploy_smartmetal() + if(emagged == 2) + explosion(src.loc,1,2,4,flame_range = 2) + qdel(src) + else + deployed_smartmetal = WEAKREF(new /obj/effect/particle_effect/foam/metal/smart(get_turf(src))) + qdel(src) + return + +//Analyse the atmosphere to see if there is a potential breach nearby +/mob/living/simple_animal/bot/atmosbot/proc/check_area_atmos() + var/turf/T = get_turf(src) + var/datum/gas_mixture/gas_mix = T.return_air() + if(gas_mix.return_pressure() < breached_pressure) + return ATMOSBOT_CHECK_BREACH + //Too little oxygen or too little pressure + var/partial_pressure = R_IDEAL_GAS_EQUATION * gas_mix.return_temperature() / gas_mix.return_volume() + var/oxygen_moles = gas_mix.get_moles(/datum/gas/oxygen) * partial_pressure + if(oxygen_moles < 20 || gas_mix.return_pressure() < WARNING_LOW_PRESSURE) + return ATMOSBOT_LOW_OXYGEN + +//Returns the closest turf that needs a holoprojection set up +/mob/living/simple_animal/bot/atmosbot/proc/return_nearest_breach() + var/turf/origin = get_turf(src) + + if(origin.blocks_air) + return null + + var/room_limit = ATMOSBOT_MAX_AREA_SCAN + var/list/checked_turfs = list() + var/list/to_check_turfs = list(origin) + while(room_limit > 0 && LAZYLEN(to_check_turfs)) + room_limit -- + var/turf/checking_turf = to_check_turfs[1] + //We have checked this turf + checked_turfs += checking_turf + to_check_turfs -= checking_turf + var/blocked = FALSE + for(var/obj/structure/holosign/barrier/atmos/A in checking_turf) + blocked = TRUE + break + if(blocked || !checking_turf.CanAtmosPass(checking_turf)) + continue + //Add adjacent turfs + for(var/direction in list(NORTH, SOUTH, EAST, WEST)) + var/turf/adjacent_turf = get_step(checking_turf, direction) + if(adjacent_turf in checked_turfs || !adjacent_turf.CanAtmosPass(adjacent_turf) || istype(adjacent_turf.loc, /area/space)) + continue + if(isspaceturf(adjacent_turf)) + return checking_turf + to_check_turfs |= adjacent_turf + return null + +/mob/living/simple_animal/bot/atmosbot/get_controls(mob/user) + var/dat + dat += hack(user) + dat += showpai(user) + dat += "Atmospheric Stabalizer Controls v1.1

" + dat += "Status: [on ? "On" : "Off"]
" + dat += "Maintenance panel panel is [open ? "opened" : "closed"]
" + if(!locked || issilicon(user) || IsAdminGhost(user)) + dat += "Breach Pressure: [breached_pressure]
" + dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
" + return dat + +/mob/living/simple_animal/bot/atmosbot/Topic(href, href_list) + if(..()) + return TRUE + + if(href_list["set_breach_pressure"]) + var/new_breach_pressure = input(usr, "Pressure to scan for breaches at? (0 to 100)", "Breach Pressure") as num + if(!isnum(new_breach_pressure) || new_breach_pressure < 0 || new_breach_pressure > 100) + return + breached_pressure = new_breach_pressure + update_controls() + update_icon() + +/mob/living/simple_animal/bot/atmosbot/update_icon() + icon_state = "atmosbot[on][on?"_[action]":""]" + +/mob/living/simple_animal/bot/atmosbot/UnarmedAttack(atom/A, proximity) + if(isturf(A) && A == get_turf(src)) + return deploy_smartmetal() + return ..() + +/mob/living/simple_animal/bot/atmosbot/explode() + on = FALSE + visible_message("[src] blows apart!") + + var/atom/Tsec = drop_location() + + new /obj/item/assembly/prox_sensor(Tsec) + new /obj/item/analyzer(Tsec) + if(prob(50)) + drop_part(robot_arm, Tsec) + + do_sparks(3, TRUE, src) + ..() diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 6e86183706c9..156d04178592 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -500,3 +500,33 @@ F.name = created_name qdel(I) qdel(src) + +//Atmosbot Assembly +/obj/item/bot_assembly/atmosbot + name = "incomplete atmosbot assembly" + desc = "An incomplete atmosbot with an analyser attached to it" + icon_state = "atmosbot_assembly" + created_name = "Atmosbot" + +/obj/item/bot_assembly/atmosbot/attackby(obj/item/I, mob/user, params) + ..() + switch(build_step) + if(ASSEMBLY_FIRST_STEP) + if(istype(I, /obj/item/grenade/chem_grenade/smart_metal_foam)) + if(!user.temporarilyRemoveItemFromInventory(I)) + return + to_chat(user,"You add the [I] to [src]!") + icon_state = "atmosbot_assembly_tank" + desc = "An incomplete atmosbot assembly with a tank strapped to it." + qdel(I) + build_step++ + + if(ASSEMBLY_SECOND_STEP) + if(isprox(I)) + if(!can_finish_build(I, user)) + return + to_chat(user, "You add the [I] to [src]! Beep Boop!") + var/mob/living/simple_animal/bot/atmosbot/A = new(drop_location()) + A.name = created_name + qdel(I) + qdel(src) diff --git a/icons/effects/atmospherics.dmi b/icons/effects/atmospherics.dmi index 5f6e056470db..77721a81ada8 100644 Binary files a/icons/effects/atmospherics.dmi and b/icons/effects/atmospherics.dmi differ diff --git a/icons/mob/aibots.dmi b/icons/mob/aibots.dmi index 844791a02a74..14054ebe40ce 100644 Binary files a/icons/mob/aibots.dmi and b/icons/mob/aibots.dmi differ diff --git a/yogstation.dme b/yogstation.dme index 4a40273aea56..1c4ea6713e37 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -2326,6 +2326,7 @@ #include "code\modules\mob\living\simple_animal\shade.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\status_procs.dm" +#include "code\modules\mob\living\simple_animal\bot\atmosbot.dm" #include "code\modules\mob\living\simple_animal\bot\bot.dm" #include "code\modules\mob\living\simple_animal\bot\cleanbot.dm" #include "code\modules\mob\living\simple_animal\bot\construction.dm"