diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index bc0dd8fc2b4..31b91c7cd1e 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -9,8 +9,9 @@ #define MIDROUND_ANTAG 64 #define SOUND_INSTRUMENTS 128 #define SOUND_SHIP_AMBIENCE 256 +#define SOUND_PRAYERS 512 -#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE) +#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS) //Chat toggles #define CHAT_OOC 1 diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 9945a13fcad..33b781ad4f8 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -76,12 +76,12 @@ // Used to get a properly sanitized input, of max_length /proc/stripped_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN) var/name = input(user, message, title, default) as text|null - return strip_html_properly(name, max_length) + return html_encode(trim(name, max_length)) //trim is "inside" because html_encode can expand single symbols into multiple symbols (such as turning < into <) // Used to get a properly sanitized multiline input, of max_length /proc/stripped_multiline_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN) var/name = input(user, message, title, default) as message|null - return strip_html_properly(name, max_length) + return html_encode(trim(name, max_length)) //Filters out undesirable characters from names /proc/reject_bad_name(var/t_in, var/allow_numbers=0, var/max_length=MAX_NAME_LEN) @@ -147,56 +147,7 @@ return t_out -//this proc strips html properly, this means that it removes everything between < and >, and between "http" and "://" -//also limit the size of the input, if specified to -/proc/strip_html_properly(var/input,var/max_length=MAX_MESSAGE_LEN) - if(!input) - return - - if(max_length) - input = copytext(input,1,max_length) - - var/sanitized_output - var/next_html_tag = findtext(input, "<") - var/next_http = findtext(input, "http", 1, next_html_tag) - - //the opening and closing of the expression to skip, e.g '<' and '>' - var/opening = non_zero_min(next_html_tag, next_http) - var/closing - - sanitized_output = copytext(input, 1, opening) - - while(next_html_tag || next_http) - - //we treat < ... > - if(opening == next_html_tag) - closing = findtext(input, ">", opening + 1) - if(closing) - next_html_tag = findtext(input, "<", closing) - next_http = findtext(input, "http", closing, next_html_tag) - else //no matching ">" - next_html_tag = 0 - - //we treat "http(s)://" - else - closing = findtext(input, "://", opening + 1) - if(closing) - closing += 2 //skip these extra // - next_http = findtext(input, "http", closing) - next_html_tag = findtext(input, "<", closing, next_http) - else //no matching "://" - next_http = 0 - - //check if we've something to skip - if(closing) - opening = non_zero_min(next_html_tag, next_http) - sanitized_output += copytext(input, closing + 1, opening) - - sanitized_output += copytext(input, opening) //don't forget the remaining text - - return sanitized_output - -//strip_html_properly helper proc that returns the smallest non null of two numbers +//html_encode helper proc that returns the smallest non null of two numbers //or 0 if they're both null (needed because of findtext returning 0 when a value is not present) /proc/non_zero_min(var/a, var/b) if(!a) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index adb3b60c80b..fb75fed9b60 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -987,25 +987,8 @@ Turf and target are seperate in case you want to teleport some distance from a t /proc/get_turf(atom/A) if (!istype(A)) return - if (isturf(A)) - return A - - var/list/atom/checked_turf_candidates = list() //prevent recursion from badmins being dumbasses - var/atom/turf_candidate = A.loc - - while (!isturf(turf_candidate)) - if (!turf_candidate || turf_candidate in checked_turf_candidates) - return - checked_turf_candidates += turf_candidate - - //SO I BET YOU MIGHT BE WONDERING WHY I'M CHECKING THIS AGAIN. - //I'LL FUCKING TELL YOU WAY, ITS BECAUSE FOR SOME GOD DAMN REASON, WHEN THIS IS CALLED - //IN AN OBJECT'S NEW() PROC, THE FIRST CHECK WILL FUCKING PASS, BUT FUCKING RUNTIME HERE - //BITCHING ABOUT HOW IT CAN'T READ NULL.LOC, SO FUCK IT, WE CHECK THIS TWICE. - if (!turf_candidate) - return - turf_candidate = turf_candidate.loc - return turf_candidate + for(A, A && !isturf(A), A=A.loc); //semicolon is for the empty statement + return A //Gets the turf this atom's *ICON* appears to inhabit diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index c250dc1d2d9..e442f74d14f 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -160,6 +160,8 @@ var/aggressive_changelog = 0 + var/reactionary_explosions = 0 //If we use reactionary explosions, explosions that react to walls and doors + /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode for(var/T in L) @@ -485,6 +487,8 @@ config.no_summon_magic = 1 if("no_summon_events") config.no_summon_events = 1 + if("reactionary_explosions") + config.reactionary_explosions = 1 else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 5cff548b620..838bcde4e26 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -9,6 +9,7 @@ var/global/datum/controller/game_controller/master_controller = new() var/processing_interval = 1 //The minimum length of time between MC ticks (in deciseconds). The highest this can be without affecting schedules, is the GCD of all subsystem var/wait. Set to 0 to disable all processing. var/iteration = 0 var/cost = 0 + var/SSCostPerSecond = 0 var/last_thing_processed var/list/subsystems = list() @@ -60,7 +61,8 @@ calculate the longest number of ticks the MC can wait between each cycle without for(var/datum/subsystem/S in subsystems) S.Initialize(world.timeofday, zlevel) sleep(-1) - + for(var/datum/subsystem/S in subsystems) + S.AfterInitialize(zlevel) world << "Initializations complete" world.log << "Initializations complete" @@ -89,10 +91,11 @@ calculate the longest number of ticks the MC can wait between each cycle without ++iteration start_time = world.timeofday - + var/SubSystemRan = 0 for(var/datum/subsystem/SS in subsystems) if(SS.can_fire > 0) if(SS.next_fire <= world.time) + SubSystemRan = 1 timer = world.timeofday last_thing_processed = SS.type SS.last_fire = world.time @@ -100,7 +103,9 @@ calculate the longest number of ticks the MC can wait between each cycle without SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer) if (SS.dynamic_wait) var/oldwait = SS.wait - SS.wait = min(max(round(SS.cost*SS.dwait_delta, 0.1),SS.dwait_lower),SS.dwait_upper) + var/GlobalCostDelta = (SSCostPerSecond-(SS.cost/SS.wait))/(SS.wait/10)-1 + var/NewWait = MC_AVERAGE(oldwait,(SS.cost-1.5+GlobalCostDelta)*SS.dwait_delta) + SS.wait = Clamp(round(NewWait,0.1),SS.dwait_lower,SS.dwait_upper) if (oldwait != SS.wait) calculateGCD() SS.next_fire += SS.wait @@ -109,11 +114,20 @@ calculate the longest number of ticks the MC can wait between each cycle without sleep(-1) cost = MC_AVERAGE(cost, world.timeofday - start_time) - + if (SubSystemRan) + calculateSScost() sleep(processing_interval) else sleep(50) +/datum/controller/game_controller/proc/calculateSScost() + var/newcost = 0 + for(var/datum/subsystem/SS in subsystems) + if (!SS.can_fire) + continue + newcost += SS.cost/(SS.wait/10) + SSCostPerSecond = MC_AVERAGE(SSCostPerSecond,newcost) + #undef MC_AVERAGE /datum/controller/game_controller/proc/roundHasStarted() diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 5c74da6d84d..969e2fa6d97 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -3,7 +3,6 @@ var/datum/subsystem/air/SSair /datum/subsystem/air name = "Air" priority = 20 - cost = 5 wait = 5 dynamic_wait = 1 dwait_lower = 5 @@ -56,10 +55,12 @@ var/datum/subsystem/air/SSair /datum/subsystem/air/Initialize(timeofday, zlevel) - setup_allturfs(zlevel) setup_atmos_machinery(zlevel) ..() +/datum/subsystem/air/AfterInitialize(zlevel) + setup_allturfs(zlevel) + #define MC_AVERAGE(average, current) (0.8*(average) + 0.2*(current)) /datum/subsystem/air/fire() var/timer = world.timeofday @@ -167,15 +168,14 @@ var/datum/subsystem/air/SSair EG.dismantle() /datum/subsystem/air/proc/setup_allturfs(z_level) + active_turfs.Cut() var/z_start = 1 var/z_finish = world.maxz if(1 <= z_level && z_level <= world.maxz) z_level = round(z_level) z_start = z_level z_finish = z_level - var/list/turfs_to_init = block(locate(1, 1, z_start), locate(world.maxx, world.maxy, z_finish)) - for(var/turf/simulated/T in turfs_to_init) T.CalculateAdjacentTurfs() if(!T.blocks_air) @@ -195,6 +195,8 @@ var/datum/subsystem/air/SSair if(!T.air.check_turf_total(enemy_tile)) T.excited = 1 active_turfs |= T + if(active_turfs.len) + warning("There are [active_turfs.len] active turfs at roundstart, this is a mapping error caused by a difference of the air between the adjacent turfs.") /datum/subsystem/air/proc/setup_atmos_machinery(z_level) for (var/obj/machinery/atmospherics/AM in atmos_machinery) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index a99ac70899f..352caeb6195 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -5,9 +5,11 @@ var/datum/subsystem/garbage_collector/SSgarbage can_fire = 1 wait = 5 priority = -1 + dynamic_wait = 1 + dwait_delta = 5 var/collection_timeout = 300// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object - var/max_run_time = 2 // how long, in deciseconds, can we run before waiting for the next tick + var/max_run_time = 1 // how long, in deciseconds, can we run before waiting for the next tick var/delslasttick = 0 // number of del()'s we've done this tick var/gcedlasttick = 0 // number of things that gc'ed last tick var/totaldels = 0 diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index c2a0c3df334..cd74bb16b84 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -7,6 +7,7 @@ var/datum/subsystem/lighting/SSlighting wait = 5 priority = 1 dynamic_wait = 1 + dwait_delta = 1 var/list/changed_lights = list() //list of all datum/light_source that need updating var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len) diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 7392c98ec88..f2598097565 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -109,7 +109,7 @@ var/datum/subsystem/shuttle/SSshuttle user << "The emergency shuttle has been disabled by Centcom." return - call_reason = strip_html_properly(trim(call_reason)) + call_reason = html_encode(trim(call_reason)) if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH) user << "You must provide a reason." diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 4d80d74daae..fa6db81352b 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -417,5 +417,5 @@ var/datum/subsystem/ticker/ticker /datum/subsystem/ticker/proc/send_random_tip() var/list/randomtips = file2list("config/tips.txt") if(randomtips.len) - world << "Tip of the round: [strip_html_properly(pick(randomtips))]" + world << "Tip of the round: [html_encode(pick(randomtips))]" diff --git a/code/controllers/subsystems.dm b/code/controllers/subsystems.dm index 5e10dcbcfd6..777bc2e5a1e 100644 --- a/code/controllers/subsystems.dm +++ b/code/controllers/subsystems.dm @@ -37,6 +37,9 @@ world << "[msg]" world.log << msg +/datum/subsystem/proc/AfterInitialize() + return + //hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc. /datum/subsystem/proc/stat_entry(msg) var/dwait = "" diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 4a7c4765b00..f40b58dca57 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -38,7 +38,15 @@ var/global/datum/getrev/revdata = new() src << "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]" src << "Enforce Human Authority: [config.enforce_human_authority]" src << "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]" - src << "Protect Assistant From Antagonist: [config.protect_assistant_from_antagonist]" src << "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes" src << "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes" + if(config.show_game_type_odds) + src <<"Game Mode Odds:" + var/sum = 0 + for(var/i=1,i<=config.probabilities.len,i++) + sum += config.probabilities[config.probabilities[i]] + for(var/i=1,i<=config.probabilities.len,i++) + if(config.probabilities[config.probabilities[i]] > 0) + var/percentage = round(config.probabilities[config.probabilities[i]] / sum * 100, 0.1) + src << "[config.probabilities[i]] [percentage]%" return diff --git a/code/datums/spells/lichdom.dm b/code/datums/spells/lichdom.dm new file mode 100644 index 00000000000..a6ace565803 --- /dev/null +++ b/code/datums/spells/lichdom.dm @@ -0,0 +1,108 @@ +/obj/effect/proc_holder/spell/targeted/lichdom + name = "Bind Soul" + desc = "A dark necromantic pact that can forever bind your soul to an item of your choosing. So long as both your body and the item remain intact you can revive from death, though the time between reincarnations grows steadily with use." + school = "necromancy" + charge_max = 10 + clothes_req = 0 + centcom_cancast = 0 + invocation = "NECREM IMORTIUM!" + invocation_type = "shout" + range = -1 + level_max = 0 //cannot be improved + cooldown_min = 10 + include_user = 1 + + var/obj/marked_item + var/mob/living/current_body + + action_icon_state = "skeleton" + +/obj/effect/proc_holder/spell/targeted/lichdom/New() + if(ticker.mode.round_ends_with_antag_death) + ticker.mode.round_ends_with_antag_death = 0 + + ..() +/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets) + for(var/mob/user in targets) + var/list/hand_items = list() + if(iscarbon(user)) + hand_items = list(user.get_active_hand(),user.get_inactive_hand()) + + if(marked_item && !stat_allowed) //sanity, shouldn't happen without badminry + marked_item = null + return + + if(stat_allowed) //Death is not my end! + if(user.stat == CONSCIOUS && iscarbon(user)) + user << "You aren't dead enough to revive!" //Usually a good problem to have + charge_counter = charge_max + return + + if(!marked_item.loc) //Wait nevermind + user << "Your phylactery is gone!" + return + + if(isobserver(user)) + var/mob/dead/observer/O = user + O.reenter_corpse() + + var/mob/living/carbon/human/lich = new /mob/living/carbon/human(get_turf(marked_item)) + + lich.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(lich), slot_shoes) + lich.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(lich), slot_w_uniform) + lich.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(lich), slot_wear_suit) + lich.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(lich), slot_head) + + lich.real_name = user.mind.name + user.mind.transfer_to(lich) + hardset_dna(lich,null,null,lich.real_name,null,/datum/species/skeleton) + lich << "Your bones clatter and shutter as they're pulled back into this world!" + charge_max += 600 + var/mob/old_body = current_body + current_body = lich + lich.Weaken(10) + + if(old_body && old_body.loc) + if(iscarbon(old_body)) + var/mob/living/carbon/C = old_body + for(var/obj/item/W in C) + C.unEquip(W) + var/wheres_wizdo = dir2text(get_dir(get_turf(old_body), get_turf(marked_item))) + if(wheres_wizdo) + old_body.visible_message("Suddenly [old_body.name]'s corpse falls to pieces! You see a strange energy rise from the remains, and speed off towards the [wheres_wizdo]!") + old_body.dust() + + if(!marked_item) //linking item to the spell + message = "" + for(var/obj/item in hand_items) + if(ABSTRACT in item.flags || NODROP in item.flags) + continue + marked_item = item + user << "You begin to focus your very being into the [item.name]..." + break + + if(!marked_item) + user << "You must hold an item you wish to make your phylactery..." + + spawn(50) + if(marked_item.loc != user) //I changed my mind I don't want to put my soul in a cheeseburger! + user << "Your soul snaps back to your body as you drop the [marked_item.name]!" + marked_item = null + return + name = "RISE!" + desc = "Rise from the dead! You will reform at the location of your phylactery and your old body will crumble away." + charge_max = 1800 //3 minute cooldown, if you rise in sight of someone and killed again, you're probably screwed. + charge_counter = 1800 + stat_allowed = 1 + marked_item.name = "Ensouled [marked_item.name]" + marked_item.desc = "A terrible aura surrounds this item, its very existence is offensive to life itself..." + marked_item.color = "#003300" + user << "With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!" + hardset_dna(user, null, null, null, null, /datum/species/skeleton) + current_body = user.mind.current + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.unEquip(H.wear_suit) + H.unEquip(H.head) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), slot_head) \ No newline at end of file diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm index e74ce4a92c6..7b29e448844 100644 --- a/code/datums/spells/summonitem.dm +++ b/code/datums/spells/summonitem.dm @@ -7,7 +7,7 @@ invocation = "GAR YOK" invocation_type = "whisper" range = -1 - level_max = 1 //cannot be improved + level_max = 0 //cannot be improved cooldown_min = 100 include_user = 1 diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm deleted file mode 100644 index 33f8c1421a5..00000000000 --- a/code/datums/wires/camera.dm +++ /dev/null @@ -1,76 +0,0 @@ -// Wires for cameras. - -/datum/wires/camera - random = 0 - holder_type = /obj/machinery/camera - wire_count = 6 - -/datum/wires/camera/GetInteractWindow() - - . = ..() - var/obj/machinery/camera/C = holder - . += "
\n[(C.view_range == initial(C.view_range) ? "The focus light is on." : "The focus light is off.")]" - . += "
\n[(C.can_use() ? "The power link light is on." : "The power link light is off.")]" - . += "
\n[(C.light_disabled ? "The camera light is off." : "The camera light is on.")]" - . += "
\n[(C.alarm_on ? "The alarm light is on." : "The alarm light is off.")]" - return . - -/datum/wires/camera/CanUse(var/mob/living/L) - var/obj/machinery/camera/C = holder - if(!C.panel_open) - return 0 - return 1 - -var/const/CAMERA_WIRE_FOCUS = 1 -var/const/CAMERA_WIRE_POWER = 2 -var/const/CAMERA_WIRE_LIGHT = 4 -var/const/CAMERA_WIRE_ALARM = 8 -var/const/CAMERA_WIRE_NOTHING1 = 16 -var/const/CAMERA_WIRE_NOTHING2 = 32 - -/datum/wires/camera/UpdateCut(var/index, var/mended) - var/obj/machinery/camera/C = holder - - switch(index) - if(CAMERA_WIRE_FOCUS) - var/range = (mended ? initial(C.view_range) : C.short_range) - C.setViewRange(range) - - if(CAMERA_WIRE_POWER) - if(C.status && !mended || !C.status && mended) - C.deactivate(usr, 1) - - if(CAMERA_WIRE_LIGHT) - C.light_disabled = !mended - - if(CAMERA_WIRE_ALARM) - if(!mended) - C.triggerCameraAlarm() - else - C.cancelCameraAlarm() - return - -/datum/wires/camera/UpdatePulsed(var/index) - var/obj/machinery/camera/C = holder - if(IsIndexCut(index)) - return - switch(index) - if(CAMERA_WIRE_FOCUS) - var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range)) - C.setViewRange(new_range) - - if(CAMERA_WIRE_POWER) - C.deactivate(null) // Deactivate the camera - - if(CAMERA_WIRE_LIGHT) - C.light_disabled = !C.light_disabled - - if(CAMERA_WIRE_ALARM) - C.visible_message("\icon[C] *beep*", "\icon[C] *beep*") - return - -/datum/wires/camera/proc/CanDeconstruct() - if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS) && IsIndexCut(CAMERA_WIRE_LIGHT) && IsIndexCut(CAMERA_WIRE_NOTHING1) && IsIndexCut(CAMERA_WIRE_NOTHING2)) - return 1 - else - return 0 \ No newline at end of file diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index ba6f252724a..e483513c40a 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -102,8 +102,7 @@ var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown", /datum/wires/Topic(href, href_list) ..() - if(in_range(holder, usr) && isliving(usr)) - + if(usr.Adjacent(holder) && isliving(usr)) var/mob/living/L = usr if(CanUse(L) && href_list["action"]) var/obj/item/I = L.get_active_hand() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 8afadbc4ce8..cb638aa6f31 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -21,6 +21,10 @@ // replaced by OPENCONTAINER flags and atom/proc/is_open_container() ///Chemistry. var/allow_spin = 1 + + //Value used to increment ex_act() if reactionary_explosions is on + var/explosion_block = 0 + /atom/proc/onCentcom() var/turf/T = get_turf(src) if(!T) diff --git a/code/game/communications.dm b/code/game/communications.dm index 75155dff914..9f7d515a300 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -299,4 +299,4 @@ var/list/pointers = list() for(var/d in data) var/val = data[d] if(istext(val)) - data[d] = strip_html_properly(val) + data[d] = html_encode(val) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 4bfeecb2247..eddb0216d76 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -188,7 +188,7 @@ return 0 - if(living_antag_player && living_antag_player.mind && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player)) + if(living_antag_player && living_antag_player.mind && isliving(living_antag_player) && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player)) return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark. for(var/mob/Player in living_mob_list) diff --git a/code/game/gamemodes/gang/dominator.dm b/code/game/gamemodes/gang/dominator.dm new file mode 100644 index 00000000000..4fbae44af79 --- /dev/null +++ b/code/game/gamemodes/gang/dominator.dm @@ -0,0 +1,209 @@ +/obj/machinery/dominator + name = "dominator" + desc = "A visibly sinister device. Looks like you can break it if you hit it enough." + icon = 'icons/obj/machines/dominator.dmi' + icon_state = "dominator" + density = 1 + anchored = 1.0 + layer = 3.6 + var/health = 200 + var/gang + var/operating = 0 + var/broken = 0 + +/obj/machinery/dominator/New() + if(!istype(ticker.mode, /datum/game_mode/gang)) + qdel(src) + return + SetLuminosity(2) + +/obj/machinery/dominator/examine(mob/user) + ..() + if(broken) + user << "It looks completely busted." + return + + var/datum/game_mode/gang/mode = ticker.mode + var/time = null + if(isnum(mode.A_timer)) + time = max(mode.A_timer, 0) + if(isnum(mode.B_timer)) + time = max(mode.B_timer, 0) + if(isnum(time)) + if(time > 0) + user << "Hostile Takeover in progress. Estimated [time] seconds remain." + else + user << "Hostile Takeover of [station_name()] successful. Have a great day." + else + user << "System on standby." + user << "System Integrity: [health/2]%" + + +/obj/machinery/dominator/proc/healthcheck(var/damage) + var/iconname = "dominator" + if(gang) + iconname += "-[gang]" + SetLuminosity(3) + + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread + + health -= damage + + switch(health) + if(101 to INFINITY) + if(prob(damage*2)) + sparks.set_up(5, 1, src) + sparks.start() + if(1 to 100) + sparks.set_up(5, 1, src) + sparks.start() + iconname += "-damaged" + + if(!broken) + if(health <= 0) + set_broken() + else + icon_state = iconname + + if(health <= -50) + new /obj/item/stack/sheet/plasteel(src.loc) + qdel(src) + +/obj/machinery/dominator/proc/set_broken() + if(!gang) + return + var/datum/game_mode/gang/mode = ticker.mode + if(gang == "A") + mode.A_timer = "OFFLINE" + if(gang == "B") + mode.B_timer = "OFFLINE" + if(!isnum(mode.A_timer) && !isnum(mode.B_timer)) + SSshuttle.emergencyNoEscape = 0 + if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) + SSshuttle.emergency.mode = SHUTTLE_DOCKED + SSshuttle.emergency.timer = world.time + priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority") + else + priority_announce("All hostile activity within station systems have ceased.","Network Alert") + SetLuminosity(0) + icon_state = "dominator-broken" + broken = 1 + +/obj/machinery/dominator/Destroy() + if(!broken) + set_broken() + ..() + +/obj/machinery/dominator/emp_act(severity) + healthcheck(100) + ..() + +/obj/machinery/dominator/ex_act(severity, target) + if(target == src) + qdel(src) + return + switch(severity) + if(1.0) + qdel(src) + if(2.0) + healthcheck(120) + if(3.0) + healthcheck(30) + return + +/obj/machinery/dominator/bullet_act(var/obj/item/projectile/Proj) + if(Proj.damage) + if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + playsound(src, 'sound/effects/bang.ogg', 50, 1) + visible_message("[src] was hit by [Proj].") + healthcheck(Proj.damage) + ..() + +/obj/machinery/dominator/blob_act() + healthcheck(110) + +/obj/machinery/dominator/attackby(I as obj, user as mob, params) + + return + +/obj/machinery/dominator/attack_hand(mob/user) + if(operating||broken) + examine(user) + return + + var/datum/game_mode/gang/mode = ticker.mode + var/gang_territory + var/timer + + var/tempgang + if(user.mind in (ticker.mode.A_gang|ticker.mode.A_bosses)) + tempgang = "A" + gang_territory = ticker.mode.A_territory.len + timer = mode.A_timer + else if(user.mind in (ticker.mode.B_gang|ticker.mode.B_bosses)) + tempgang = "B" + gang_territory = ticker.mode.B_territory.len + timer = mode.B_timer + + if(!tempgang) + examine(user) + return + + if(isnum(timer)) //In theory, this shouldn't happen. But if it does, they get this meme + user << "Error: Hostile Takeover is already in progress." + return + + var/time = max(180,900 - ((round((gang_territory/start_state.num_territories)*200, 1) - 60) * 15)) + if(alert(user,"With [round((gang_territory/start_state.num_territories)*100, 1)]% station control, a takeover will require [time] seconds.\nThe entire station will likely be alerted once it starts.\nYour gang must be prepared to defend this device throughout the duration.\nAre you ready?","Confirmation","Yes","No") == "Yes") + if ((!in_range(src, user) || !istype(src.loc, /turf))) + return 0 + var/area/srcloc = get_area(src.loc) + gang = tempgang + mode.domination(gang,1,srcloc.name) + src.name = "[gang_name(gang)] Gang [src.name]" + healthcheck(0) + operating = 1 + +/obj/machinery/dominator/attack_alien(mob/living/user) + user.do_attack_animation(src) + playsound(src, 'sound/effects/bang.ogg', 50, 1) + user.visible_message("[user] smashes against [src] with its claws.",\ + "You smash against [src] with your claws.",\ + "You hear metal scraping.") + healthcheck(15) + +/obj/machinery/dominator/attack_animal(mob/living/user as mob) + if(!isanimal(user)) + return + var/mob/living/simple_animal/M = user + M.do_attack_animation(src) + if(M.melee_damage_upper <= 0) + return + healthcheck(M.melee_damage_upper) + +/obj/machinery/dominator/mech_melee_attack(obj/mecha/M) + if(M.damtype == "brute") + playsound(src, 'sound/effects/bang.ogg', 50, 1) + visible_message("[M.name] has hit [src].") + healthcheck(M.force) + return + +/obj/machinery/dominator/attack_hulk(mob/user) + playsound(src, 'sound/effects/bang.ogg', 50, 1) + user.visible_message("[user] smashes [src].",\ + "You punch [src].",\ + "You hear metal being slammed.") + healthcheck(5) + +/obj/machinery/dominator/attackby(obj/item/weapon/I as obj, mob/living/user as mob, params) + if(istype(I, /obj/item/weapon)) + add_fingerprint(user) + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src) + if( (I.flags&NOBLUDGEON) || !I.force ) + return + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + visible_message("[user] has hit \the [src] with [I].") + if(I.damtype == BURN || I.damtype == BRUTE) + healthcheck(I.force) + return diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm index 6967dc894c7..97ed4eecbcd 100644 --- a/code/game/gamemodes/gang/gang.dm +++ b/code/game/gamemodes/gang/gang.dm @@ -15,6 +15,10 @@ var/list/A_territory_lost = list() var/list/B_territory_new = list() var/list/B_territory_lost = list() + var/gang_A_style + var/gang_A_headgear + var/gang_B_style + var/gang_B_headgear /datum/game_mode/gang name = "gang war" @@ -26,14 +30,15 @@ recommended_enemies = 2 enemy_minimum_age = 14 var/finished = 0 - var/goal_scalar = 0.5 //Goal = Total territories x goal_scalar - + // Victory timers + var/A_timer = "OFFLINE" + var/B_timer = "OFFLINE" /////////////////////////// //Announces the game type// /////////////////////////// /datum/game_mode/gang/announce() world << "The current game mode is - Gang War!" - world << "A violent turf war has erupted on the station!
Gangsters - Take over the station by claiming more than [round(100*goal_scalar,1)]% of the station!
Crew - The gangs will try to keep you on the station. Successfully evacuate the station to win!
" + world << "A violent turf war has erupted on the station!
Gangsters - Take over the station by activating and defending a Dominator!
Crew - The gangs will try to keep you on the station. Successfully evacuate the station to win!
" /////////////////////////////////////////////////////////////////////////////// @@ -73,6 +78,15 @@ modePlayer += B_bosses ..() +/datum/game_mode/gang/process(seconds) + if(!finished) + if(isnum(A_timer)) + A_timer -= seconds + if(isnum(B_timer)) + B_timer -= seconds + + ticker.mode.check_win() + /datum/game_mode/gang/proc/assign_bosses() var/datum/mind/boss = pick(antag_candidates) A_bosses += boss @@ -91,7 +105,7 @@ /datum/game_mode/proc/forge_gang_objectives(var/datum/mind/boss_mind) var/datum/objective/rival_obj = new rival_obj.owner = boss_mind - rival_obj.explanation_text = "Claim more than 50% the station before the [(boss_mind in A_bosses) ? gang_name("B") : gang_name("A")] Gang does." + rival_obj.explanation_text = "Preform a hostile takeover of the station with a Dominator." boss_mind.objectives += rival_obj @@ -103,6 +117,17 @@ boss_mind.current << "Objective #[obj_count]: [objective.explanation_text]" obj_count++ +/datum/game_mode/gang/proc/domination(var/gang,var/modifier=1,var/dominatorloc) + if(gang=="A") + A_timer = max(180,900 - ((round((ticker.mode.A_territory.len/start_state.num_territories)*200, 1) - 60) * 15)) * modifier + if(gang=="B") + B_timer = max(180,900 - ((round((ticker.mode.B_territory.len/start_state.num_territories)*200, 1) - 60) * 15)) * modifier + if(gang && dominatorloc) + priority_announce("Hostile runtimes detected in all station systems. A network breach by the [gang_name(gang)] Gang has been traced to [dominatorloc].","Network Alert") + if(get_security_level() != "delta") + set_security_level("red") + SSshuttle.emergencyNoEscape = 1 + /////////////////////////////////////////////////////////////////////////// //This equips the bosses with their gear, and makes the clown not clumsy// /////////////////////////////////////////////////////////////////////////// @@ -132,37 +157,107 @@ var/where = mob.equip_in_one_of_slots(gangtool, slots) if (!where) mob << "Your Syndicate benefactors were unfortunately unable to get you a Gangtool." + . += 1 else gangtool.register_device(mob) - mob << "The Gangtool in your [where] will allow you to use your influence to purchase items and prevent the station from evacuating before you can take over. Use it to recall the emergency shuttle from anywhere on the station." + mob << "The Gangtool in your [where] will allow you to purchase items, send messages to your gangsters and to recall the emergency shuttle from anywhere on the station." mob << "You can also promote your gang members to lieutenant by giving them an unregistered gangtool. Lieutenants cannot be deconverted and are able to use recruitment pens and gangtools." - . += 1 var/where2 = mob.equip_in_one_of_slots(T, slots) if (!where2) mob << "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start." + . += 1 else mob << "The recruitment pen in your [where2] will help you get your gang started. Use it on unsuspecting crew members to recruit them." - . += 1 var/where3 = mob.equip_in_one_of_slots(SC, slots) if (!where3) mob << "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start." + . += 1 else mob << "The territory spraycan in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get. Distribute these to your gangsters to grow your influence faster." - . += 1 mob.update_icons() return . +//Used by recallers when purchasing a gang outfit. First time a gang outfit is purchased the buyer decides a gang style which is stored so gang outfits are uniform +/datum/game_mode/proc/gang_outfit(mob/user,var/obj/item/device/gangtool/gangtool,var/gang) + if(!user || !gangtool || !gang) + return 0 + if(!gangtool.can_use(user)) + return 0 + + var/gang_style_list = list("Gang Colors","Leather Jackets","Fine Suits") + var/style + var/headgear + if(gang == "A") + if(!gang_A_style) + gang_A_style = input("Pick an outfit style.", "Pick Style") as null|anything in gang_style_list + if(gang_A_style && (alert(user,"Include headgear?","Option","Yes","No") == "Yes")) + gang_A_headgear = 1 + style = gang_A_style + headgear = gang_A_headgear + + if(gang == "B") + if(!gang_B_style) + gang_B_style = input("Pick an outfit style.", "Pick Style") as null|anything in gang_style_list + if(gang_B_style && (alert(user,"Include headgear?","Option","Yes","No") == "Yes")) + gang_B_headgear = 1 + style = gang_B_style + headgear = gang_B_headgear + + if(!style) + return 0 + + if(gangtool.can_use(user) && (((gang == "A") ? gang_points.A : gang_points.B) >= 1)) + switch(style) + if("Gang Colors") + if(gang == "A") + new /obj/item/clothing/under/color/blue(user.loc) + if(headgear) + new /obj/item/clothing/mask/bandana/blue(user.loc) + if(gang == "B") + new /obj/item/clothing/under/color/red(user.loc) + if(headgear) + new /obj/item/clothing/mask/bandana/red(user.loc) + if("Leather Jackets") + new /obj/item/clothing/suit/jacket/leather(user.loc) + if(headgear) + if(gang == "A") + new /obj/item/clothing/mask/bandana/blue(user.loc) + if(gang == "B") + new /obj/item/clothing/mask/bandana/red(user.loc) + if("Fine Suits") + new /obj/item/clothing/under/suit_jacket/really_black(user.loc) + if(headgear) + new /obj/item/clothing/head/fedora(user.loc) + + return 1 + + return 0 + ///////////////////////////////////////////// //Checks if the either gang have won or not// ///////////////////////////////////////////// /datum/game_mode/gang/check_win() - if(A_territory.len > (start_state.num_territories * goal_scalar)) - finished = "A" //Gang A wins - else if(B_territory.len > (start_state.num_territories * goal_scalar)) - finished = "B" //Gang B wins + var/winner = 0 + + if(isnum(A_timer)) + if(A_timer < 0) + winner += 1 + if(isnum(B_timer)) + if(B_timer < 0) + winner += 2 + + if(winner) + if(winner == 3) //Edge Case: If both dominators activate at the same time + domination("A",0.5) + domination("B",0.5) + priority_announce("Multiple station takeover attempts have made simultaneously. Conflicting hostile runtimes have delayed both attempts.","Network Alert") + else if(winner == 1) + finished = "A" //Gang A wins + else if(winner == 2) + finished = "B" //Gang B wins /////////////////////////////// //Checks if the round is over// @@ -282,7 +377,7 @@ if(!finished) world << "The station was [station_was_nuked ? "destroyed!" : "evacuated before either gang could claim it!"]" else - world << "The [finished=="A" ? gang_name("A") : gang_name("B")] Gang has claimed over [round(100*goal_scalar,1)]% of the station and has assumed control!" + world << "The [finished=="A" ? gang_name("A") : gang_name("B")] Gang successfully preformed a hostile takeover of the station!!" ..() return 1 @@ -338,8 +433,8 @@ ////////////////////////////////////////////////////////// /datum/gang_points - var/A = 30 - var/B = 30 + var/A = 25 + var/B = 25 var/next_point_interval = 1800 var/next_point_time @@ -429,12 +524,9 @@ var/A_control = round((ticker.mode.A_territory.len/start_state.num_territories)*100, 1) var/B_control = round((ticker.mode.B_territory.len/start_state.num_territories)*100, 1) ticker.mode.message_gangtools((ticker.mode.A_tools),"Your gang now has [A_control]% control of the station.",0) - ticker.mode.message_gangtools((ticker.mode.A_tools),"The [gang_name("B")] Gang has [B_control]% control of the station.",0,1) + //ticker.mode.message_gangtools((ticker.mode.A_tools),"The [gang_name("B")] Gang has [B_control]% control of the station.",0,1) ticker.mode.message_gangtools((ticker.mode.B_tools),"Your gang now has [B_control]% control of the station.",0) - ticker.mode.message_gangtools((ticker.mode.B_tools),"The [gang_name("A")] Gang has [A_control]% control of the station.",0,1) - - //Victory check - ticker.mode.check_win() + //ticker.mode.message_gangtools((ticker.mode.B_tools),"The [gang_name("A")] Gang has [A_control]% control of the station.",0,1) //Restart the counter start() diff --git a/code/game/objects/items/devices/recaller.dm b/code/game/gamemodes/gang/recaller.dm similarity index 72% rename from code/game/objects/items/devices/recaller.dm rename to code/game/gamemodes/gang/recaller.dm index de3f046635c..addef28d740 100644 --- a/code/game/objects/items/devices/recaller.dm +++ b/code/game/gamemodes/gang/recaller.dm @@ -2,7 +2,7 @@ /obj/item/device/gangtool name = "suspicious device" desc = "A strange device of sorts. Hard to really make out what it actually does just by looking." - icon_state = "recaller" + icon_state = "gangtool" item_state = "walkietalkie" throwforce = 0 w_class = 1.0 @@ -33,30 +33,28 @@ else dat += "Register Device
" else + var/datum/game_mode/gang/gangmode + if(istype(ticker.mode, /datum/game_mode/gang)) + gangmode = ticker.mode + var/gang_size = ((gang == "A")? (ticker.mode.A_gang.len + ticker.mode.A_bosses.len) : (ticker.mode.B_gang.len + ticker.mode.B_bosses.len)) var/gang_territory = ((gang == "A")? ticker.mode.A_territory.len : ticker.mode.B_territory.len) var/points = ((gang == "A") ? ticker.mode.gang_points.A : ticker.mode.gang_points.B) + var/timer + if(gangmode) + timer = ((gang == "A") ? gangmode.A_timer : gangmode.B_timer) + if(isnum(timer)) + dat += "
Takeover In Progress:
[timer] seconds remain

" dat += "Registration: [(gang == "A")? gang_name("A") : gang_name("B")] Gang [boss ? "Administrator" : "Lieutenant"]
" - dat += "Organization Size: [gang_size]
" - dat += "Station Control: [round((gang_territory/start_state.num_territories)*100, 1)]%
" + dat += "Organization Size: [gang_size] | Station Control: [round((gang_territory/start_state.num_territories)*100, 1)]%
" + dat += "Send Gang-wide Message
" dat += "Recall Emergency Shuttle
" dat += "
" dat += "Influence: [points]
" - dat += "Time until Influence grows: [(points >= 100) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))]
" - dat += "Purchase Items:
" - - dat += "(5 Influence) " - if(points >= 5) - dat += "Send Gang-wide Message
" - else - dat += "Send Gang-wide Message
" - - dat += "(10 Influence) " - if(points >= 10) - dat += "Territory Spraycan
" - else - dat += "Territory Spraycan
" + dat += "Time until Influence grows: [(points >= 999) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))]
" + dat += "
" + dat += "Purchase Weapons:
" dat += "(10 Influence) " if(points >= 10) @@ -64,8 +62,8 @@ else dat += "Switchblade
" - dat += "(25 Influence) " - if(points >= 25) + dat += "(20 Influence) " + if(points >= 20) dat += "10mm Pistol
" else dat += "10mm Pistol
" @@ -76,8 +74,35 @@ else dat += "10mm Ammo
" - dat += "(40 Influence) " - if(points >= 40) + dat += "(50 Influence) " + if(points >= 50) + dat += "Thompson SMG
" + else + dat += "Thompson SMG
" + + dat += "
" + dat += "Purchase Utilities:
" + + dat += "(10 Influence) " + if(points >= 10) + dat += "Territory Spraycan
" + else + dat += "Territory Spraycan
" + + dat += "(1 Influence) " + if(points >= 1) + dat += "Gang Outfit
" + else + dat += "Gang Outfit
" + + dat += "(10 Influence) " + if(points >= 10) + dat += "Bulletproof Vest
" + else + dat += "Bulletproof Vest
" + + dat += "(30 Influence) " + if(points >= 30) dat += "Recruitment Pen
" else dat += "Recruitment Pen
" @@ -91,14 +116,23 @@ dat += "Promote a Gangster
" else dat += "Promote a Gangster
" + if(gangmode) + dat += "(50 Influence) " + if(points >= 50) + dat += "Station Dominator
" + dat += "(Estimated Takeover Time: [round(max(180,900 - ((round((gang_territory/start_state.num_territories)*200, 10) - 60) * 15))/60,1)] minutes)
" + else + dat += "Station Dominator
" dat += "
" dat += "Refresh
" - var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v0.4") + var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v0.4", 350, 550) popup.set_content(dat) popup.open() + + /obj/item/device/gangtool/Topic(href, href_list) if(!can_use(usr)) return @@ -115,6 +149,10 @@ var/points = ((gang == "A") ? ticker.mode.gang_points.A : ticker.mode.gang_points.B) var/item_type switch(href_list["purchase"]) + if("outfit") + if(points >= 1) + item_type = ticker.mode.gang_outfit(usr,src,gang) + points = 1 if("spraycan") if(points >= 10) item_type = /obj/item/toy/crayon/spraycan/gang @@ -124,31 +162,60 @@ item_type = /obj/item/weapon/switchblade points = 10 if("pistol") - if(points >= 25) + if(points >= 20) item_type = /obj/item/weapon/gun/projectile/automatic/pistol - points = 25 + points = 20 if("ammo") if(points >= 10) item_type = /obj/item/ammo_box/magazine/m10mm points = 10 + if("SMG") + if(points >= 50) + item_type = /obj/item/weapon/gun/projectile/automatic/tommygun + points = 50 + if("vest") + if(points >= 10) + item_type = /obj/item/clothing/suit/armor/bulletproof + points = 10 if("pen") - if(points >= 40) + if(points >= 30) item_type = /obj/item/weapon/pen/gang - points = 40 + points = 30 if("gangtool") if((promotions < 3) && (points >= (promotions*20)+10)) item_type = /obj/item/device/gangtool/lt points = (promotions*20)+10 promotions++ + if("dominator") + if(istype(ticker.mode, /datum/game_mode/gang)) + var/datum/game_mode/gang/mode = ticker.mode + if(isnum((gang == "A") ? mode.A_timer : mode.B_timer)) + return + + var/fail = 0 + var/usrarea = get_area(usr.loc) + var/usrturf = get_turf(usr.loc) + if(istype(usrarea,/area/space) || istype(usrturf,/turf/space) || usr.z != 1) + usr << "You can only use this on the station!" + fail = 1 + for(var/obj/obj in usrturf) + if(obj.density) + usr << "There's not enough room here!" + fail = 1 + break + if(!fail && points >= 50) + item_type = /obj/machinery/dominator + points = 50 if(item_type) if(gang == "A") ticker.mode.gang_points.A -= points else if(gang == "B") ticker.mode.gang_points.B -= points - var/obj/purchased = new item_type(get_turf(usr)) - var/mob/living/carbon/human/H = usr - H.put_in_any_hand_if_possible(purchased) + if(ispath(item_type)) + var/obj/purchased = new item_type(get_turf(usr)) + var/mob/living/carbon/human/H = usr + H.put_in_any_hand_if_possible(purchased) ticker.mode.message_gangtools(((gang=="A")? ticker.mode.A_tools : ticker.mode.B_tools), "A [href_list["purchase"]] was purchased by [usr] for [points] Influence.") log_game("A [href_list["purchase"]] was purchased by [key_name(usr)] for [points] Influence.") @@ -172,18 +239,16 @@ return var/list/members = list() if(gang == "A") - if(ticker.mode.gang_points.A >= 5) - members += ticker.mode.A_bosses | ticker.mode.A_gang - ticker.mode.gang_points.A -= 5 + members += ticker.mode.A_bosses | ticker.mode.A_gang else if(gang == "B") - if(ticker.mode.gang_points.B >= 5) - members += ticker.mode.B_bosses | ticker.mode.B_gang - ticker.mode.gang_points.B -= 5 + members += ticker.mode.B_bosses | ticker.mode.B_gang if(members.len) + var/ping = "[boss ? "Gang Boss" : "Gang Lieutenant"]: [message]" for(var/datum/mind/ganger in members) if(ganger.current.z <= 2) - ganger.current << "BOSS: [message]" - message_admins("[key_name_admin(user)] sent a global message to the [gang_name(gang)] Gang ([gang]): [message].") + ganger.current << "[ping]" + for(var/mob/M in dead_mob_list) + M << "[gang_name(gang)] [ping]" log_game("[key_name(user)] sent a global message to the [gang_name(gang)] Gang ([gang]): [message].") @@ -196,6 +261,7 @@ if(user.mind in (ticker.mode.A_gang | ticker.mode.A_bosses)) ticker.mode.A_tools += src gang = "A" + icon_state = "gangtool-a" if(!(user.mind in ticker.mode.A_bosses)) ticker.mode.remove_gangster(user.mind, 0, 2) ticker.mode.A_bosses += user.mind @@ -206,6 +272,7 @@ else if(user.mind in (ticker.mode.B_gang | ticker.mode.B_bosses)) ticker.mode.B_tools += src gang = "B" + icon_state = "gangtool-b" if(!(user.mind in ticker.mode.B_bosses)) ticker.mode.remove_gangster(user.mind, 0, 2) ticker.mode.B_bosses += user.mind @@ -218,7 +285,7 @@ user << "You have been promoted to Lieutenant!" ticker.mode.forge_gang_objectives(user.mind) ticker.mode.greet_gang(user.mind,0) - user << "The Gangtool you registered will allow you to use your gang's influence to purchase items and prevent the station from evacuating before your gang can take over. Use it to recall the emergency shuttle from anywhere on the station." + user << "The Gangtool you registered will allow you to purchase items, send messages to your gangsters and to recall the emergency shuttle from anywhere on the station." user << "You may also now use recruitment pens to grow your gang membership. Use them on unsuspecting crew members to recruit them." if(!gang) usr << "ACCESS DENIED: Unauthorized user." diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 8a58076e663..da2e49f4af7 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -182,6 +182,11 @@ log_name = "IS" category = "Utility Spells" +/datum/spellbook_entry/lichdom + name = "Bind Soul" + spell_type = /obj/effect/proc_holder/spell/targeted/lichdom + log_name = "LD" + /datum/spellbook_entry/lightningbolt name = "Lightning Bolt" spell_type = /obj/effect/proc_holder/spell/targeted/lightning diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 78297803c2a..76623347eb9 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -18,7 +18,8 @@ var/list/injection_chems = list() //list of injectable chems except ephedrine, coz ephedrine is always avalible var/list/possible_chems = list(list("morphine", "salbutamol", "salglu_solution"), list("morphine", "salbutamol", "salglu_solution", "oculine"), - list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "pen_acid")) + list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "pen_acid"), + list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "omnizine")) /obj/machinery/sleeper/New() ..() component_parts = list() diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index 87eb95b4f42..abb5bc29586 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -78,6 +78,7 @@ set_frequency(frequency) /obj/machinery/air_sensor/Destroy() + SSair.atmos_machinery -= src if(radio_controller) radio_controller.remove_object(src,frequency) ..() diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm index d8ba823694b..99bd769543a 100644 --- a/code/game/machinery/atmoalter/meter.dm +++ b/code/game/machinery/atmoalter/meter.dm @@ -18,6 +18,11 @@ src.target = locate(/obj/machinery/atmospherics/pipe) in loc return 1 +/obj/machinery/meter/Destroy() + SSair.atmos_machinery -= src + src.target = null + ..() + /obj/machinery/meter/initialize() if (!target) src.target = locate(/obj/machinery/atmospherics/pipe) in loc diff --git a/code/game/machinery/atmoalter/zvent.dm b/code/game/machinery/atmoalter/zvent.dm index 26bd2cff6c1..42e1926ef4e 100644 --- a/code/game/machinery/atmoalter/zvent.dm +++ b/code/game/machinery/atmoalter/zvent.dm @@ -9,6 +9,14 @@ var/on = 0 var/volume_rate = 800 +/obj/machinery/zvent/New() + ..() + SSair.atmos_machinery += src + +/obj/machinery/zvent/Destroy() + SSair.atmos_machinery -= src + ..() + /obj/machinery/zvent/process_atmos() //all this object does, is make its turf share air with the ones above and below it, if they have a vent too. diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index ca4b9fdd034..ae2204f9da3 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -8,12 +8,12 @@ active_power_usage = 10 layer = 5 - var/datum/wires/camera/wires = null // Wires datum + var/health = 50 var/list/network = list("SS13") var/c_tag = null var/c_tag_order = 999 - var/status = 1.0 - anchored = 1.0 + var/status = 1 + anchored = 1 var/start_active = 0 //If it ignores the random chance to start broken on round start var/invuln = null var/obj/item/device/camera_bug/bug = null @@ -30,8 +30,6 @@ var/emped = 0 //Number of consecutive EMP's on this camera /obj/machinery/camera/New() - wires = new(src) - assembly = new(src) assembly.state = 4 assembly.anchored = 1 @@ -59,20 +57,18 @@ if(bug.current == src) bug.current = null bug = null - qdel(wires) cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that ..() /obj/machinery/camera/emp_act(severity) if(!isEmpProof()) - if(prob(100/severity)) + if(prob(150/severity)) icon_state = "[initial(icon_state)]emp" var/list/previous_network = network network = list() cameranet.removeCamera(src) stat |= EMPED SetLuminosity(0) - triggerCameraAlarm() emped = emped+1 //Increase the number of consecutive EMP's var/thisemp = emped //Take note of which EMP this proc is for spawn(900) @@ -81,10 +77,12 @@ network = previous_network icon_state = initial(icon_state) stat &= ~EMPED - cancelCameraAlarm() if(can_use()) cameranet.addCamera(src) emped = 0 //Resets the consecutive EMP count + triggerCameraAlarm() + spawn(100) + cancelCameraAlarm() for(var/mob/O in mob_list) if (O.client && O.client.eye == src) O.unset_machine() @@ -117,66 +115,71 @@ if(!istype(user)) return user.do_attack_animation(src) - status = 0 + add_hiddenprint(user) visible_message("\The [user] slashes at [src]!") playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - icon_state = "[initial(icon_state)]1" - add_hiddenprint(user) - deactivate(user,0) + health = max(0, health - 30) + if(!health && status) + deactivate(user, 0) -/obj/machinery/camera/attackby(W as obj, mob/living/user as mob, params) - var/msg = "You attach [W] into the assembly inner circuits." - var/msg2 = "The camera already has that upgrade!" +/obj/machinery/camera/attackby(obj/W, mob/living/user, params) + var/msg = "You attach [W] into the assembly's inner circuits." + var/msg2 = "[src] already has that upgrade!" // DECONSTRUCTION if(istype(W, /obj/item/weapon/screwdriver)) - //user << "You start to [panel_open ? "close" : "open"] the camera's panel." - //if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown panel_open = !panel_open - user.visible_message("[user] screws the camera's panel [panel_open ? "open" : "closed"]!", - "You screw the camera's panel [panel_open ? "open" : "closed"].") + user << "You screw the camera's panel [panel_open ? "open" : "closed"]." playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + return - else if((istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) && panel_open) - wires.Interact(user) + if(panel_open) + if(istype(W, /obj/item/weapon/wirecutters)) //enable/disable the camera + deactivate(user, 1) + health = initial(health) //this is a pretty simplistic way to heal the camera, but there's no reason for this to be complex. - else if(istype(W, /obj/item/weapon/weldingtool) && wires.CanDeconstruct()) - if(weld(W, user)) - user << "You unweld the camera leaving it as just a frame screwed to the wall." - if(!assembly) - assembly = new() - assembly.loc = src.loc - assembly.state = 1 - assembly.dir = src.dir - assembly.update_icon() - assembly = null - qdel(src) - return - else if(istype(W, /obj/item/device/analyzer) && panel_open) //XRay - if(!isXRay()) - upgradeXRay() - qdel(W) - user << "[msg]" - else - user << "[msg2]" + else if(istype(W, /obj/item/device/multitool)) //change focus + setViewRange((view_range == initial(view_range)) ? short_range : initial(view_range)) + user << "You [(view_range == initial(view_range)) ? "restore" : "mess up"] the camera's focus." - else if(istype(W, /obj/item/stack/sheet/mineral/plasma) && panel_open) - if(!isEmpProof()) - upgradeEmpProof() - user << "[msg]" - qdel(W) - else - user << "[msg2]" - else if(istype(W, /obj/item/device/assembly/prox_sensor) && panel_open) - if(!isMotion()) - upgradeMotion() - user << "[msg]" - qdel(W) - else - user << "[msg2]" + else if(istype(W, /obj/item/weapon/weldingtool)) + if(weld(W, user)) + visible_message("[user] unwelds [src], leaving it as just a frame screwed to the wall.", "You unweld [src], leaving it as just a frame screwed to the wall") + if(!assembly) + assembly = new() + assembly.loc = src.loc + assembly.state = 1 + assembly.dir = src.dir + assembly.update_icon() + assembly = null + qdel(src) + return + + else if(istype(W, /obj/item/device/analyzer)) + if(!isXRay()) + upgradeXRay() + qdel(W) + user << "[msg]" + else + user << "[msg2]" + + else if(istype(W, /obj/item/stack/sheet/mineral/plasma)) + if(!isEmpProof()) + upgradeEmpProof() + user << "[msg]" + qdel(W) + else + user << "[msg2]" + else if(istype(W, /obj/item/device/assembly/prox_sensor)) + if(!isMotion()) + upgradeMotion() + user << "[msg]" + qdel(W) + else + user << "[msg2]" // OTHER - else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user)) + if((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user)) var/mob/living/U = user var/obj/item/weapon/paper/X = null var/obj/item/device/pda/P = null @@ -204,6 +207,7 @@ else if (O.client && O.client.eye == src) O << "[U] holds \a [itemname] up to one of the cameras ..." O << browse(text("[][]", itemname, info), text("window=[]", itemname)) + else if (istype(W, /obj/item/device/camera_bug)) if (!src.can_use()) user << "Camera non-functional." @@ -216,23 +220,29 @@ user << "Camera bugged." src.bug = W src.bug.bugged_cameras[src.c_tag] = src + else if(istype(W, /obj/item/device/laser_pointer)) var/obj/item/device/laser_pointer/L = W L.laser_act(src, user) + else - ..() + if(W.force > 10) //fairly simplistic, but will do for now. + user.changeNext_move(CLICK_CD_MELEE) + visible_message("[user] hits [src] with [W]!", "You hit [src] with [W]!") + health = max(0, health - W.force) + if(!health && status) + deactivate(user, 1) return -/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1) - if(choice==1) - status = !( src.status ) - if (!(src.status)) +/obj/machinery/camera/proc/deactivate(mob/user, displaymessage = 1) //this should be called toggle() but doing a find and replace for this would be ass + if(displaymessage) + status = !status + if(!status) if(user) visible_message("[user] deactivates [src]!") add_hiddenprint(user) else visible_message("\The [src] deactivates!") - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) icon_state = "[initial(icon_state)]1" else @@ -241,8 +251,11 @@ add_hiddenprint(user) else visible_message("\The [src] reactivates!") - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + triggerCameraAlarm() icon_state = initial(icon_state) + spawn(100) + cancelCameraAlarm() + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) // now disconnect anyone using the camera //Apparently, this will disconnect anyone even if the camera was re-activated. @@ -308,7 +321,6 @@ return null /proc/near_range_camera(var/mob/M) - for(var/obj/machinery/camera/C in range(4, M)) if(C.can_use()) // check if camera disabled return C @@ -317,7 +329,6 @@ return null /obj/machinery/camera/proc/weld(var/obj/item/weapon/weldingtool/WT, var/mob/living/user) - if(busy) return 0 if(!WT.remove_fuel(0, user)) @@ -347,4 +358,4 @@ /obj/machinery/camera/portable/process() //Updates whenever the camera is moved. if(cameranet && get_turf(src) != prev_turf) cameranet.updatePortableCamera(src) - prev_turf = get_turf(src) \ No newline at end of file + prev_turf = get_turf(src) diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index 95664e9a49f..759082e598b 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -49,38 +49,13 @@ return list() for(var/mob/living/M in mob_list) - // Easy checks first. - // Don't detect mobs on Centcom. Since the wizard den is on Centcom, we only need this. - var/turf/T = get_turf(M) - if(!T) - continue - if(T.z == ZLEVEL_CENTCOM) - continue - if(T.z >= ZLEVEL_SPACEMAX) - continue - if(M == usr) - continue - if(M.invisibility)//cloaked - continue - if(M.digitalcamo) + if(!M.can_track(usr)) continue // Human check var/human = 0 if(istype(M, /mob/living/carbon/human)) human = 1 - var/mob/living/carbon/human/H = M - //Cameras can't track people wearing an agent card or a ninja hood. - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) - continue - if(istype(H.head, /obj/item/clothing/head)) - var/obj/item/clothing/head/hat = H.head - if(hat.blockTracking) - continue - - // Now, are they viewable by a camera? (This is last because it's the most intensive check) - if(!near_camera(M)) - continue var/name = M.name if (name in track.names) @@ -109,51 +84,54 @@ ai_actual_track(target) -/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target as mob) +/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target) if(!istype(target)) return var/mob/living/silicon/ai/U = usr - U.cameraFollow = target - //U << text("Now tracking [] on camera.", target.name) - //if (U.machine == null) - // U.machine = U - U << "Now tracking [target.get_visible_name()] on camera." - spawn (0) + U.cameraFollow = target + U.tracking = 1 + + U << "Attempting to track [target.get_visible_name()]..." + sleep(min(30, get_dist(target, U.eyeobj) / 4)) + spawn(15) //give the AI a grace period to stop moving. + U.tracking = 0 + + if(!target || !target.can_track(usr)) + U << "Target is not near any active cameras." + U.cameraFollow = null + return + + U << "Now tracking [target.get_visible_name()] on camera." + + var/cameraticks = 0 + spawn(0) while (U.cameraFollow == target) if (U.cameraFollow == null) return - if (istype(target, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = target - if(H.wear_id && istype(H.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) - U << "Follow camera mode terminated." - U.cameraFollow = null - return - if(istype(H.head, /obj/item/clothing/head)) - var/obj/item/clothing/head/hat = H.head - if(hat.blockTracking) - U << "Follow camera mode terminated." - U.cameraFollow = null - return - if(H.digitalcamo) - U << "Follow camera mode terminated." - U.cameraFollow = null - return - if(istype(target.loc,/obj/effect/dummy)) - U << "Follow camera mode ended." - U.cameraFollow = null - return - - if (!near_camera(target)) - U << "Target is not near any active cameras." - sleep(100) - continue + if (!target.can_track(usr)) + U.tracking = 1 + U << "Target is not near any active cameras." + cameraticks++ + if(cameraticks > 9) + U.cameraFollow = null + tracking = 0 + return + else + continue + + else + cameraticks = 0 + U.tracking = 0 if(U.eyeobj) U.eyeobj.setLoc(get_turf(target)) + else view_core() + U.cameraFollow = null return + sleep(10) /proc/near_camera(var/mob/living/M) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 87be0acbdf5..00a8bde3ac0 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -44,6 +44,8 @@ for(var/obj/item/weapon/stock_parts/manipulator/P in component_parts) speed_coeff += P.rating heal_level = (efficiency * 15) + 10 + if(heal_level > 100) + heal_level = 100 //The return of data disks?? Just for transferring between genetics machine/cloning machine. //TO-DO: Make the genetics machine accept them. diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 31eacb182d8..0f4909b7d80 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -101,10 +101,10 @@ var/name_part1 var/name_part2 - name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ") + name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ", "Ban ") name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") - name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn") + name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers") src.enemy_name = replacetext((name_part1 + name_part2), "the ", "") src.name = (name_action + name_part1 + name_part2) @@ -145,6 +145,7 @@ src.blocked = 1 var/attackamt = rand(2,6) src.temp = "You attack for [attackamt] damage!" + playsound(src.loc, 'sound/arcade/Hit.ogg', 50, 1, extrarange = -3, falloff = 10) src.updateUsrDialog() if(turtle > 0) turtle-- @@ -158,6 +159,7 @@ var/pointamt = rand(1,3) var/healamt = rand(6,8) src.temp = "You use [pointamt] magic to heal for [healamt] damage!" + playsound(src.loc, 'sound/arcade/Heal.ogg', 50, 1, extrarange = -3, falloff = 10) src.updateUsrDialog() turtle++ @@ -172,6 +174,7 @@ src.blocked = 1 var/chargeamt = rand(4,7) src.temp = "You regain [chargeamt] points" + playsound(src.loc, 'sound/arcade/Mana.ogg', 50, 1, extrarange = -3, falloff = 10) src.player_mp += chargeamt if(turtle > 0) turtle-- @@ -206,6 +209,7 @@ if(!gameover) src.gameover = 1 src.temp = "[src.enemy_name] has fallen! Rejoice!" + playsound(src.loc, 'sound/arcade/Win.ogg', 50, 1, extrarange = -3, falloff = 10) if(emagged) feedback_inc("arcade_win_emagged") @@ -222,11 +226,13 @@ else if (emagged && (turtle >= 4)) var/boomamt = rand(5,10) src.temp = "[src.enemy_name] throws a bomb, exploding you for [boomamt] damage!" + playsound(src.loc, 'sound/arcade/Boom.ogg', 50, 1, extrarange = -3, falloff = 10) src.player_hp -= boomamt else if ((src.enemy_mp <= 5) && (prob(70))) var/stealamt = rand(2,3) src.temp = "[src.enemy_name] steals [stealamt] of your power!" + playsound(src.loc, 'sound/arcade/Steal.ogg', 50, 1, extrarange = -3, falloff = 10) src.player_mp -= stealamt src.updateUsrDialog() @@ -234,6 +240,7 @@ src.gameover = 1 sleep(10) src.temp = "You have been drained! GAME OVER" + playsound(src.loc, 'sound/arcade/Lose.ogg', 50, 1, extrarange = -3, falloff = 10) if(emagged) feedback_inc("arcade_loss_mana_emagged") usr.gib() @@ -242,17 +249,20 @@ else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4)) src.temp = "[src.enemy_name] heals for 4 health!" + playsound(src.loc, 'sound/arcade/Heal.ogg', 50, 1, extrarange = -3, falloff = 10) src.enemy_hp += 4 src.enemy_mp -= 4 else var/attackamt = rand(3,6) src.temp = "[src.enemy_name] attacks for [attackamt] damage!" + playsound(src.loc, 'sound/arcade/Hit.ogg', 50, 1, extrarange = -3, falloff = 10) src.player_hp -= attackamt if ((src.player_mp <= 0) || (src.player_hp <= 0)) src.gameover = 1 src.temp = "You have been crushed! GAME OVER" + playsound(src.loc, 'sound/arcade/Lose.ogg', 50, 1, extrarange = -3, falloff = 10) if(emagged) feedback_inc("arcade_loss_hp_emagged") usr.gib() diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 4f7c4dfad82..5530c7cc5a1 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -265,6 +265,15 @@ to destroy them and players will be able to make replacements. /obj/item/weapon/stock_parts/cell = 5, /obj/item/weapon/stock_parts/capacitor = 1) +/obj/item/weapon/circuitboard/emitter + name = "circuit board (Emitter)" + build_path = /obj/machinery/power/emitter + board_type = "machine" + origin_tech = "programming=4;powerstorage=5;engineering=5" + req_components = list( + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + /obj/item/weapon/circuitboard/power_compressor name = "circuit board (Power Compressor)" build_path = /obj/machinery/power/compressor @@ -384,6 +393,7 @@ to destroy them and players will be able to make replacements. origin_tech = "programming=1;biotech=1" req_components = list( /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/manipulator = 1, /obj/item/weapon/stock_parts/console_screen = 1) /obj/item/weapon/circuitboard/microwave @@ -393,9 +403,71 @@ to destroy them and players will be able to make replacements. origin_tech = "programming=1" req_components = list( /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/stack/cable_coil = 2, /obj/item/weapon/stock_parts/console_screen = 1) +/obj/item/weapon/circuitboard/gibber + name = "circuit board (Gibber)" + build_path = /obj/machinery/gibber + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + +/obj/item/weapon/circuitboard/processor + name = "circuit board (Food processor)" + build_path = /obj/machinery/processor + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + +/obj/item/weapon/circuitboard/recycler + name = "circuit board (Recycler)" + build_path = /obj/machinery/recycler + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + +/obj/item/weapon/circuitboard/seed_extractor + name = "circuit board (Seed Extractor)" + build_path = /obj/machinery/seed_extractor + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + +/obj/item/weapon/circuitboard/smartfridge + name = "circuit board (Smartfridge)" + build_path = /obj/machinery/smartfridge + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1) + +/obj/item/weapon/circuitboard/monkey_recycler + name = "circuit board (Monkey Recycler)" + build_path = /obj/machinery/monkey_recycler + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1) + +/obj/item/weapon/circuitboard/holopad + name = "circuit board (AI Holopad)" + build_path = /obj/machinery/hologram/holopad + board_type = "machine" + origin_tech = "programming=1" + req_components = list( + /obj/item/weapon/stock_parts/capacitor = 1) + /obj/item/weapon/circuitboard/chem_dispenser name = "circuit board (Portable Chem Dispenser)" build_path = /obj/machinery/chem_dispenser/constructable @@ -639,6 +711,8 @@ obj/item/weapon/circuitboard/rdserver req_components = list( /obj/item/weapon/stock_parts/console_screen = 1, /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/manipulator = 1, /obj/item/device/assembly/igniter = 1) /obj/item/weapon/circuitboard/mining_equipment_vendor diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index c7b8dc92fe8..ae1a9fb771d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -46,6 +46,8 @@ var/hasShocked = 0 //Prevents multiple shocks from happening var/autoclose = 1 + explosion_block = 1 + /obj/machinery/door/airlock/command icon = 'icons/obj/doors/Doorcom.dmi' doortype = /obj/structure/door_assembly/door_assembly_com @@ -268,6 +270,7 @@ name = "high tech security airlock" icon = 'icons/obj/doors/hightechsecurity.dmi' doortype = /obj/structure/door_assembly/door_assembly_highsecurity + explosion_block = 2 /obj/machinery/door/airlock/shuttle name = "shuttle airlock" diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index e558ccbac61..c1836108462 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -6,6 +6,7 @@ var/id = 1 var/auto_close = 0 // Time in seconds to automatically close when opened, 0 if it doesn't. sub_door = 1 + explosion_block = 3 heat_proof = 1 /obj/machinery/door/poddoor/preopen @@ -87,318 +88,27 @@ operating = 0 +//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS. +/obj/machinery/door/poddoor/ex_act(severity, target) + switch(severity) + if(1.0) + if(prob(80)) + qdel(src) + else + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + if(2.0) + if(prob(20)) + qdel(src) + else + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() + if(3.0) + if(prob(80)) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() -/* -/obj/machinery/door/poddoor/two_tile_hor/open() - if (src.operating == 1) //doors can still open when emag-disabled - return - if (!ticker) - return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick("pdoorc0", src) - src.icon_state = "pdoor0" - src.SetOpacity(0) - f1.SetOpacity(0) - f2.SetOpacity(0) - - sleep(10) - src.density = 0 - f1.density = 0 - f2.density = 0 - - update_nearby_tiles() - - if(operating == 1) //emag again - src.operating = 0 - if(autoclose) - spawn(150) - autoclose() - return 1 - -/obj/machinery/door/poddoor/two_tile_hor/close() - if (src.operating) - return - src.operating = 1 - flick("pdoorc1", src) - src.icon_state = "pdoor1" - - src.density = 1 - f1.density = 1 - f2.density = 1 - - sleep(10) - src.SetOpacity(initial(opacity)) - f1.SetOpacity(initial(opacity)) - f2.SetOpacity(initial(opacity)) - - update_nearby_tiles() - - src.operating = 0 - return - -/obj/machinery/door/poddoor/four_tile_hor/open() - if (src.operating == 1) //doors can still open when emag-disabled - return - if (!ticker) - return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick("pdoorc0", src) - src.icon_state = "pdoor0" - sleep(10) - src.density = 0 - src.sd_SetOpacity(0) - - f1.density = 0 - f1.sd_SetOpacity(0) - f2.density = 0 - f2.sd_SetOpacity(0) - f3.density = 0 - f3.sd_SetOpacity(0) - f4.density = 0 - f4.sd_SetOpacity(0) - - update_nearby_tiles() - - if(operating == 1) //emag again - src.operating = 0 - if(autoclose) - spawn(150) - autoclose() - return 1 - -/obj/machinery/door/poddoor/four_tile_hor/close() - if (src.operating) - return - src.operating = 1 - flick("pdoorc1", src) - src.icon_state = "pdoor1" - src.density = 1 - - f1.density = 1 - f1.sd_SetOpacity(1) - f2.density = 1 - f2.sd_SetOpacity(1) - f3.density = 1 - f3.sd_SetOpacity(1) - f4.density = 1 - f4.sd_SetOpacity(1) - - if (src.visible) - src.sd_SetOpacity(1) - update_nearby_tiles() - - sleep(10) - src.operating = 0 - return - -/obj/machinery/door/poddoor/two_tile_ver/open() - if (src.operating == 1) //doors can still open when emag-disabled - return - if (!ticker) - return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick("pdoorc0", src) - src.icon_state = "pdoor0" - sleep(10) - src.density = 0 - src.sd_SetOpacity(0) - - f1.density = 0 - f1.sd_SetOpacity(0) - f2.density = 0 - f2.sd_SetOpacity(0) - - update_nearby_tiles() - - if(operating == 1) //emag again - src.operating = 0 - if(autoclose) - spawn(150) - autoclose() - return 1 - -/obj/machinery/door/poddoor/two_tile_ver/close() - if (src.operating) - return - src.operating = 1 - flick("pdoorc1", src) - src.icon_state = "pdoor1" - src.density = 1 - - f1.density = 1 - f1.sd_SetOpacity(1) - f2.density = 1 - f2.sd_SetOpacity(1) - - if (src.visible) - src.sd_SetOpacity(1) - update_nearby_tiles() - - sleep(10) - src.operating = 0 - return - -/obj/machinery/door/poddoor/four_tile_ver/open() - if (src.operating == 1) //doors can still open when emag-disabled - return - if (!ticker) - return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick("pdoorc0", src) - src.icon_state = "pdoor0" - sleep(10) - src.density = 0 - src.sd_SetOpacity(0) - - f1.density = 0 - f1.sd_SetOpacity(0) - f2.density = 0 - f2.sd_SetOpacity(0) - f3.density = 0 - f3.sd_SetOpacity(0) - f4.density = 0 - f4.sd_SetOpacity(0) - - update_nearby_tiles() - - if(operating == 1) //emag again - src.operating = 0 - if(autoclose) - spawn(150) - autoclose() - return 1 - -/obj/machinery/door/poddoor/four_tile_ver/close() - if (src.operating) - return - src.operating = 1 - flick("pdoorc1", src) - src.icon_state = "pdoor1" - src.density = 1 - - f1.density = 1 - f1.sd_SetOpacity(1) - f2.density = 1 - f2.sd_SetOpacity(1) - f3.density = 1 - f3.sd_SetOpacity(1) - f4.density = 1 - f4.sd_SetOpacity(1) - - if (src.visible) - src.sd_SetOpacity(1) - update_nearby_tiles() - - sleep(10) - src.operating = 0 - return - - - - -/obj/machinery/door/poddoor/two_tile_hor - var/obj/machinery/door/poddoor/filler_object/f1 - var/obj/machinery/door/poddoor/filler_object/f2 - icon = 'icons/obj/doors/1x2blast_hor.dmi' - - New() - ..() - f1 = new/obj/machinery/door/poddoor/filler_object (src.loc) - f2 = new/obj/machinery/door/poddoor/filler_object (get_step(src,EAST)) - f1.density = density - f2.density = density - f1.sd_SetOpacity(opacity) - f2.sd_SetOpacity(opacity) - - Destroy() - qdel(f1) - qdel(f2) - ..() - -/obj/machinery/door/poddoor/two_tile_ver - var/obj/machinery/door/poddoor/filler_object/f1 - var/obj/machinery/door/poddoor/filler_object/f2 - icon = 'icons/obj/doors/1x2blast_vert.dmi' - - New() - ..() - f1 = new/obj/machinery/door/poddoor/filler_object (src.loc) - f2 = new/obj/machinery/door/poddoor/filler_object (get_step(src,NORTH)) - f1.density = density - f2.density = density - f1.sd_SetOpacity(opacity) - f2.sd_SetOpacity(opacity) - - Destroy() - qdel(f1) - qdel(f2) - ..() - -/obj/machinery/door/poddoor/four_tile_hor - var/obj/machinery/door/poddoor/filler_object/f1 - var/obj/machinery/door/poddoor/filler_object/f2 - var/obj/machinery/door/poddoor/filler_object/f3 - var/obj/machinery/door/poddoor/filler_object/f4 - icon = 'icons/obj/doors/1x4blast_hor.dmi' - - New() - ..() - f1 = new/obj/machinery/door/poddoor/filler_object (src.loc) - f2 = new/obj/machinery/door/poddoor/filler_object (get_step(f1,EAST)) - f3 = new/obj/machinery/door/poddoor/filler_object (get_step(f2,EAST)) - f4 = new/obj/machinery/door/poddoor/filler_object (get_step(f3,EAST)) - f1.density = density - f2.density = density - f3.density = density - f4.density = density - f1.sd_SetOpacity(opacity) - f2.sd_SetOpacity(opacity) - f4.sd_SetOpacity(opacity) - f3.sd_SetOpacity(opacity) - - Destroy() - qdel(f1) - qdel(f2) - qdel(f3) - qdel(f4) - ..() - -/obj/machinery/door/poddoor/four_tile_ver - var/obj/machinery/door/poddoor/filler_object/f1 - var/obj/machinery/door/poddoor/filler_object/f2 - var/obj/machinery/door/poddoor/filler_object/f3 - var/obj/machinery/door/poddoor/filler_object/f4 - icon = 'icons/obj/doors/1x4blast_vert.dmi' - - New() - ..() - f1 = new/obj/machinery/door/poddoor/filler_object (src.loc) - f2 = new/obj/machinery/door/poddoor/filler_object (get_step(f1,NORTH)) - f3 = new/obj/machinery/door/poddoor/filler_object (get_step(f2,NORTH)) - f4 = new/obj/machinery/door/poddoor/filler_object (get_step(f3,NORTH)) - f1.density = density - f2.density = density - f3.density = density - f4.density = density - f1.sd_SetOpacity(opacity) - f2.sd_SetOpacity(opacity) - f4.sd_SetOpacity(opacity) - f3.sd_SetOpacity(opacity) - - Destroy() - qdel(f1) - qdel(f2) - qdel(f3) - qdel(f4) - ..() - -/obj/machinery/door/poddoor/filler_object - name = "" - icon_state = "" - -*/ \ No newline at end of file diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm index df94284c2c5..f8c634f9724 100644 --- a/code/game/machinery/doors/unpowered.dm +++ b/code/game/machinery/doors/unpowered.dm @@ -21,4 +21,5 @@ name = "door" icon_state = "door1" opacity = 1 - density = 1 \ No newline at end of file + density = 1 + explosion_block = 1 \ No newline at end of file diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 6f20b8ce9f6..299a8c01b38 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -42,6 +42,35 @@ var/const/HOLOPAD_MODE = RANGE_BASED var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating. var/temp = "" +/obj/machinery/hologram/holopad/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/holopad(null) + component_parts += new /obj/item/weapon/stock_parts/capacitor(null) + RefreshParts() + +/obj/machinery/hologram/holopad/RefreshParts() + var/holograph_range = 4 + for(var/obj/item/weapon/stock_parts/capacitor/B in component_parts) + holograph_range += 1 * B.rating + holo_range = holograph_range + +/obj/machinery/hologram/holopad/attackby(obj/item/P as obj, mob/user as mob, params) + if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P)) + return + + if(exchange_parts(user, P)) + return + + if(default_pry_open(P)) + return + + if(default_unfasten_wrench(user, P)) + return + + default_deconstruction_crowbar(P) + + /obj/machinery/hologram/holopad/attack_hand(var/mob/living/carbon/human/user) //Carn: Hologram requests. if(!istype(user)) return diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 8d07ebf090d..e5961c09fc9 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -93,7 +93,7 @@ return PROCESS_KILL if(!(get_dist(src, attached) <= 1 && isturf(attached.loc))) - attached << "The IV drip needle is ripped out of you, doesn't that hurt?" + attached << "The IV drip needle is ripped out of you!" attached.apply_damage(3, BRUTE, pick("r_arm", "l_arm")) attached = null update_icon() @@ -103,10 +103,10 @@ // Give blood if(mode) if(beaker.volume > 0) - var/transfer_amount = REAGENTS_METABOLISM + var/transfer_amount = 5 if(istype(beaker, /obj/item/weapon/reagent_containers/blood)) // speed up transfer on blood packs - transfer_amount = 4 + transfer_amount = 10 beaker.reagents.reaction(attached, INGEST, 1,0) //make reagents reacts, but don't spam messages beaker.reagents.trans_to(attached, transfer_amount) update_icon() @@ -205,4 +205,4 @@ else usr << "No chemicals are attached." - usr << "[attached ? attached : "No one"] is attached." \ No newline at end of file + usr << "[attached ? attached : "No one"] is attached." diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index c616c2d6301..1498fa14fe8 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -377,9 +377,13 @@ Class Procs: /obj/machinery/proc/exchange_parts(mob/user, obj/item/weapon/storage/part_replacer/W) var/shouldplaysound = 0 if(istype(W) && component_parts) - if(panel_open) + if(panel_open || W.works_from_distance) var/obj/item/weapon/circuitboard/CB = locate(/obj/item/weapon/circuitboard) in component_parts var/P + if(W.works_from_distance) + user << "Following parts detected in the machine:" + for(var/var/obj/item/C in component_parts) + user << " [C.name]" for(var/obj/item/weapon/stock_parts/A in component_parts) for(var/D in CB.req_components) if(ispath(A.type, D)) diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 7c1751ff821..c8a121619cd 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -13,12 +13,38 @@ var/const/SAFETY_COOLDOWN = 100 var/icon_name = "grinder-o" var/blood = 0 var/eat_dir = WEST + var/amount_produced = 1 + var/probability_mod = 1 + var/extra_materials = 0 + var/list/blacklist = list(/obj/item/pipe, /obj/item/pipe_meter, /obj/structure/disposalconstruct, /obj/item/weapon/reagent_containers, /obj/item/weapon/paper, /obj/item/stack/, /obj/item/weapon/pen, /obj/item/weapon/storage/, /obj/item/clothing/mask/cigarette) // Don't allow us to grind things we can poop out at 200 a second for free. /obj/machinery/recycler/New() // On us ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/recycler(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + RefreshParts() update_icon() +/obj/machinery/recycler/RefreshParts() + var/amt_made = 0 + var/prob_mod = 0 + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + amt_made = 1 * B.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + if(M.rating > 1) + prob_mod = 2 * M.rating + else + prob_mod = 1 * M.rating + if(M.rating >= 3) + extra_materials = 1 + else + extra_materials = 0 + probability_mod = prob_mod + amount_produced = amt_made + /obj/machinery/recycler/examine(mob/user) ..() user << "The power light is [(stat & NOPOWER) ? "off" : "on"]." @@ -31,15 +57,22 @@ var/const/SAFETY_COOLDOWN = 100 /obj/machinery/recycler/attackby(var/obj/item/I, var/mob/user, params) - if(istype(I, /obj/item/weapon/screwdriver)) - if(emagged) - emagged = 0 - update_icon() - user << "You reset the crusher to its default factory settings." - else - ..() + if(default_deconstruction_screwdriver(user, "grinder-oOpen", "grinder-o0", I)) return + + if(exchange_parts(user, I)) + return + + if(default_pry_open(I)) + return + + if(default_unfasten_wrench(user, I)) + return + + default_deconstruction_crowbar(I) + ..() add_fingerprint(user) + return /obj/machinery/recycler/emag_act(user as mob) if(!emagged) @@ -70,13 +103,6 @@ var/const/SAFETY_COOLDOWN = 100 return if(safety_mode) return - // If we're not already grinding something. - if(!grinding) - grinding = 1 - spawn(1) - grinding = 0 - else - return var/move_dir = get_dir(loc, AM.loc) if(move_dir == eat_dir) @@ -93,15 +119,40 @@ var/const/SAFETY_COOLDOWN = 100 /obj/machinery/recycler/proc/recycle(var/obj/item/I, var/sound = 1) I.loc = src.loc + if(is_type_in_list(I, blacklist)) + qdel(I) + if(sound) + playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + return qdel(I) - if(prob(15)) - new /obj/item/stack/sheet/metal(loc) - if(prob(10)) - new /obj/item/stack/sheet/glass(loc) - if(prob(2)) - new /obj/item/stack/sheet/plasteel(loc) - if(prob(1)) - new /obj/item/stack/sheet/rglass(loc) + if(prob(15 + probability_mod)) + var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(loc) + M.amount = amount_produced + if(prob(10 + probability_mod)) + var/obj/item/stack/sheet/glass/G = new /obj/item/stack/sheet/glass(loc) + G.amount = amount_produced + if(prob(2 + probability_mod)) + var/obj/item/stack/sheet/plasteel/P = new /obj/item/stack/sheet/plasteel(loc) + P.amount = amount_produced + if(prob(1 + probability_mod)) + var/obj/item/stack/sheet/rglass/R = new /obj/item/stack/sheet/rglass(loc) + R.amount = amount_produced + if(extra_materials) + if(prob(4 + probability_mod)) + var/obj/item/stack/sheet/mineral/plasma/PS = new /obj/item/stack/sheet/mineral/plasma(loc) + PS.amount = amount_produced + if(prob(3 + probability_mod)) + var/obj/item/stack/sheet/mineral/gold/GS = new /obj/item/stack/sheet/mineral/gold(loc) + GS.amount = amount_produced + if(prob(2 + probability_mod)) + var/obj/item/stack/sheet/mineral/silver/S = new /obj/item/stack/sheet/mineral/silver(loc) + S.amount = amount_produced + if(prob(1 + probability_mod)) + var/obj/item/stack/sheet/mineral/bananium/B = new /obj/item/stack/sheet/mineral/bananium(loc) + B.amount = amount_produced + if(prob(1 + probability_mod)) + var/obj/item/stack/sheet/mineral/diamond/D = new /obj/item/stack/sheet/mineral/diamond(loc) + D.amount = amount_produced if(sound) playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 63620b72676..7e1fd4d977c 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -90,6 +90,18 @@ for(var/turf/T in trange(max_range, epicenter)) var/dist = cheap_pythag(T.x - x0,T.y - y0) + + if(config.reactionary_explosions) + var/turf/Trajectory = T + while(Trajectory != epicenter) + Trajectory = get_step_towards(Trajectory, epicenter) + if(Trajectory.density && Trajectory.explosion_block) + dist += Trajectory.explosion_block + + for(var/obj/machinery/door/D in Trajectory) + if(D.density && D.explosion_block) + dist += D.explosion_block + var/flame_dist = 0 var/throw_dist = dist @@ -138,3 +150,76 @@ /proc/secondaryexplosion(turf/epicenter, range) for(var/turf/tile in trange(range, epicenter)) tile.ex_act(2) + + +/client/proc/check_bomb_impacts() + set name = "Check Bomb Impact" + set category = "Debug" + + var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No") + var/turf/epicenter = get_turf(mob) + if(!epicenter) + return + + var/dev = 0 + var/heavy = 0 + var/light = 0 + var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb") + var/choice = input("Bomb Size?") in choices + switch(choice) + if(null) + return 0 + if("Small Bomb") + dev = 1 + heavy = 2 + light = 3 + if("Medium Bomb") + dev = 2 + heavy = 3 + light = 4 + if("Big Bomb") + dev = 3 + heavy = 5 + light = 7 + if("Custom Bomb") + dev = input("Devestation range (Tiles):") as num + heavy = input("Heavy impact range (Tiles):") as num + light = input("Light impact range (Tiles):") as num + + var/max_range = max(dev, heavy, light) + var/x0 = epicenter.x + var/y0 = epicenter.y + var/list/wipe_colours = list() + for(var/turf/T in trange(max_range, epicenter)) + wipe_colours += T + var/dist = cheap_pythag(T.x - x0, T.y - y0) + + if(newmode == "Yes") + var/turf/TT = T + while(TT != epicenter) + TT = get_step_towards(TT,epicenter) + if(TT.density && TT.explosion_block) + dist += TT.explosion_block + + for(var/obj/machinery/door/D in TT) + if(D.density && D.explosion_block) + dist += D.explosion_block + + if(dist < dev) + T.color = "red" + T.maptext = "Dev" + else if (dist < heavy) + T.color = "yellow" + T.maptext = "Heavy" + else if (dist < light) + T.color = "blue" + T.maptext = "Light" + else + continue + + sleep(100) + for(var/turf/T in wipe_colours) + T.color = null + T.maptext = "" + + diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index aeb17f0df26..83dcbf39f7c 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -58,7 +58,7 @@ . = ..() var/area/A = get_area() if(get_area_type() == AREA_STATION) - . += "

According to \the [src], you are now in \"[strip_html_properly(A.name)]\".

" + . += "

According to \the [src], you are now in \"[html_encode(A.name)]\".

" var/datum/browser/popup = new(user, "blueprints", "[src]", 700, 500) popup.set_content(.) popup.open() @@ -83,7 +83,7 @@ . = ..() var/area/A = get_area() if(get_area_type() == AREA_STATION) - . += "

According to \the [src], you are now in \"[strip_html_properly(A.name)]\".

" + . += "

According to \the [src], you are now in \"[html_encode(A.name)]\".

" . += "

You may move an amendment to the drawing.

" var/datum/browser/popup = new(user, "blueprints", "[src]", 700, 500) popup.set_content(.) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 6c37732b1b7..caed55b1454 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -136,10 +136,7 @@ /obj/item/toy/crayon/spraycan/New() ..() - if(gang) - name = "Modified Paint Applicator" - else - name = "NanoTrasen-brand Rapid Paint Applicator" + name = "spray can" update_icon() /obj/item/toy/crayon/spraycan/examine(mob/user) @@ -155,7 +152,7 @@ if("Toggle Cap") user << "You [capped ? "Remove" : "Replace"] the cap of the [src]" capped = capped ? 0 : 1 - icon_state = "spraycan[gang ? "_gang" : ""][capped ? "_cap" : ""]" + icon_state = "spraycan[capped ? "_cap" : ""]" update_icon() if("Change Drawing") ..() @@ -194,8 +191,7 @@ overlays += I /obj/item/toy/crayon/spraycan/gang - desc = "A suspicious-looking spraycan modified to use special paint used by gangsters to mark territory." - icon_state = "spraycan_gang_cap" + desc = "A modified container containing suspicious paint." gang = 1 uses = 20 instant = -1 diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 9225c031d28..16f19760d7d 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -904,16 +904,16 @@ var/global/list/obj/item/device/pda/PDAs = list() else var/obj/item/I = user.get_active_hand() if (istype(I, /obj/item/weapon/card/id)) - if(!user.drop_item()) + if(!user.unEquip(I)) return 0 I.loc = src id = I else var/obj/item/weapon/card/I = user.get_active_hand() if (istype(I, /obj/item/weapon/card/id) && I:registered_name) - var/obj/old_id = id - if(!user.drop_item()) + if(!user.unEquip(I)) return 0 + var/obj/old_id = id I.loc = src id = I user.put_in_hands(old_id) @@ -924,7 +924,7 @@ var/global/list/obj/item/device/pda/PDAs = list() ..() if(istype(C, /obj/item/weapon/cartridge) && !cartridge) cartridge = C - if(!user.drop_item()) + if(!user.unEquip(C)) return cartridge.loc = src user << "You insert [cartridge] into [src]." @@ -952,7 +952,7 @@ var/global/list/obj/item/device/pda/PDAs = list() return //Return in case of failed check or when successful. updateSelfDialog()//For the non-input related code. else if(istype(C, /obj/item/device/paicard) && !src.pai) - if(!user.drop_item()) + if(!user.unEquip(C)) return C.loc = src pai = C @@ -963,7 +963,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(O) user << "There is already a pen in \the [src]!" else - if(!user.drop_item()) + if(!user.unEquip(C)) return C.loc = src user << "You slide \the [C] into \the [src]." @@ -1032,7 +1032,7 @@ var/global/list/obj/item/device/pda/PDAs = list() note = replacetext(note, "
  • ", "\[*\]") note = replacetext(note, "", "\[/list\]") - note = strip_html_properly(note) + note = html_encode(note) notescanned = 1 user << "Paper scanned. Saved to PDA's notekeeper." //concept of scanning paper copyright brainoblivion 2009 @@ -1186,7 +1186,7 @@ var/global/list/obj/item/device/pda/PDAs = list() //ntrc handler proc /obj/item/device/pda/proc/msg_chat(channel as text, sender as text, message as text) - var/msg = "[strip_html_properly(sender)]| [strip_html_properly(message)]
    " + var/msg = "[html_encode(sender)]| [html_encode(message)]
    " if(!channel) for(var/C in ntrclog) ntrclog[C] = msg + ntrclog[C] diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/game/objects/items/devices/PDA/chatroom.dm index 1cc8d642cd3..a46b4def36f 100644 --- a/code/game/objects/items/devices/PDA/chatroom.dm +++ b/code/game/objects/items/devices/PDA/chatroom.dm @@ -66,7 +66,7 @@ var/list/chatchannels = list(default_ntrc_chatroom.name = default_ntrc_chatroom) /datum/chatroom/proc/send_message(client,nick,message) //standard message if(!message) return 0 - logs.Insert(1,"[strip_html_properly(nick)]> [strip_html_properly(message)]") + logs.Insert(1,"[html_encode(nick)]> [html_encode(message)]") log_chat("[usr]/([usr.ckey]) as [nick] sent to [name]: [message]") events.fireEvent("msg_chat",name,nick,message) return 1 diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 862fc2a89b8..bca8126ad81 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -30,23 +30,24 @@ ..() SSobj.processing += src - /obj/item/device/multitool/ai_detect/Destroy() SSobj.processing -= src ..() /obj/item/device/multitool/ai_detect/process() - if(track_delay > world.time) return var/found_eye = 0 var/turf/our_turf = get_turf(src) - if(cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z)) + for(var/mob/living/silicon/ai/AI in ai_list) + if(AI.cameraFollow == src) + found_eye = 1 + break + if(!found_eye && cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z)) var/datum/camerachunk/chunk = cameranet.getCameraChunk(our_turf.x, our_turf.y, our_turf.z) - if(chunk) if(chunk.seenby.len) for(var/mob/camera/aiEye/A in chunk.seenby) @@ -62,4 +63,3 @@ track_delay = world.time + 10 // 1 second return - diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index 2a8ef3cae0b..fd5cb821462 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -100,7 +100,7 @@ /obj/item/device/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans) if(mytape && recording) mytape.timestamp += mytape.used_capacity - mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [strip_html_properly(message)]" + mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [html_encode(message)]" /obj/item/device/taperecorder/verb/record() set name = "Start Recording" diff --git a/code/game/objects/items/holotape.dm b/code/game/objects/items/holotape.dm index bd10a107cad..68070972d6e 100644 --- a/code/game/objects/items/holotape.dm +++ b/code/game/objects/items/holotape.dm @@ -153,6 +153,8 @@ charging = 0 /obj/item/holotape/Bumped(var/mob/M) + if(!ismob(M)) + return if(iscarbon(M)) var/mob/living/carbon/C = M if(C.m_intent == "walk") @@ -227,11 +229,11 @@ /obj/item/holotape/proc/breaktape() var/dir[2] - var/icon_dir = src.icon_state - if(icon_dir == "[src.icon_base]_h") + var/icon_dir = icon_state + if(icon_dir == "[icon_base]_h") dir[1] = EAST dir[2] = WEST - if(icon_dir == "[src.icon_base]_v") + if(icon_dir == "[icon_base]_v") dir[1] = NORTH dir[2] = SOUTH diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm index 34522d2ec59..35d3ae089ce 100644 --- a/code/game/objects/items/stacks/sheets/sheets.dm +++ b/code/game/objects/items/stacks/sheets/sheets.dm @@ -8,18 +8,4 @@ throw_range = 3 attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "smashed") var/perunit = MINERAL_MATERIAL_AMOUNT - var/sheettype = null //this is used for girders in the creation of walls/false walls - - -// Since the sheetsnatcher was consolidated into weapon/storage/bag we now use -// item/attackby() properly, making this unnecessary - -/*/obj/item/stack/sheet/attackby(obj/item/weapon/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/storage/bag/sheetsnatcher)) - var/obj/item/weapon/storage/bag/sheetsnatcher/S = W - if(!S.mode) - S.add(src,user) - else - for (var/obj/item/stack/sheet/stack in locate(src.x,src.y,src.z)) - S.add(stack,user) - ..()*/ \ No newline at end of file + var/sheettype = null //this is used for girders in the creation of walls/false walls \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm index 92ebff9c716..7519804b005 100644 --- a/code/game/objects/items/weapons/storage/bags.dm +++ b/code/game/objects/items/weapons/storage/bags.dm @@ -335,3 +335,17 @@ ..() +/* + * Chemistry bag + */ + +/obj/item/weapon/storage/bag/chemistry + name = "chemistry bag" + icon = 'icons/obj/chemical.dmi' + icon_state = "bag" + desc = "A bag for storing pills, patches, and bottles." + storage_slots = 50 + max_combined_w_class = 200 + w_class = 1 + preposition = "in" + can_hold = list(/obj/item/weapon/reagent_containers/pill, /obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/reagent_containers/glass/bottle) diff --git a/code/game/objects/items/weapons/storage/book.dm b/code/game/objects/items/weapons/storage/book.dm index 9a71db5ab8d..5d5eb001840 100644 --- a/code/game/objects/items/weapons/storage/book.dm +++ b/code/game/objects/items/weapons/storage/book.dm @@ -68,11 +68,9 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", " /obj/item/weapon/storage/book/bible/proc/setupbiblespecifics(var/obj/item/weapon/storage/book/bible/B, var/mob/living/carbon/human/H) switch(B.icon_state) if("honk1","honk2") - new /obj/item/weapon/grown/bananapeel(B) - new /obj/item/weapon/grown/bananapeel(B) - - if(B.icon_state == "honk1") - H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask) + new /obj/item/weapon/bikehorn(B) + H.dna.add_mutation(CLOWNMUT) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask) if("bible") for(var/area/chapel/main/A in world) @@ -211,4 +209,4 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", " /obj/item/weapon/storage/book/bible/attackby(obj/item/weapon/W as obj, mob/user as mob, params) playsound(src.loc, "rustle", 50, 1, -5) - ..() \ No newline at end of file + ..() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index bae96ce7ef0..dde6cba1c31 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -1,6 +1,5 @@ /obj languages = HUMAN - //var/datum/module/mod //not used var/crit_fail = 0 var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj. animate_movement = 2 diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 85f3f7582bb..9de891501fa 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -68,7 +68,7 @@ return (!density) /obj/structure/closet/proc/can_open() - if(src.welded || src.locked) + if(welded || locked) return 0 return 1 @@ -81,32 +81,32 @@ /obj/structure/closet/proc/dump_contents() for(var/obj/O in src) - O.loc = src.loc + O.loc = loc for(var/mob/M in src) - M.loc = src.loc + M.loc = loc if(M.client) M.client.eye = M.client.mob M.client.perspective = MOB_PERSPECTIVE /obj/structure/closet/proc/take_contents() - for(var/atom/movable/AM in src.loc) + for(var/atom/movable/AM in loc) if(insert(AM) == -1) // limit reached break /obj/structure/closet/proc/open() - if(src.opened) + if(opened) return 0 - if(!src.can_open()) + if(!can_open()) return 0 - src.dump_contents() + dump_contents() - src.opened = 1 + opened = 1 if(istype(src, /obj/structure/closet/body_bag)) - playsound(src.loc, 'sound/items/zip.ogg', 15, 1, -3) + playsound(loc, 'sound/items/zip.ogg', 15, 1, -3) else - playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3) + playsound(loc, 'sound/machines/click.ogg', 15, 1, -3) density = 0 update_icon() return 1 @@ -139,25 +139,25 @@ return 1 /obj/structure/closet/proc/close() - if(!src.opened) + if(!opened) return 0 - if(!src.can_close()) + if(!can_close()) return 0 take_contents() - src.opened = 0 + opened = 0 if(istype(src, /obj/structure/closet/body_bag)) - playsound(src.loc, 'sound/items/zip.ogg', 15, 1, -3) + playsound(loc, 'sound/items/zip.ogg', 15, 1, -3) else - playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3) + playsound(loc, 'sound/machines/click.ogg', 15, 1, -3) density = 1 update_icon() return 1 /obj/structure/closet/proc/toggle() - if(src.opened) - return src.close() - return src.open() + if(opened) + return close() + return open() /obj/structure/closet/ex_act(severity, target) contents_explosion(severity, target) @@ -192,9 +192,9 @@ return if(opened) if(istype(W, /obj/item/weapon/grab)) - if(src.large) + if(large) var/obj/item/weapon/grab/G = W - src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet + MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet user.drop_item() else user << "The locker is too small to stuff [W] into!" @@ -210,7 +210,7 @@ if( !opened || !istype(src, /obj/structure/closet) || !user || !WT || !WT.isOn() || !user.loc ) return playsound(loc, 'sound/items/Welder2.ogg', 50, 1) - new /obj/item/stack/sheet/metal(src.loc) + new /obj/item/stack/sheet/metal(loc) visible_message("[user] has cut \the [src] apart with \the [WT].", "You hear welding.") qdel(src) return @@ -239,10 +239,10 @@ user << "The locker appears to be broken." return if(!place(user, W) && !isnull(W)) - src.attack_hand(user) + attack_hand(user) /obj/structure/closet/proc/place(var/mob/user, var/obj/item/I) - if(!src.opened && secure) + if(!opened && secure) togglelock(user) return 1 return 0 @@ -258,21 +258,21 @@ return 0 if(!istype(user.loc, /turf)) // are you in a container/closet/pod/etc? Will also check for null loc return 0 - if(needs_opened && !src.opened) + if(needs_opened && !opened) return 0 if(istype(O, /obj/structure/closet)) return 0 if(move_them) - step_towards(O, src.loc) + step_towards(O, loc) if(show_message && user != O) user.show_viewers("[user] stuffs [O] into [src]!") - src.add_fingerprint(user) + add_fingerprint(user) return 1 /obj/structure/closet/relaymove(mob/user as mob) - if(user.stat || !isturf(src.loc)) + if(user.stat || !isturf(loc)) return - if(!src.open()) + if(!open()) user << "It won't budge!" if(world.time > lastbang+5) lastbang = world.time @@ -281,19 +281,20 @@ /obj/structure/closet/attack_paw(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/structure/closet/attack_hand(mob/user as mob) - src.add_fingerprint(user) + add_fingerprint(user) if(user.lying && get_dist(src, user) > 0) return - if(!src.toggle()) - return src.attackby(null, user) + if(!toggle()) + user << "You cannot close the locker!" + return // tk grab then use on self /obj/structure/closet/attack_self_tk(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/structure/closet/verb/verb_toggleopen() set src in oview(1) @@ -304,7 +305,7 @@ return if(iscarbon(usr) || issilicon(usr)) - src.attack_hand(usr) + attack_hand(usr) else usr << "This mob type can't use this verb." @@ -322,7 +323,7 @@ if(istype(user.loc, /obj/structure/closet/critter) && !welded) breakout_time = 0.75 //45 seconds if it's an unwelded critter crate - if( opened || (!welded && !locked && !istype(src.loc, /obj/mecha)) ) + if( opened || (!welded && !locked && !istype(loc, /obj/mecha)) ) return //Door's open, not locked or welded or inside a mech, no point in resisting. //okay, so the closet is either welded or locked... resist!!! @@ -332,7 +333,7 @@ for(var/mob/O in viewers(src)) O << "[src] begins to shake violently!" if(do_after(user,(breakout_time*60*10))) //minutes * 60seconds * 10deciseconds - if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded && !istype(src.loc, /obj/mecha)) ) + if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded && !istype(loc, /obj/mecha)) ) return //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting @@ -340,11 +341,11 @@ locked = 0 //applies to critter crates and secure lockers only broken = 1 //applies to secure lockers only user.visible_message("[user] successfully broke out of [src]!", "You successfully break out of [src]!") - if(istype( src.loc, /obj/structure/bigDelivery)) - var/obj/structure/bigDelivery/D = src.loc + if(istype( loc, /obj/structure/bigDelivery)) + var/obj/structure/bigDelivery/D = loc qdel(D) - else if(istype( src.loc, /obj/mecha)) - src.loc = get_turf(src.loc) + else if(istype( loc, /obj/mecha)) + loc = get_turf(loc) open() else user << "You fail to break out of [src]!" @@ -354,7 +355,7 @@ if(!user.canUseTopic(user) || broken) user << "You can't do that right now!" return - if(src.opened || !secure || !in_range(src, user)) + if(opened || !secure || !in_range(src, user)) return else togglelock(user) @@ -364,20 +365,20 @@ O.emp_act(severity) if(secure && !broken) if(prob(50/severity)) - src.locked = !src.locked - src.update_icon() + locked = !locked + update_icon() if(prob(20/severity) && !opened) if(!locked) open() else - src.req_access = list() - src.req_access += pick(get_all_accesses()) + req_access = list() + req_access += pick(get_all_accesses()) ..() /obj/structure/closet/proc/togglelock(mob/user as mob) if(secure) - if(src.allowed(user)) - src.locked = !src.locked + if(allowed(user)) + locked = !locked add_fingerprint(user) for(var/mob/O in viewers(user, 3)) if((O.client && !( O.eye_blind ))) diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index a4510966df7..37433c2423c 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -311,6 +311,8 @@ new /obj/item/weapon/storage/backpack/chemistry(src) new /obj/item/weapon/storage/backpack/satchel_chem(src) new /obj/item/weapon/storage/backpack/satchel_chem(src) + new /obj/item/weapon/storage/bag/chemistry(src) + new /obj/item/weapon/storage/bag/chemistry(src) return diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 6eb5f7b9317..ffe58681ab0 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -106,7 +106,20 @@ name = "magic mirror" desc = "Turn and face the strange... face." icon_state = "magic_mirror" + var/list/races_blacklist = list("skeleton") + var/list/choosable_races = list() +/obj/structure/mirror/magic/New() + if(!choosable_races.len) + for(var/datum/species/S in typesof(/datum/species) - /datum/species) + if(!(S.id in races_blacklist)) + choosable_races += S + ..() + +/obj/structure/mirror/magic/badmin/New() + for(var/datum/species/S in typesof(/datum/species) - /datum/species) + choosable_races += S + ..() /obj/structure/mirror/magic/attack_hand(mob/user as mob) if(!ishuman(user)) @@ -130,7 +143,7 @@ if("race") var/newrace - var/racechoice = input(H, "What are we again?", "Race change") as null|anything in species_list + var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races newrace = species_list[racechoice] if(!newrace || !H.dna) diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index 4e44968971b..0b1f15d41b3 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -32,28 +32,37 @@ return if(istype(I, /obj/item/stack/sheet/plasteel)) var/obj/item/stack/sheet/plasteel/P = I + if(P.get_amount() < 1) + user << "You need one plasteel sheet to do this!" + return user << "You start adding [P] to [src]..." if(do_after(user, 50)) + P.use(1) new /obj/structure/table/reinforced(src.loc) qdel(src) - P.use(1) - return + return if(istype(I, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = I + if(M.get_amount() < 1) + user << "You need one metal sheet to do this!" + return user << "You start adding [M] to [src]..." if(do_after(user, 20)) + M.use(1) new /obj/structure/table(src.loc) qdel(src) - M.use(1) - return + return if(istype(I, /obj/item/stack/sheet/glass)) var/obj/item/stack/sheet/glass/G = I + if(G.get_amount() < 1) + user << "You need one glass sheet to do this!" + return user << "You start adding [G] to [src]..." if(do_after(user, 20)) + G.use(1) new /obj/structure/table/glass(src.loc) qdel(src) - G.use(1) - return + return /* * Wooden Frames @@ -71,17 +80,23 @@ ..() if(istype(I, /obj/item/stack/sheet/mineral/wood)) var/obj/item/stack/sheet/mineral/wood/W = I + if(W.get_amount() < 1) + user << "You need one wood sheet to do this!" + return user << "You start adding [W] to [src]..." if(do_after(user, 20)) + W.use(1) new /obj/structure/table/wood(src.loc) qdel(src) - W.use(1) - return + return if(istype(I, /obj/item/stack/tile/carpet)) var/obj/item/stack/tile/carpet/C = I + if(C.get_amount() < 1) + user << "You need one carpet sheet to do this!" + return user << "You start adding [C] to [src]..." if(do_after(user, 20)) + C.use(1) new /obj/structure/table/wood/poker(src.loc) qdel(src) - C.use(1) - return \ No newline at end of file + return \ No newline at end of file diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index b3a52450234..8262201bf28 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -29,7 +29,7 @@ /obj/structure/windoor_assembly/New(dir=NORTH) ..() - src.ini_dir = src.dir + ini_dir = dir air_update_turf(1) /obj/structure/windoor_assembly/Destroy() @@ -77,7 +77,7 @@ var/obj/item/weapon/weldingtool/WT = W if (WT.remove_fuel(0,user)) user.visible_message("[user] disassembles the windoor assembly.", "You start to disassemble the windoor assembly...") - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + playsound(loc, 'sound/items/Welder2.ogg', 50, 1) if(do_after(user, 40)) if(!src || !WT.isOn()) return @@ -93,41 +93,41 @@ //Wrenching an unsecure assembly anchors it in place. Step 4 complete if(istype(W, /obj/item/weapon/wrench) && !anchored) - for(var/obj/machinery/door/window/WD in src.loc) - if(WD.dir == src.dir) + for(var/obj/machinery/door/window/WD in loc) + if(WD.dir == dir) user << "There is already a windoor in that location!" return - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] secures the windoor assembly to the floor.", "You start to secure the windoor assembly to the floor...") if(do_after(user, 40)) - if(!src || src.anchored) + if(!src || anchored) return - for(var/obj/machinery/door/window/WD in src.loc) - if(WD.dir == src.dir) + for(var/obj/machinery/door/window/WD in loc) + if(WD.dir == dir) user << "There is already a windoor in that location!" return user << "You secure the windoor assembly." - src.anchored = 1 - if(src.secure) - src.name = "secure anchored windoor assembly" + anchored = 1 + if(secure) + name = "secure anchored windoor assembly" else - src.name = "anchored windoor assembly" + name = "anchored windoor assembly" //Unwrenching an unsecure assembly un-anchors it. Step 4 undone else if(istype(W, /obj/item/weapon/wrench) && anchored) - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] unsecures the windoor assembly to the floor.", "You start to unsecure the windoor assembly to the floor...") if(do_after(user, 40)) - if(!src || !src.anchored) + if(!src || !anchored) return user << "You unsecure the windoor assembly." - src.anchored = 0 - if(src.secure) - src.name = "secure windoor assembly" + anchored = 0 + if(secure) + name = "secure windoor assembly" else - src.name = "windoor assembly" + name = "windoor assembly" //Adding plasteel makes the assembly a secure windoor assembly. Step 2 (optional) complete. else if(istype(W, /obj/item/stack/sheet/plasteel) && !secure) @@ -143,27 +143,29 @@ P.use(2) user << "You reinforce the windoor." - src.secure = 1 - if(src.anchored) - src.name = "secure anchored windoor assembly" + secure = 1 + if(anchored) + name = "secure anchored windoor assembly" else - src.name = "secure windoor assembly" + name = "secure windoor assembly" //Adding cable to the assembly. Step 5 complete. else if(istype(W, /obj/item/stack/cable_coil) && anchored) user.visible_message("[user] wires the windoor assembly.", "You start to wire the windoor assembly...") if(do_after(user, 40)) - if(!src || !src.anchored || src.state != "01") + if(!src || !anchored || state != "01") return var/obj/item/stack/cable_coil/CC = W - CC.use(1) + if(!CC.use(1)) + user << "You need more cable to do this!" + return user << "You wire the windoor." - src.state = "02" - if(src.secure) - src.name = "secure wired windoor assembly" + state = "02" + if(secure) + name = "secure wired windoor assembly" else - src.name = "wired windoor assembly" + name = "wired windoor assembly" else ..() @@ -171,61 +173,61 @@ //Removing wire from the assembly. Step 5 undone. if(istype(W, /obj/item/weapon/wirecutters)) - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly...") if(do_after(user, 40)) - if(!src || src.state != "02") + if(!src || state != "02") return user << "You cut the windoor wires." new/obj/item/stack/cable_coil(get_turf(user), 1) - src.state = "01" - if(src.secure) - src.name = "secure anchored windoor assembly" + state = "01" + if(secure) + name = "secure anchored windoor assembly" else - src.name = "anchored windoor assembly" + name = "anchored windoor assembly" //Adding airlock electronics for access. Step 6 complete. else if(istype(W, /obj/item/weapon/airlock_electronics)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly...") user.drop_item() W.loc = src if(do_after(user, 40)) - if(!src || src.electronics) - W.loc = src.loc + if(!src || electronics) + W.loc = loc return user << "You install the airlock electronics." - src.name = "near finished windoor assembly" - src.electronics = W + name = "near finished windoor assembly" + electronics = W else - W.loc = src.loc + W.loc = loc //Screwdriver to remove airlock electronics. Step 6 undone. else if(istype(W, /obj/item/weapon/screwdriver)) if(!electronics) return - playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1) user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to uninstall electronics from the airlock assembly...") if(do_after(user, 40)) if(!src || !electronics) return user << "You remove the airlock electronics." - src.name = "wired windoor assembly" + name = "wired windoor assembly" var/obj/item/weapon/airlock_electronics/ae ae = electronics electronics = null - ae.loc = src.loc + ae.loc = loc else if(istype(W, /obj/item/weapon/pen)) - var/t = stripped_input(user, "Enter the name for the door.", src.name, src.created_name,MAX_NAME_LEN) + var/t = stripped_input(user, "Enter the name for the door.", name, created_name,MAX_NAME_LEN) if(!t) return - if(!in_range(src, usr) && src.loc != usr) + if(!in_range(src, usr) && loc != usr) return created_name = t return @@ -234,37 +236,37 @@ //Crowbar to complete the assembly, Step 7 complete. else if(istype(W, /obj/item/weapon/crowbar)) - if(!src.electronics) + if(!electronics) usr << "The assembly is missing electronics!" return usr << browse(null, "window=windoor_access") - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + playsound(loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] pries the windoor into the frame.", "You start prying the windoor into the frame...") if(do_after(user, 40)) - if(src.loc && src.electronics) + if(loc && electronics) density = 1 //Shouldn't matter but just incase user << "You finish the windoor." if(secure) - var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(src.loc) - if(src.facing == "l") + var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(loc) + if(facing == "l") windoor.icon_state = "leftsecureopen" windoor.base_state = "leftsecure" else windoor.icon_state = "rightsecureopen" windoor.base_state = "rightsecure" - windoor.dir = src.dir + windoor.dir = dir windoor.density = 0 - if(src.electronics.use_one_access) - windoor.req_one_access = src.electronics.conf_access + if(electronics.use_one_access) + windoor.req_one_access = electronics.conf_access else - windoor.req_access = src.electronics.conf_access - windoor.electronics = src.electronics - src.electronics.loc = windoor + windoor.req_access = electronics.conf_access + windoor.electronics = electronics + electronics.loc = windoor if(created_name) windoor.name = created_name qdel(src) @@ -272,19 +274,19 @@ else - var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(src.loc) - if(src.facing == "l") + var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(loc) + if(facing == "l") windoor.icon_state = "leftopen" windoor.base_state = "left" else windoor.icon_state = "rightopen" windoor.base_state = "right" - windoor.dir = src.dir + windoor.dir = dir windoor.density = 0 - windoor.req_access = src.electronics.conf_access - windoor.electronics = src.electronics - src.electronics.loc = windoor + windoor.req_access = electronics.conf_access + windoor.electronics = electronics + electronics.loc = windoor if(created_name) windoor.name = created_name qdel(src) @@ -305,18 +307,18 @@ set src in oview(1) if(usr.stat || !usr.canmove || usr.restrained()) return - if (src.anchored) + if (anchored) usr << "It is fastened to the floor; therefore, you can't rotate it!" return 0 - //if(src.state != "01") + //if(state != "01") //update_nearby_tiles(need_rebuild=1) //Compel updates before - src.dir = turn(src.dir, 270) + dir = turn(dir, 270) - //if(src.state != "01") + //if(state != "01") //update_nearby_tiles(need_rebuild=1) - src.ini_dir = src.dir + ini_dir = dir update_icon() return @@ -328,11 +330,11 @@ if(usr.stat || !usr.canmove || usr.restrained()) return - if(src.facing == "l") + if(facing == "l") usr << "The windoor will now slide to the right." - src.facing = "r" + facing = "r" else - src.facing = "l" + facing = "l" usr << "The windoor will now slide to the left." update_icon() diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 6e565879c9f..25f2ec88ecb 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -105,6 +105,28 @@ ChangeTurf(/turf/simulated/floor/plating) return + +/turf/simulated/floor/engine/ex_act(severity,target) + switch(severity) + if(1.0) + if(prob(80)) + ReplaceWithLattice() + else if(prob(50)) + qdel(src) + else + make_plating(1) + if(2.0) + if(prob(50)) + make_plating(1) + + +/turf/simulated/floor/engine/cult + name = "engraved floor" + icon_state = "cult" + +/turf/simulated/floor/engine/cult/narsie_act() + return + /turf/simulated/floor/engine/n20/New() ..() var/datum/gas_mixture/adding = new diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index af5a84bdc3c..2829c18e6c9 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -6,6 +6,7 @@ opacity = 1 density = 1 blocks_air = 1 + explosion_block = 1 thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index c61a20cb100..fb73c1f61c6 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -17,6 +17,7 @@ mineral = "gold" //var/electro = 1 //var/shocked = null + explosion_block = 0 //gold is a soft metal you dingus. /turf/simulated/wall/mineral/silver name = "silver wall" @@ -34,6 +35,7 @@ walltype = "diamond" mineral = "diamond" slicing_duration = 200 //diamond wall takes twice as much time to slice + explosion_block = 3 /turf/simulated/wall/mineral/diamond/thermitemelt(mob/user as mob) return @@ -51,6 +53,7 @@ icon_state = "sandstone0" walltype = "sandstone" mineral = "sandstone" + explosion_block = 0 /turf/simulated/wall/mineral/uranium name = "uranium wall" @@ -143,3 +146,4 @@ walltype = "wood" mineral = "wood" hardness = 70 + explosion_block = 0 \ No newline at end of file diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm index aec87adc748..00f6f38825f 100644 --- a/code/game/turfs/simulated/walls_reinforced.dm +++ b/code/game/turfs/simulated/walls_reinforced.dm @@ -10,6 +10,7 @@ var/d_state = 0 hardness = 10 sheet_type = /obj/item/stack/sheet/plasteel + explosion_block = 2 /turf/simulated/wall/r_wall/break_wall() builtin_sheet.loc = src diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 740ec63b06e..1c073505ab8 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -10,6 +10,7 @@ var/list/admin_verbs_default = list( /client/proc/deadchat, /*toggles deadchat on/off*/ /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ /client/proc/toggleprayers, /*toggles prayers on/off*/ + /client/verb/toggleprayersounds, /*Toggles prayer sounds (HALLELUJAH!)*/ /client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/ /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ /client/proc/secrets, @@ -120,7 +121,9 @@ var/list/admin_verbs_debug = list( /client/proc/SDQL2_query, /client/proc/test_movable_UI, /client/proc/test_snap_UI, - /client/proc/debugNatureMapGenerator + /client/proc/debugNatureMapGenerator, + /client/proc/check_bomb_impacts, + /proc/machine_upgrade ) var/list/admin_verbs_possess = list( /proc/possess, @@ -547,7 +550,7 @@ var/list/admin_verbs_hideable = list( var/list/Lines = file2list("config/admins.txt") for(var/line in Lines) var/list/splitline = text2list(line, " = ") - if(splitline[1] == ckey) + if(lowertext(splitline[1]) == ckey) if(splitline.len >= 2) rank = ckeyEx(splitline[2]) break diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 334190fbd20..14d8693c3e5 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -307,7 +307,7 @@ if(ratio) config.midround_antag_life_check = ratio/100 - message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio * 100]% alive.") + message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio]% alive.") check_antagonists() else if(href_list["toggle_noncontinuous_behavior"]) @@ -1605,6 +1605,7 @@ message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]") feedback_inc("admin_cookies_spawned",1) H << "Your prayers have been answered!! You received the best cookie!" + H << 'sound/effects/pray_chaplain.ogg' else if(href_list["BlueSpaceArtillery"]) var/mob/living/M = locate(href_list["BlueSpaceArtillery"]) diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm index 767f30e1380..d06bd7e61c8 100644 --- a/code/modules/admin/verbs/buildmode.dm +++ b/code/modules/admin/verbs/buildmode.dm @@ -1,3 +1,10 @@ +#define BASIC_BUILDMODE 1 +#define ADV_BUILDMODE 2 +#define VAR_BUILDMODE 3 +#define THROW_BUILDMODE 4 +#define AREA_BUILDMODE 5 +#define NUM_BUILDMODES 5 + /proc/togglebuildmode(mob/M as mob in player_list) set name = "Toggle Build Mode" set category = "Special Verbs" @@ -35,7 +42,7 @@ M.client.screen += D H.cl = M.client -/obj/effect/bmode//Cleaning up the tree a bit +/obj/effect/bmode //Cleaning up the tree a bit density = 1 anchored = 1 layer = 20 @@ -68,7 +75,7 @@ /obj/effect/bmode/buildhelp/Click() switch(master.cl.buildmode) - if(1) + if(BASIC_BUILDMODE) usr << "\blue ***********************************************************" usr << "\blue Left Mouse Button = Construct / Upgrade" usr << "\blue Right Mouse Button = Deconstruct / Delete / Downgrade" @@ -78,7 +85,7 @@ usr << "\blue Use the button in the upper left corner to" usr << "\blue change the direction of built objects." usr << "\blue ***********************************************************" - if(2) + if(ADV_BUILDMODE) usr << "\blue ***********************************************************" usr << "\blue Right Mouse Button on buildmode button = Set object type" usr << "\blue Left Mouse Button on turf/obj = Place objects" @@ -87,17 +94,23 @@ usr << "\blue Use the button in the upper left corner to" usr << "\blue change the direction of built objects." usr << "\blue ***********************************************************" - if(3) + if(VAR_BUILDMODE) usr << "\blue ***********************************************************" usr << "\blue Right Mouse Button on buildmode button = Select var(type) & value" usr << "\blue Left Mouse Button on turf/obj/mob = Set var(type) & value" usr << "\blue Right Mouse Button on turf/obj/mob = Reset var's value" usr << "\blue ***********************************************************" - if(4) + if(THROW_BUILDMODE) usr << "\blue ***********************************************************" usr << "\blue Left Mouse Button on turf/obj/mob = Select" usr << "\blue Right Mouse Button on turf/obj/mob = Throw" usr << "\blue ***********************************************************" + if(AREA_BUILDMODE) + usr << "\blue ***********************************************************" + usr << "\blue Left Mouse Button on turf/obj/mob = Select corner" + usr << "\blue Right Mouse Button on buildmode button = Select generator" + usr << "\blue ***********************************************************" + return 1 /obj/effect/bmode/buildquit @@ -117,6 +130,13 @@ var/obj/effect/bmode/buildmode/buildmode = null var/obj/effect/bmode/buildquit/buildquit = null var/atom/movable/throw_atom = null + var/turf/cornerA = null + var/turf/cornerB = null + var/generator_path = null + +/obj/effect/bmode/buildholder/proc/Reset()//Reset temporary variables + cornerA = null + cornerB = null /obj/effect/bmode/buildmode icon_state = "buildmode1" @@ -129,25 +149,15 @@ var/list/pa = params2list(params) if(pa.Find("left")) - switch(master.cl.buildmode) - if(1) - master.cl.buildmode = 2 - src.icon_state = "buildmode2" - if(2) - master.cl.buildmode = 3 - src.icon_state = "buildmode3" - if(3) - master.cl.buildmode = 4 - src.icon_state = "buildmode4" - if(4) - master.cl.buildmode = 1 - src.icon_state = "buildmode1" + master.cl.buildmode = (master.cl.buildmode % NUM_BUILDMODES) +1 + master.Reset() + src.icon_state = "buildmode[master.cl.buildmode]" else if(pa.Find("right")) switch(master.cl.buildmode) - if(1) + if(BASIC_BUILDMODE) return 1 - if(2) + if(ADV_BUILDMODE) objholder = text2path(input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet")) if(!ispath(objholder)) objholder = /obj/structure/closet @@ -155,7 +165,7 @@ else if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0)) objholder = /obj/structure/closet - if(3) + if(VAR_BUILDMODE) var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine") master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name") @@ -174,6 +184,16 @@ master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world if("turf-reference") master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world + if(AREA_BUILDMODE) + var/list/gen_paths = typesof(/datum/mapGenerator) - /datum/mapGenerator + + var/type = input(usr,"Select Generator Type","Type") as null|anything in gen_paths + if(!type) return + + master.generator_path = type + master.cornerA = null + master.cornerB = null + return 1 @@ -186,8 +206,11 @@ if(!holder) return var/list/pa = params2list(params) + if(istype(object,/obj/effect/bmode)) + return + switch(buildmode) - if(1) + if(BASIC_BUILDMODE) if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") ) var/turf/T = object if(istype(object,/turf/space)) @@ -233,7 +256,7 @@ var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) WIN.dir = NORTHWEST log_admin("Build Mode: [key_name(usr)] built a window at ([object.x],[object.y],[object.z])") - if(2) + if(ADV_BUILDMODE) if(pa.Find("left")) if(ispath(holder.buildmode.objholder,/turf)) var/turf/T = get_turf(object) @@ -248,7 +271,7 @@ log_admin("Build Mode: [key_name(usr)] deleted [object] at ([object.x],[object.y],[object.z])") qdel(object) - if(3) + if(VAR_BUILDMODE) if(pa.Find("left")) //I cant believe this shit actually compiles. if(object.vars.Find(holder.buildmode.varholder)) log_admin("Build Mode: [key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]") @@ -262,7 +285,7 @@ else usr << "[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'" - if(4) + if(THROW_BUILDMODE) if(pa.Find("left")) if(isturf(object)) return @@ -271,4 +294,35 @@ if(holder.throw_atom) holder.throw_atom.throw_at(object, 10, 1) log_admin("Build Mode: [key_name(usr)] threw [holder.throw_atom] at [object] ([object.x],[object.y],[object.z])") - + if(AREA_BUILDMODE) + if(!holder.cornerA) + holder.cornerA = get_turf(object) + return + if(holder.cornerA && !holder.cornerB) + holder.cornerB = get_turf(object) + + if(pa.Find("left")) //rectangular + if(holder.cornerA && holder.cornerB) + if(!holder.generator_path) + usr << "Select generator type first." + var/datum/mapGenerator/G = new holder.generator_path + G.defineRegion(holder.cornerA,holder.cornerB,1) + G.generate() + holder.cornerA = null + holder.cornerB = null + return + /* Something wrong with this, will check later + if(pa.Find("right")) // circular + if(holder.cornerA && holder.cornerB) + if(!holder.generator_path) + usr << "Select generator type first." + var/datum/mapGenerator/G = new holder.generator_path + G.defineCircularRegion(holder.cornerA,holder.cornerB,1) + G.generate() + holder.cornerA = null + holder.cornerB = null + return + */ + //Something wrong - Reset + holder.cornerA = null + holder.cornerB = null \ No newline at end of file diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index dac9d8d47ac..02aac7f6db8 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1091,6 +1091,8 @@ var/global/list/g_fancy_list_of_types = null usr << browse(dat, "window=dellog") + + //Deathsquad /proc/equip_deathsquad(var/mob/living/carbon/human/M, var/officer) var/obj/item/device/radio/R = new /obj/item/device/radio/headset/headset_cent/alt(M) diff --git a/code/modules/admin/verbs/machine_upgrade.dm b/code/modules/admin/verbs/machine_upgrade.dm new file mode 100644 index 00000000000..9c1089c5fff --- /dev/null +++ b/code/modules/admin/verbs/machine_upgrade.dm @@ -0,0 +1,10 @@ +/proc/machine_upgrade(obj/machinery/M as obj in world) + set name = "Tweak Component Ratings" + set category = "Debug" + var/new_rating = input("Enter new rating:","Num") as num + if(new_rating && M.component_parts) + for(var/obj/item/weapon/stock_parts/P in M.component_parts) + P.rating = new_rating + M.RefreshParts() + + feedback_add_details("admin_verb","MU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index f14df6a3fc9..3125067f32b 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -142,15 +142,33 @@ var/list/VVckey_edit = list("key", "ckey") if(confirm != "Continue") return - var/list/names = sortList(L) + var/assoc = 0 + if(L.len > 0) + var/a = L[1] + if(istext(a) && L[a] != null) + assoc = 1 //This is pretty weak test but i can't think of anything else + usr << "List appears to be associative." - var/variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" + var/list/names = null + if(!assoc) + names = sortList(L) + + var/variable + var/assoc_key + if(assoc) + variable = input("Which var?","Var") as null|anything in L + "(ADD VAR)" + else + variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)" if(variable == "(ADD VAR)") mod_list_add(L, O, original_name, objectvar) return - if(!variable) + if(assoc) + assoc_key = variable + variable = L[assoc_key] + + if(!assoc && !variable || assoc && !assoc_key) return var/default @@ -240,7 +258,12 @@ var/list/VVckey_edit = list("key", "ckey") if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])") class = "marked datum" - var/original_var = L[L.Find(variable)] + var/original_var + if(assoc) + original_var = L[assoc_key] + else + original_var = L[L.Find(variable)] + var/new_var switch(class) //Spits a runtime error if you try to modify an entry in the contents list. Dunno how to fix it, yet. @@ -249,7 +272,10 @@ var/list/VVckey_edit = list("key", "ckey") if("restore to default") new_var = initial(variable) - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("edit referenced object") modify_variables(variable) @@ -263,35 +289,59 @@ var/list/VVckey_edit = list("key", "ckey") if("text") new_var = input("Enter new text:","Text") as text - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("num") new_var = input("Enter new number:","Num") as num - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("type") new_var = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("reference") new_var = input("Select reference:","Reference") as mob|obj|turf|area in world - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("mob reference") new_var = input("Select reference:","Reference") as mob in world - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("file") new_var = input("Pick file:","File") as file - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("icon") new_var = input("Pick icon:","Icon") as icon - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var if("marked datum") new_var = holder.marked_datum - L[L.Find(variable)] = new_var + if(assoc) + L[assoc_key] = new_var + else + L[L.Find(variable)] = new_var world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: [original_var]=[new_var]" log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]") @@ -539,4 +589,4 @@ var/list/VVckey_edit = list("key", "ckey") world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]" log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]") - message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]") \ No newline at end of file + message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]") diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 85fb049bd4d..5671bd85046 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -17,11 +17,21 @@ return var/image/cross = image('icons/obj/storage.dmi',"bible") - msg = "\icon[cross] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]" - + if(usr.job == "Chaplain") + cross = image('icons/obj/storage.dmi',"kingyellow") + msg = "\icon[cross] CHAPLAIN PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]" + else if(iscultist(usr)) + cross = image('icons/obj/storage.dmi',"tome") + msg = "\icon[cross] CULTIST PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]" + else + cross = image('icons/obj/storage.dmi',"bible") + msg = "\icon[cross] PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]" for(var/client/C in admins) if(C.prefs.chat_toggles & CHAT_PRAYER) C << msg + if(C.prefs.toggles & SOUND_PRAYERS) + if(usr.job == "Chaplain") + C << 'sound/effects/pray.ogg' usr << "Your prayers have been received by the gods." feedback_add_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 5d5aefac0be..1769315acab 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -21,6 +21,7 @@ attach(A2,user) name = "[A.name]-[A2.name] assembly" update_icon() + feedback_add_details("assembly_made","[name]") /obj/item/device/assembly_holder/proc/attach(var/obj/item/device/assembly/A, var/mob/user) if(!A.remove_item_from_storage(src)) diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index db9fbce26e5..99218130f57 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -82,6 +82,18 @@ src << "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat." feedback_add_details("admin_verb","TP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/verb/toggleprayersounds() + set name = "Hear/Silence Prayer Sounds" + set category = "Preferences" + set desc = "Toggles hearing pray sounds." + prefs.toggles ^= SOUND_PRAYERS + prefs.save_preferences() + if(prefs.toggles & SOUND_PRAYERS) + src << "You will now hear prayer sounds." + else + src << "You will no longer prayer sounds." + feedback_add_details("admin_verb", "PSounds") + /client/verb/togglePRs() set name = "Show/Hide Pull Request Announcements" set category = "Preferences" @@ -208,7 +220,8 @@ var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \ "ghost_blue","ghost_yellow","ghost_green","ghost_pink", \ "ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \ - "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink") + "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\ + "ghost_mellow","ghost_rainbow","ghost_camo","ghost_fire") /client/verb/pick_form() set name = "Choose Ghost Form" set category = "Preferences" diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index 2aecf9f789b..dd22a1e9f5c 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -19,6 +19,11 @@ desc = "Strange-looking yellow hat-wear that most certainly belongs to a powerful magic user." icon_state = "yellowwizard" +/obj/item/clothing/head/wizard/black + name = "black wizard hat" + desc = "Strange-looking black hat-wear that most certainly belongs to a real skeleton. Spooky." + icon_state = "blackwizard" + /obj/item/clothing/head/wizard/fake name = "wizard hat" desc = "It has WIZZARD written across it in sequins. Comes with a cool beard." @@ -72,6 +77,12 @@ icon_state = "yellowwizard" item_state = "yellowwizrobe" +/obj/item/clothing/suit/wizrobe/black + name = "black wizard robe" + desc = "An unnerving black gem-lined robe that reeks of death and decay." + icon_state = "blackwizard" + item_state = "blackwizrobe" + /obj/item/clothing/suit/wizrobe/marisa name = "witch robe" desc = "Magic is all about the spell power, ZE!" diff --git a/code/modules/crafting/table.dm b/code/modules/crafting/table.dm index 75847c323f4..7f6e111599a 100644 --- a/code/modules/crafting/table.dm +++ b/code/modules/crafting/table.dm @@ -78,6 +78,7 @@ /obj/structure/table/proc/construct_item(mob/user, datum/table_recipe/R) check_table() + var/send_feedback = 1 if(check_contents(R) && check_tools(user, R)) if(do_after(user, R.time)) if(!check_contents(R) || !check_tools(user, R)) @@ -86,6 +87,8 @@ if(istype(I, /obj/item/weapon/reagent_containers/food/snacks)) var/obj/item/weapon/reagent_containers/food/snacks/S = I S.create_reagents(S.volume) + feedback_add_details("food_made","[S.name]") + send_feedback = 0 var/list/parts = del_reqs(R, I) for(var/A in parts) if(istype(A, /obj/item)) @@ -98,6 +101,8 @@ I.reagents = new /datum/reagents() I.reagents.reagent_list.Add(A) I.CheckParts() + if(send_feedback) + feedback_add_details("object_crafted","[I.name]") return 1 return 0 diff --git a/code/modules/events/camerafailure.dm b/code/modules/events/camerafailure.dm new file mode 100644 index 00000000000..458b50e9a83 --- /dev/null +++ b/code/modules/events/camerafailure.dm @@ -0,0 +1,20 @@ +/datum/round_event_control/camera_failure + name = "Camera Failure" + typepath = /datum/round_event/camera_failure + weight = 100 + max_occurrences = 20 + alertadmins = 0 + +/datum/round_event/camera_failure + startWhen = 1 + endWhen = 2 + announceWhen = 0 + +/datum/round_event/camera_failure/tick() + var/iterations = 1 + var/obj/machinery/camera/C = pick(cameranet.cameras) + while(prob(round(100/iterations))) + while(!("SS13" in C.network)) + C = pick(cameranet.cameras) + C.deactivate(null, 0) + iterations *= 2.5 diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm index 3dad124aabe..078f7dab63b 100644 --- a/code/modules/events/dust.dm +++ b/code/modules/events/dust.dm @@ -1,12 +1,11 @@ /datum/round_event_control/meteor_wave/dust name = "Minor Space Dust" typepath = /datum/round_event/meteor_wave/dust - weight = 300 + weight = 200 max_occurrences = 1000 earliest_start = 0 alertadmins = 0 - /datum/round_event/meteor_wave/dust startWhen = 1 endWhen = 2 @@ -19,4 +18,4 @@ spawn_meteors(1, meteorsC) /datum/round_event/meteor_wave/dust/tick() - return \ No newline at end of file + return diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm index e9661d5dc7c..07dbff7d269 100644 --- a/code/modules/events/event.dm +++ b/code/modules/events/event.dm @@ -28,6 +28,7 @@ return PROCESS_KILL var/datum/round_event/E = new typepath() E.control = src + feedback_add_details("event_ran","[E]") occurrences++ testing("[time2text(world.time, "hh:mm:ss")] [E.type]") diff --git a/code/modules/food&drinks/kitchen machinery/gibber.dm b/code/modules/food&drinks/kitchen machinery/gibber.dm index 38a52ffa9ff..e5111bfb000 100644 --- a/code/modules/food&drinks/kitchen machinery/gibber.dm +++ b/code/modules/food&drinks/kitchen machinery/gibber.dm @@ -9,7 +9,9 @@ var/operating = 0 //Is it on? var/dirty = 0 // Does it need cleaning? var/gibtime = 40 // Time from starting until meat appears - var/typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/ + var/typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human + var/meat_produced = 0 + var/ignore_clothing = 0 use_power = 1 idle_power_usage = 2 active_power_usage = 500 @@ -47,6 +49,21 @@ /obj/machinery/gibber/New() ..() src.overlays += image('icons/obj/kitchen.dmi', "grjam") + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/gibber(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + RefreshParts() + +/obj/machinery/gibber/RefreshParts() + var/gib_time = 40 + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + meat_produced += 3 * B.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + gib_time -= 5 * M.rating + gibtime = gib_time + if(M.rating >= 2) + ignore_clothing = 1 /obj/machinery/gibber/update_icon() overlays.Cut() @@ -77,29 +94,43 @@ else src.startgibbing(user) -/obj/machinery/gibber/attackby(obj/item/weapon/grab/G as obj, mob/user as mob, params) - if(default_unfasten_wrench(user, G)) +/obj/machinery/gibber/attackby(obj/item/P as obj, mob/user as mob, params) + if (istype(P, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = P + if(!istype(G.affecting, /mob/living/carbon/)) + user << "This item is not suitable for the gibber!" + return + if(G.affecting.abiotic(1) && !ignore_clothing) + user << "Subject may not have abiotic items on." + return + + user.visible_message("[user] starts to put [G.affecting] into the gibber!") + src.add_fingerprint(user) + if(do_after(user, gibtime) && G && G.affecting && !occupant) + user.visible_message("[user] stuffs [G.affecting] into the gibber!") + var/mob/M = G.affecting + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + qdel(G) + update_icon() + + if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", P)) return - if (!( istype(G, /obj/item/weapon/grab)) || !(istype(G.affecting, /mob/living/carbon/human))) - user << "This item is not suitable for the gibber!" - return - if(G.affecting.abiotic(1)) - user << "Subject may not have abiotic items on." + if(exchange_parts(user, P)) return - user.visible_message("[user] starts to put [G.affecting] into the gibber!") - src.add_fingerprint(user) - if(do_after(user, 30) && G && G.affecting && !occupant) - user.visible_message("[user] stuffs [G.affecting] into the gibber!") - var/mob/M = G.affecting - if(M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - M.loc = src - src.occupant = M - qdel(G) - update_icon() + if(default_pry_open(P)) + return + + if(default_unfasten_wrench(user, P)) + return + + default_deconstruction_crowbar(P) + /obj/machinery/gibber/verb/eject() @@ -125,15 +156,21 @@ return use_power(1000) visible_message("You hear a loud squelchy grinding sound.") + playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1) src.operating = 1 update_icon() + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking var/sourcename = src.occupant.real_name - var/sourcejob = src.occupant.job + var/sourcejob + if(ishuman(occupant)) + var/mob/living/carbon/human/gibee = occupant + sourcejob = gibee.job var/sourcenutriment = src.occupant.nutrition / 15 var/sourcetotalreagents = src.occupant.reagents.total_volume - var/totalslabs = 3 + var/gibtype = /obj/effect/decal/cleanable/blood/gibs - var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/allmeat[totalslabs] + var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/allmeat[meat_produced] if(ishuman(occupant)) var/mob/living/carbon/human/gibee = occupant @@ -141,13 +178,19 @@ typeofmeat = gibee.dna.species.meat else typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human - for (var/i=1 to totalslabs) - var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/newmeat = new typeofmeat + else + if(iscarbon(occupant)) + var/mob/living/carbon/C = occupant + typeofmeat = C.type_of_meat + gibtype = C.gib_type + for (var/i=1 to meat_produced) + var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/newmeat = new typeofmeat newmeat.name = sourcename + newmeat.name newmeat.subjectname = sourcename - newmeat.subjectjob = sourcejob - newmeat.reagents.add_reagent ("nutriment", sourcenutriment / totalslabs) // Thehehe. Fat guys go first - src.occupant.reagents.trans_to (newmeat, round (sourcetotalreagents / totalslabs, 1)) // Transfer all the reagents from the + if(sourcejob) + newmeat.subjectjob = sourcejob + newmeat.reagents.add_reagent ("nutriment", sourcenutriment / meat_produced) // Thehehe. Fat guys go first + src.occupant.reagents.trans_to (newmeat, round (sourcetotalreagents / meat_produced, 1)) // Transfer all the reagents from the allmeat[i] = newmeat add_logs(user, occupant, "gibbed") @@ -157,13 +200,17 @@ spawn(src.gibtime) playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) operating = 0 - for (var/i=1 to totalslabs) + for (var/i=1 to meat_produced) + var/list/nearby_turfs = orange(3, get_turf(src)) var/obj/item/meatslab = allmeat[i] - var/turf/Tx = locate(src.x - i, src.y, src.z) meatslab.loc = src.loc - meatslab.throw_at(Tx,i,3) - if (!Tx.density) - new /obj/effect/decal/cleanable/blood/gibs(Tx,i) + meatslab.throw_at(pick(nearby_turfs),i,3) + for (var/turfs=1 to meat_produced*3) + var/turf/gibturf = pick(nearby_turfs) + if (!gibturf.density && src in viewers(gibturf)) + new gibtype(gibturf,i) + + pixel_x = initial(pixel_x) //return to its spot after shaking src.operating = 0 update_icon() diff --git a/code/modules/food&drinks/kitchen machinery/microwave.dm b/code/modules/food&drinks/kitchen machinery/microwave.dm index ff196ae88db..b04ac183825 100644 --- a/code/modules/food&drinks/kitchen machinery/microwave.dm +++ b/code/modules/food&drinks/kitchen machinery/microwave.dm @@ -12,7 +12,7 @@ var/operating = 0 // Is it on? var/dirty = 0 // = {0..100} Does it need cleaning? var/broken = 0 // ={0,1,2} How broken is it??? - var/global/max_n_of_items = 10 + var/max_n_of_items = 10 // whatever fat fuck made this a global var needs to look at themselves in the mirror sometime var/efficiency = 0 var/microwavepower = 1 @@ -28,15 +28,20 @@ component_parts = list() component_parts += new /obj/item/weapon/circuitboard/microwave(null) component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) component_parts += new /obj/item/weapon/stock_parts/console_screen(null) component_parts += new /obj/item/stack/cable_coil(null, 2) RefreshParts() /obj/machinery/microwave/RefreshParts() var/E + var/max_items = 10 for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts) E += M.rating + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + max_items = 10 * M.rating efficiency = E + max_n_of_items = max_items /******************* * Item Adding @@ -246,6 +251,7 @@ if(F.cooked_type) var/obj/item/weapon/reagent_containers/food/snacks/S = new F.cooked_type (get_turf(src)) F.initialize_cooked_food(S, efficiency) + feedback_add_details("food_made","[F.name]") else new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src) if(dirty < 100) diff --git a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm index 7d709d9cf8f..bb88e5ec867 100644 --- a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm +++ b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm @@ -10,12 +10,44 @@ idle_power_usage = 5 active_power_usage = 50 var/grinded = 0 + var/required_grind = 5 + var/cube_production = 1 +/obj/machinery/monkey_recycler/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/monkey_recycler(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + RefreshParts() + +/obj/machinery/monkey_recycler/RefreshParts() + var/req_grind = 5 + var/cubes_made = 1 + for(var/obj/item/weapon/stock_parts/manipulator/B in component_parts) + req_grind -= B.rating + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + cubes_made = M.rating + cube_production = cubes_made + required_grind = req_grind + /obj/machinery/monkey_recycler/attackby(var/obj/item/O as obj, var/mob/user as mob, params) - if(default_unfasten_wrench(user, O)) + if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O)) return + if(exchange_parts(user, O)) + return + + if(default_pry_open(O)) + return + + if(default_unfasten_wrench(user, O)) + power_change() + return + + default_deconstruction_crowbar(O) + if (src.stat != 0) //NOPOWER etc return if (istype(O, /obj/item/weapon/grab)) @@ -32,8 +64,12 @@ qdel(target) user << "You stuff the monkey in the machine." playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1) + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking use_power(500) src.grinded++ + sleep(50) + pixel_x = initial(pixel_x) //return to its spot after shaking user << "The machine now has [grinded] monkey\s worth of material stored." else @@ -43,12 +79,13 @@ /obj/machinery/monkey_recycler/attack_hand(var/mob/user as mob) if (src.stat != 0) //NOPOWER etc return - if(grinded >= 5) + if(grinded >= required_grind) user << "The machine hisses loudly as it condenses the grinded monkey meat. After a moment, it dispenses a brand new monkey cube." playsound(src.loc, 'sound/machines/hiss.ogg', 50, 1) - grinded -= 5 - new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped(src.loc) + grinded -= required_grind + for(var/i = 0, i < cube_production, i++) + new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped(src.loc) user << "The machine's display flashes that it has [grinded] monkeys worth of material left." else - user << "The machine needs at least 5 monkeys worth of material to produce a monkey cube. It only has [grinded]." + user << "The machine needs at least [required_grind] monkey(s) worth of material to produce a monkey cube. It only has [grinded]." return diff --git a/code/modules/food&drinks/kitchen machinery/processor.dm b/code/modules/food&drinks/kitchen machinery/processor.dm index cde0bf70683..78038266d98 100644 --- a/code/modules/food&drinks/kitchen machinery/processor.dm +++ b/code/modules/food&drinks/kitchen machinery/processor.dm @@ -12,16 +12,31 @@ use_power = 1 idle_power_usage = 5 active_power_usage = 50 + var/rating_speed = 1 + var/rating_amount = 1 +/obj/machinery/processor/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/processor(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + RefreshParts() +/obj/machinery/processor/RefreshParts() + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + rating_amount = B.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + rating_speed = M.rating /datum/food_processor_process var/input var/output var/time = 40 -/datum/food_processor_process/proc/process_food(loc, what) - if (src.output && loc) - new src.output(loc) +/datum/food_processor_process/proc/process_food(loc, what, var/obj/machinery/processor/processor) + if (src.output && loc && processor) + for(var/i = 0, i < processor.rating_amount, i++) + new src.output(loc) if (what) qdel(what) // Note to self: Make this safer @@ -60,18 +75,18 @@ /* mobs */ -/datum/food_processor_process/mob/process_food(loc, what) +/datum/food_processor_process/mob/process_food(loc, what, processor) ..() -/datum/food_processor_process/mob/slime/process_food(loc, what) +/datum/food_processor_process/mob/slime/process_food(loc, what, var/obj/machinery/processor/processor) var/mob/living/simple_animal/slime/S = what var/C = S.cores if(S.stat != DEAD) S.loc = loc S.visible_message("[C] crawls free of the processor!") return - for(var/i = 1, i <= C, i++) + for(var/i = 1, i <= C + processor.rating_amount, i++) new S.coretype(loc) feedback_add_details("slime_core_harvested","[replacetext(S.colour," ","_")]") ..() @@ -79,7 +94,7 @@ /datum/food_processor_process/mob/slime/input = /mob/living/simple_animal/slime /datum/food_processor_process/mob/slime/output = null -/datum/food_processor_process/mob/monkey/process_food(loc, what) +/datum/food_processor_process/mob/monkey/process_food(loc, what, processor) var/mob/living/carbon/monkey/O = what if (O.client) //grief-proof O.loc = loc @@ -123,8 +138,20 @@ if(src.processing) user << "The processor is in the process of processing!" return 1 + if(default_deconstruction_screwdriver(user, "processor1", "processor", O)) + return + + if(exchange_parts(user, O)) + return + + if(default_pry_open(O)) + return + if(default_unfasten_wrench(user, O)) return + + default_deconstruction_crowbar(O) + var/what = O if (istype(O, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = O @@ -151,20 +178,30 @@ if(src.contents.len == 0) user << "The processor is empty!" return 1 + src.processing = 1 + user.visible_message("[user] turns on [src].", \ + "You turn on [src].", \ + "You hear a food processor.") + playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + use_power(500) + var/total_time = 0 + for(var/O in src.contents) + var/datum/food_processor_process/P = select_recipe(O) + if (!P) + log_admin("DEBUG: [O] in processor havent suitable recipe. How do you put it in?") //-rastaf0 // DEAR GOD THIS BURNS MY EYES HAVE YOU EVER LOOKED IN AN ENGLISH DICTONARY BEFORE IN YOUR LIFE AAAAAAAAAAAAAAAAAAAAA - Iamgoofball + continue + total_time += P.time + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = (total_time / rating_speed)*5) //start shaking + sleep(total_time / rating_speed) for(var/O in src.contents) var/datum/food_processor_process/P = select_recipe(O) if (!P) log_admin("DEBUG: [O] in processor havent suitable recipe. How do you put it in?") //-rastaf0 continue - src.processing = 1 - user.visible_message("[user] turns on \a [src].", \ - "You turn on \a [src].", \ - "You hear a food processor.") - playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) - use_power(500) - sleep(P.time) - P.process_food(src.loc, O) - src.processing = 0 + P.process_food(src.loc, O, src) + pixel_x = initial(pixel_x) //return to its spot after shaking + src.processing = 0 src.visible_message("\the [src] finishes processing.") /obj/machinery/processor/verb/eject() diff --git a/code/modules/food&drinks/kitchen machinery/smartfridge.dm b/code/modules/food&drinks/kitchen machinery/smartfridge.dm index 9746ee4a83c..dce85ce5ed2 100644 --- a/code/modules/food&drinks/kitchen machinery/smartfridge.dm +++ b/code/modules/food&drinks/kitchen machinery/smartfridge.dm @@ -13,11 +13,22 @@ idle_power_usage = 5 active_power_usage = 100 flags = NOREACT - var/global/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't like things over 1000. + var/max_n_of_items = 1500 var/icon_on = "smartfridge" var/icon_off = "smartfridge-off" var/item_quants = list() +/obj/machinery/smartfridge/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/smartfridge(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + RefreshParts() + +/obj/machinery/smartfridge/RefreshParts() + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + max_n_of_items = 1500 * B.rating + /obj/machinery/smartfridge/power_change() ..() update_icon() @@ -35,9 +46,21 @@ ********************/ /obj/machinery/smartfridge/attackby(var/obj/item/O as obj, var/mob/user as mob, params) + if(default_deconstruction_screwdriver(user, "smartfridge_open", "smartfridge", O)) + return + + if(exchange_parts(user, O)) + return + + if(default_pry_open(O)) + return + if(default_unfasten_wrench(user, O)) power_change() return + + default_deconstruction_crowbar(O) + if(stat) return 0 diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 41d7dedaaa5..ba32bb2c6ff 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -13,6 +13,7 @@ var/menustat = "menu" var/efficiency = 0 var/productivity = 0 + var/max_items = 40 /obj/machinery/biogenerator/New() ..() @@ -28,12 +29,15 @@ /obj/machinery/biogenerator/RefreshParts() var/E = 0 var/P = 0 + var/max_storage = 40 for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) P += B.rating + max_storage = 40 * B.rating for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) E += M.rating efficiency = E productivity = P + max_items = max_storage /obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well. update_icon() @@ -65,15 +69,15 @@ var/i = 0 for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents) i++ - if(i >= 10) + if(i >= max_items) user << "The biogenerator is already full! Activate it." else for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents) - if(i >= 10) + if(i >= max_items) break G.loc = src i++ - if(i<10) + if(iYou empty the plant bag into the biogenerator." else if(O.contents.len == 0) user << "You empty the plant bag into the biogenerator, filling it to its capacity." @@ -87,7 +91,7 @@ var/i = 0 for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents) i++ - if(i >= 10) + if(i >= max_items) user << "The biogenerator is full! Activate it." else user.unEquip(O) @@ -155,6 +159,7 @@ dat += "Book bag: Make ([200/efficiency])
    " dat += "Plant bag: Make ([200/efficiency])
    " dat += "Mining satchel: Make ([200/efficiency])
    " + dat += "Chemistry bag: Make ([200/efficiency])
    " dat += "Botanical gloves: Make ([250/efficiency])
    " dat += "Utility belt: Make ([300/efficiency])
    " dat += "Security belt: Make ([300/efficiency])
    " @@ -266,6 +271,9 @@ if("mnbag") if (check_cost(200/efficiency)) return 0 else new/obj/item/weapon/storage/bag/ore(src.loc) + if("chbag") + if (check_cost(200/efficiency)) return 0 + else new/obj/item/weapon/storage/bag/chemistry(src.loc) if("gloves") if (check_cost(250/efficiency)) return 0 else new/obj/item/clothing/gloves/botanic_leather(src.loc) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 78a92dc1481..608414b38c2 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -22,6 +22,7 @@ var/planted = 0 //Is it occupied? var/harvest = 0 //Ready to harvest? var/obj/item/seeds/myseed = null //The currently planted seed + var/rating = 1 var/unwrenchable = 1 pixel_y=8 @@ -37,22 +38,34 @@ component_parts += new /obj/item/weapon/circuitboard/hydroponics(null) component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) component_parts += new /obj/item/weapon/stock_parts/console_screen(null) RefreshParts() /obj/machinery/hydroponics/constructable/RefreshParts() - var tmp_capacity = 0 + var/tmp_capacity = 0 for (var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) tmp_capacity += M.rating + for (var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + rating = M.rating maxwater = tmp_capacity * 50 // Up to 300 maxnutri = tmp_capacity * 5 // Up to 30 waterlevel = maxwater nutrilevel = 3 /obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/user, params) + if(default_deconstruction_screwdriver(user, "hydrotray3", "hydrotray3", I)) + return + if(exchange_parts(user, I)) return + if(default_pry_open(I)) + return + + if(default_unfasten_wrench(user, I)) + return + if(istype(I, /obj/item/weapon/crowbar)) if(anchored==2) user << "Unscrew the hoses first!" @@ -89,10 +102,10 @@ mutate() else if(istype(Proj ,/obj/item/projectile/energy/florayield)) if(myseed.yield == 0)//Oh god don't divide by zero you'll doom us all. - adjustSYield(1) + adjustSYield(1 * rating) //world << "Yield increased by 1, from 0, to a total of [myseed.yield]" else if(prob(1/(myseed.yield * myseed.yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2... - adjustSYield(1) + adjustSYield(1 * rating) //world << "Yield increased by 1, to a total of [myseed.yield]" else ..() @@ -115,7 +128,7 @@ //Nutrients////////////////////////////////////////////////////////////// // Nutrients deplete slowly if(prob(50)) - adjustNutri(-1) + adjustNutri(-1 / rating) // Lack of nutrients hurts non-weeds if(nutrilevel <= 0 && myseed.plant_type != 1) @@ -128,56 +141,56 @@ var/lightAmt = currentTurf.lighting_lumcount if(myseed.plant_type == 2) // Mushroom if(lightAmt < 2) - adjustHealth(-1) + adjustHealth(-1 / rating) else // Non-mushroom if(lightAmt < 4) - adjustHealth(-2) + adjustHealth(-2 / rating) //Water////////////////////////////////////////////////////////////////// // Drink random amount of water - adjustWater(-rand(1,6)) + adjustWater(-rand(1,6) / rating) // If the plant is dry, it loses health pretty fast, unless mushroom if(waterlevel <= 10 && myseed.plant_type != 2) - adjustHealth(-rand(0,1)) + adjustHealth(-rand(0,1) / rating) if(waterlevel <= 0) - adjustHealth(-rand(0,2)) + adjustHealth(-rand(0,2) / rating) // Sufficient water level and nutrient level = plant healthy else if(waterlevel > 10 && nutrilevel > 0) - adjustHealth(rand(1,2)) + adjustHealth(rand(1,2) / rating) if(prob(5)) //5 percent chance the weed population will increase - adjustWeeds(1) + adjustWeeds(1 / rating) //Toxins///////////////////////////////////////////////////////////////// // Too much toxins cause harm, but when the plant drinks the contaiminated water, the toxins disappear slowly if(toxic >= 40 && toxic < 80) - adjustHealth(-1) - adjustToxic(-rand(1,10)) + adjustHealth(-1 / rating) + adjustToxic(-rand(1,10) / rating) else if(toxic >= 80) // I don't think it ever gets here tbh unless above is commented out adjustHealth(-3) - adjustToxic(-rand(1,10)) + adjustToxic(-rand(1,10) / rating) //Pests & Weeds////////////////////////////////////////////////////////// else if(pestlevel >= 5) - adjustHealth(-1) + adjustHealth(-1 / rating) // If it's a weed, it doesn't stunt the growth if(weedlevel >= 5 && myseed.plant_type != 1 ) - adjustHealth(-1) + adjustHealth(-1 / rating) //Health & Age/////////////////////////////////////////////////////////// // Plant dies if health <= 0 if(health <= 0) plantdies() - adjustWeeds(1) // Weeds flourish + adjustWeeds(1 / rating) // Weeds flourish // If the plant is too old, lose health fast if(age > myseed.lifespan) - adjustHealth(-rand(1,5)) + adjustHealth(-rand(1,5) / rating) // Harvest code if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead)) @@ -187,10 +200,10 @@ else lastproduce = age if(prob(5)) // On each tick, there's a 5 percent chance the pest population will increase - adjustPests(1) + adjustPests(1 / rating) else if(waterlevel > 10 && nutrilevel > 0 && prob(10)) // If there's no plant, the percentage chance is 10% - adjustWeeds(1) + adjustWeeds(1 / rating) // Weeeeeeeeeeeeeeedddssss @@ -436,18 +449,18 @@ // Nutriments if(S.has_reagent("eznutriment", 1)) - yieldmod = 1 - mutmod = 1 + yieldmod = 1 * rating + mutmod = 1 * rating adjustNutri(round(S.get_reagent_amount("eznutriment") * 1)) if(S.has_reagent("left4zednutriment", 1)) - yieldmod = 0 - mutmod = 2 + yieldmod = 0 * rating + mutmod = 2 * rating adjustNutri(round(S.get_reagent_amount("left4zednutriment") * 1)) if(S.has_reagent("robustharvestnutriment", 1)) - yieldmod = 2 - mutmod = 0 + yieldmod = 2 * rating + mutmod = 0 * rating adjustNutri(round(S.get_reagent_amount("robustharvestnutriment") *1 )) // Antitoxin binds shit pretty well. So the tox goes significantly down @@ -734,17 +747,17 @@ user.visible_message("[user] unwrenches [src].", \ "You unwrench [src].") - else if(istype(O, /obj/item/weapon/screwdriver) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY + else if(istype(O, /obj/item/weapon/wirecutters) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY if(anchored) if(anchored == 2) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) anchored = 1 - user << "You unscrew \the [src]'s hoses." + user << "You snip \the [src]'s hoses." else if(anchored == 1) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) anchored = 2 - user << "You screw in \the [src]'s hoses." + user << "You reconnect \the [src]'s hoses." for(var/obj/machinery/hydroponics/h in range(1,src)) spawn() @@ -789,7 +802,7 @@ var/t_amount = 0 var/list/result = list() var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc //needed for TK - + var/product_name while(t_amount < getYield()) var/obj/item/weapon/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, potency) result.Add(t_prod) // User gets a consumable @@ -802,7 +815,9 @@ t_prod.potency = potency t_prod.plant_type = plant_type t_amount++ - + product_name = t_prod.name + if(getYield() >= 1) + feedback_add_details("food_harvested","[product_name]|[getYield()]") parent.update_tray() return result diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index c7169acc0c3..0ad83aeb190 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -1,7 +1,10 @@ -/proc/seedify(var/obj/item/O as obj, var/t_max) +/proc/seedify(var/obj/item/O as obj, var/t_max, var/obj/machinery/seed_extractor/extractor) var/t_amount = 0 if(t_max == -1) - t_max = rand(1,4) + if(extractor) + t_max = rand(1,4) * extractor.seed_multiplier + else + t_max = rand(1,4) if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown/)) var/obj/item/weapon/reagent_containers/food/snacks/grown/F = O @@ -51,8 +54,39 @@ density = 1 anchored = 1 var/piles = list() + var/max_seeds = 1000 + var/seed_multiplier = 1 + +/obj/machinery/seed_extractor/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/seed_extractor(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + RefreshParts() + +/obj/machinery/seed_extractor/RefreshParts() + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + max_seeds = 1000 * B.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + seed_multiplier = M.rating /obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob, params) + + if(default_deconstruction_screwdriver(user, "sextractor_open", "sextractor", O)) + return + + if(exchange_parts(user, O)) + return + + if(default_pry_open(O)) + return + + if(default_unfasten_wrench(user, O)) + return + + default_deconstruction_crowbar(O) + if(isrobot(user)) return @@ -60,7 +94,7 @@ var/obj/item/weapon/storage/P = O var/loaded = 0 for(var/obj/item/seeds/G in P.contents) - if(contents.len >= 999) + if(contents.len >= max_seeds) break ++loaded add(G) diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index 1b81cbe8e9c..1dd002229be 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -16,6 +16,9 @@ var/stack_list[0] //Key: Type. Value: Instance of type. var/obj/item/weapon/card/id/inserted_id var/points = 0 + var/ore_pickup_rate = 15 + var/sheet_per_ore = 1 + var/point_upgrade = 1 var/list/ore_values = list(("sand" = 1), ("iron" = 1), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("bananium" = 30), ("diamond" = 40), ("plasma" = 40)) /obj/machinery/mineral/ore_redemption/New() @@ -23,10 +26,26 @@ component_parts = list() component_parts += new /obj/item/weapon/circuitboard/ore_redemption(null) component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) component_parts += new /obj/item/device/assembly/igniter(null) component_parts += new /obj/item/weapon/stock_parts/console_screen(null) RefreshParts() +/obj/machinery/mineral/ore_redemption/RefreshParts() + var/ore_pickup_rate_temp = 15 + var/point_upgrade_temp = 1 + var/sheet_per_ore_temp = 1 + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + sheet_per_ore_temp = B.rating + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + ore_pickup_rate_temp = 15 * M.rating + for(var/obj/item/weapon/stock_parts/micro_laser/L in component_parts) + point_upgrade_temp = L.rating + ore_pickup_rate = ore_pickup_rate_temp + point_upgrade = point_upgrade_temp + sheet_per_ore = sheet_per_ore_temp + /obj/machinery/mineral/ore_redemption/proc/process_sheet(obj/item/weapon/ore/O) var/obj/item/stack/sheet/processed_sheet = SmeltMineral(O) if(processed_sheet) @@ -40,7 +59,7 @@ if(D.department == "Science" || D.department == "Robotics" || D.department == "Research Director's Desk" || (D.department == "Chemistry" && (s.name == "uranium" || s.name == "solid plasma"))) D.createmessage("Ore Redemption Machine", "New minerals available!", msg, 1, 0) var/obj/item/stack/sheet/storage = stack_list[processed_sheet] - storage.amount += 1 //Stack the sheets + storage.amount += sheet_per_ore //Stack the sheets O.loc = null //Let the old sheet... qdel(O) //... garbage collect @@ -50,7 +69,7 @@ var/i if(T) if(locate(/obj/item/weapon/ore) in T) - for (i = 0; i < 10; i++) + for (i = 0; i < ore_pickup_rate; i++) var/obj/item/weapon/ore/O = locate() in T if(O) process_sheet(O) @@ -59,7 +78,7 @@ else var/obj/structure/ore_box/B = locate() in T if(B) - for (i = 0; i < 10; i++) + for (i = 0; i < ore_pickup_rate; i++) var/obj/item/weapon/ore/O = locate() in B.contents if(O) process_sheet(O) @@ -75,6 +94,14 @@ inserted_id = I interact(user) return + if(exchange_parts(user, W)) + return + + if(default_pry_open(W)) + return + + if(default_unfasten_wrench(user, W)) + return if(default_deconstruction_screwdriver(user, "ore_redemption-open", "ore_redemption", W)) updateUsrDialog() return @@ -88,7 +115,7 @@ /obj/machinery/mineral/ore_redemption/proc/SmeltMineral(var/obj/item/weapon/ore/O) if(O.refined_type) var/obj/item/stack/sheet/M = O.refined_type - points += O.points + points += O.points * point_upgrade return M qdel(O)//No refined type? Purge it. return @@ -135,7 +162,7 @@ var/dat = "" for(var/ore in ore_values) var/value = ore_values[ore] - dat += "" + dat += "" dat += "
    [capitalize(ore)][value]
    [capitalize(ore)][value * point_upgrade]
    " return dat diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index e9067b526dc..ddfdd96ad9a 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -439,6 +439,7 @@ var/global/list/rockTurfEdgeCache user << "You finish cutting into the rock." P.update_icon() gets_drilled(user) + feedback_add_details("pick_used_mining","[P.name]") else return attack_hand(user) return @@ -448,6 +449,7 @@ var/global/list/rockTurfEdgeCache var/i for (i=0;i 0)) stat(null, "Time left: [max(malf.AI_win_timeleft/malf.apcs, 0)]") + if(istype(ticker.mode, /datum/game_mode/gang)) + var/datum/game_mode/gang/mode = ticker.mode + if(isnum(mode.A_timer)) + stat(null, "[gang_name("A")] Gang Takeover: [max(mode.A_timer, 0)]") + if(isnum(mode.B_timer)) + stat(null, "[gang_name("B")] Gang Takeover: [max(mode.B_timer, 0)]") + /mob/dead/observer/verb/reenter_corpse() set category = "Ghost" set name = "Re-enter Corpse" diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 0b33449b5ef..02d7cc2a8e2 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -12,6 +12,7 @@ ventcrawler = 2 languages = ALIEN verb_say = "hisses" + type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno var/nightvision = 1 var/storedPlasma = 250 var/max_plasma = 500 @@ -28,6 +29,7 @@ var/heat_protection = 0.5 var/leaping = 0 var/list/obj/effect/proc_holder/alien/abilities = list() + gib_type = /obj/effect/decal/cleanable/xenoblood/xgibs /mob/living/carbon/alien/New() verbs += /mob/living/proc/mob_sleep diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 41a04d1273f..4026083e1ac 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -23,5 +23,7 @@ var/co2overloadtime = null var/temperature_resistance = T0C+75 has_limbs = 1 + var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/ var/remote_view = 0 + var/gib_type = /obj/effect/decal/cleanable/blood/gibs diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index ab85a8f3d19..32086909dbf 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -130,6 +130,8 @@ emp_act var/obj/item/organ/limb/affecting = get_organ(ran_zone(user.zone_sel.selecting)) var/hit_area = parse_zone(affecting.name) var/target_area = parse_zone(target_limb.name) + feedback_add_details("item_used_for_combat","[I.name]|[I.force]") + feedback_add_details("zone_targeted","[def_zone]") if(dna) // allows your species to affect the attacked_by code return dna.species.spec_attacked_by(I,user,def_zone,affecting,hit_area,src.a_intent,target_limb,target_area,src) @@ -154,7 +156,6 @@ emp_act var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) apply_damage(I.force, I.damtype, affecting, armor , I) - var/bloody = 0 if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2)))) if(affecting.status == ORGAN_ORGANIC) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index ecc7c49649e..8d08b29ecb2 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -136,3 +136,13 @@ return bypass // if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species. else return 0 + +/mob/living/carbon/human/can_track(mob/living/user) + if(wear_id && istype(wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) + return 0 + if(istype(head, /obj/item/clothing/head)) + var/obj/item/clothing/head/hat = head + if(hat.blockTracking) + return 0 + + return ..() diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index f55238a821b..b9321879663 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -31,7 +31,7 @@ /mob/living/carbon/human/experience_pressure_difference() playsound(src, 'sound/effects/space_wind.ogg', 50, 1) - if(shoes.flags&NOSLIP) + if(shoes && shoes.flags&NOSLIP) return 0 . = ..() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 4f953dff6e9..7d29d7a3bdc 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -73,12 +73,14 @@ if (getBrainLoss() >= 60 && stat != DEAD) if (prob(3)) - switch(pick(1,2,3)) + switch(pick(1,2,3,4)) if(1) - say(pick("IM A PONY NEEEEEEIIIIIIIIIGH", "without oxigen blob don't evoluate?", "CAPTAINS A COMDOM", "[pick("", "that faggot traitor")] [pick("joerge", "george", "gorge", "gdoruge")] [pick("mellens", "melons", "mwrlins")] is grifing me HAL;P!!!", "can u give me [pick("telikesis","halk","eppilapse")]?", "THe saiyans screwed", "Bi is THE BEST OF BOTH WORLDS>", "I WANNA PET TEH monkeyS", "stop grifing me!!!!", "SOTP IT#")) + say(pick("IM A PONY NEEEEEEIIIIIIIIIGH", "without oxigen blob don't evoluate?", "CAPTAINS A COMDOM", "[pick("", "that faggot traitor")] [pick("joerge", "george", "gorge", "gdoruge")] [pick("mellens", "melons", "mwrlins")] is grifing me HAL;P!!!", "can u give me [pick("telikesis","halk","eppilapse","kamelien","eksrey","glowey skin")]?", "THe saiyans screwed", "Bi is THE BEST OF BOTH WORLDS>", "I WANNA PET TEH monkeyS", "stop grifing me!!!!", "SOTP IT#", "shiggey diggey!!", "A PIRATE APPEAR")) if(2) - say(pick("FUS RO DAH","fucking 4rries!", "stat me", ">my face", "roll it easy!", "waaaaaagh!!!", "red wonz go fasta", "FOR TEH EMPRAH", "lol2cat", "dem dwarfs man, dem dwarfs", "SPESS MAHREENS", "hwee did eet fhor khayosss", "lifelike texture ;_;", "luv can bloooom", "PACKETS!!!")) + say(pick("FUS RO DAH","fucking 4rries!", "stat me", ">my face", "roll it easy!", "waaaaaagh!!!", "red wonz go fasta", "FOR TEH EMPRAH", "lol2cat", "dem dwarfs man, dem dwarfs", "SPESS MAHREENS", "hwee did eet fhor khayosss", "lifelike texture ;_;", "luv can bloooom", "PACKETS!!!", "port ba[pick("y", "i", "e")] med!!!!", "REVIRT GON CHEM!!!!!!!!", "youed call her a toeugh bithc", "closd for merbegging", "pray can u [pick("spawn", "MAke me", "creat")] [pick("zenomorfs", "ayleins", "treaitors", "sheadow linkgs", "ubdoocters")]???")) if(3) + say(pick("GEY AWAY FROM ME U GREIFING PRICK!!!!", "ur a fuckeing autist!", ";HELP SHITECIRTY MURDERIN MEE!!!", "hwat dose tha [pick("g", "squid", "r")] mean?????", "CAL; TEH SHUTTLE!!!!!", "wearnig siNGUARLTY IS .... FIne xDDDDDDDDD", "AI laW 22 Open door", "this SI mY stATIon......", "who the HELL do u thenk u r?!!!!", "geT THE FUCK OUTTTT", "H U G B O X", ";;CRAGING THIS STTAYTION WITH NIO SURVIVROS", "[pick("bager", "syebl")] is down11!!!!!!!!!!!!!!!!!")) + if(4) emote("drool") diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index 23bb31ead56..fd4573900c7 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -10,7 +10,7 @@ return - message = trim(strip_html_properly(message)) + message = trim(html_encode(message)) if(!can_speak(message)) return diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 51b73cc9a7a..a7c821c9493 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -8,6 +8,8 @@ pass_flags = PASSTABLE languages = MONKEY ventcrawler = 1 + type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey + gib_type = /obj/effect/decal/cleanable/blood/gibs /mob/living/carbon/monkey/New() create_reagents(1000) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0f1fe82505d..855ecf423c4 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -816,3 +816,41 @@ Sorry Giacom. Please don't be mad :( /mob/living/proc/get_standard_pixel_y_offset(lying = 0) return initial(pixel_y) + +/mob/living/Stat() + ..() + if(statpanel("Status")) + if(ticker) + if(ticker.mode) + if(istype(ticker.mode, /datum/game_mode/gang)) + var/datum/game_mode/gang/mode = ticker.mode + if(isnum(mode.A_timer)) + stat(null, "[gang_name("A")] Gang Takeover: [max(mode.A_timer, 0)]") + if(isnum(mode.B_timer)) + stat(null, "[gang_name("B")] Gang Takeover: [max(mode.B_timer, 0)]") + +/mob/living/cancel_camera() + ..() + cameraFollow = null + +/mob/living/proc/can_track(mob/living/user) + //basic fast checks go first. When overriding this proc, I recommend calling ..() at the end. + var/turf/T = get_turf(src) + if(!T) + return 0 + if(T.z == ZLEVEL_CENTCOM) //dont detect mobs on centcomm + return 0 + if(T.z >= ZLEVEL_SPACEMAX) + return 0 + if(src == user) + return 0 + if(invisibility || alpha == 0)//cloaked + return 0 + if(digitalcamo) + return 0 + + // Now, are they viewable by a camera? (This is last because it's the most intensive check) + if(!near_camera(src)) + return 0 + + return 1 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 9317991ac81..65479146645 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -35,6 +35,7 @@ var/list/ai_list = list() var/obj/item/device/pda/ai/aiPDA = null var/obj/item/device/multitool/aiMulti = null var/obj/machinery/bot/Bot + var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed. //MALFUNCTION var/datum/module_picker/malf_picker @@ -62,6 +63,13 @@ var/list/ai_list = list() var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking. var/apc_override = 0 //hack for letting the AI use its APC even when visionless + var/mob/camera/aiEye/eyeobj = new() + var/sprint = 10 + var/cooldown = 0 + var/acceleration = 1 + + var/obj/machinery/camera/portable/builtInCamera + /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) rename_self("ai", 1) name = real_name @@ -118,6 +126,13 @@ var/list/ai_list = list() job = "AI" ai_list += src shuttle_caller_list += src + + eyeobj.ai = src + eyeobj.name = "[src.name] (AI Eye)" // Give it a name + eyeobj.loc = src.loc + + builtInCamera = new /obj/machinery/camera/portable(src) + builtInCamera.network = list("SS13") ..() return @@ -125,6 +140,7 @@ var/list/ai_list = list() ai_list -= src shuttle_caller_list -= src SSshuttle.autoEvac() + qdel(eyeobj) // No AI, no Eye ..() @@ -457,7 +473,8 @@ var/list/ai_list = list() /mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C) - src.cameraFollow = null + if(!tracking) + cameraFollow = null if (!C || stat == 2) //C.can_use()) return 0 @@ -589,7 +606,7 @@ var/list/ai_list = list() set category = "AI Commands" set name = "Jump To Network" unset_machine() - src.cameraFollow = null + cameraFollow = null var/cameralist[0] if(usr.stat == 2) diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 33ba6d1056f..dd38dac92d1 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -36,30 +36,8 @@ return ai.client return null - -// AI MOVEMENT - -// The AI's "eye". Described on the top of the page. - -/mob/living/silicon/ai - var/mob/camera/aiEye/eyeobj = new() - var/sprint = 10 - var/cooldown = 0 - var/acceleration = 1 - - -// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us. -/mob/living/silicon/ai/New() - ..() - eyeobj.ai = src - eyeobj.name = "[src.name] (AI Eye)" // Give it a name - spawn(5) - eyeobj.loc = src.loc - -/mob/living/silicon/ai/Destroy() - eyeobj.ai = null - qdel(eyeobj) // No AI, no Eye - eyeobj = null +/mob/camera/aiEye/Destroy() + ai = null ..() /atom/proc/move_camera_by_click() @@ -92,7 +70,8 @@ else user.sprint = initial - user.cameraFollow = null + if(!user.tracking) + user.cameraFollow = null //user.unset_machine() //Uncomment this if it causes problems. //user.lightNearbyCamera() @@ -115,10 +94,7 @@ src.eyeobj.ai = src src.eyeobj.name = "[src.name] (AI Eye)" // Give it a name - if(client && client.eye) - client.eye = src - for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks) - c.remove(eyeobj) + eyeobj.setLoc(loc) /mob/living/silicon/ai/verb/toggle_acceleration() set category = "AI Commands" @@ -126,6 +102,3 @@ acceleration = !acceleration usr << "Camera acceleration has been toggled [acceleration ? "on" : "off"]." - - - diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index a324cdbbfe7..0e629e59283 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -163,9 +163,9 @@ // ok, we're alive, camera is good and in our network... - src.set_machine(src) - src:current = C - src.reset_view(C) + set_machine(src) + current = C + reset_view(C) return 1 diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 46be3e6feb3..7ce41a2de6a 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -12,7 +12,6 @@ use_power() /mob/living/silicon/robot/proc/clamp_values() - SetStunned(min(stunned, 30)) SetParalysis(min(paralysis, 30)) SetWeakened(min(weakened, 20)) @@ -23,29 +22,16 @@ adjustFireLoss(0) /mob/living/silicon/robot/proc/use_power() - - if(cell) - if(cell.charge <= 0) + if(cell && cell.charge) + if(cell.charge <= 100) uneq_all() - stat = UNCONSCIOUS - else if (cell.charge <= 100) - uneq_all() - cell.use(1) - else - if(module_state_1) - cell.use(5) - if(module_state_2) - cell.use(5) - if(module_state_3) - cell.use(5) - cell.use(1) + cell.use(1) else uneq_all() stat = UNCONSCIOUS /mob/living/silicon/robot/handle_regular_status_updates() - if(camera && !scrambledcodes) if(stat == DEAD || wires.IsCameraCut()) camera.status = 0 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 77e0040131f..c016f818fbd 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -556,13 +556,8 @@ if(user != src)//To prevent syndieborgs from emagging themselves if(!opened)//Cover is closed if(locked) - if(prob(90)) - user << "You emag the cover lock." - locked = 0 - else - user << "You fail to emag the cover lock!" - if(prob(25)) - src << "Hack attempt detected." + user << "You emag the cover lock." + locked = 0 else user << "The cover is already unlocked!" return @@ -573,42 +568,37 @@ return else sleep(6) - if(prob(50)) - SetEmagged(1) - SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown - lawupdate = 0 - connected_ai = null - user << "You emag [src]'s interface." - message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") - log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") - clear_supplied_laws() - clear_inherent_laws() - laws = new /datum/ai_laws/syndicate_override - var/time = time2text(world.realtime,"hh:mm:ss") - lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") - set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.") - src << "ALERT: Foreign software detected." - sleep(5) - src << "Initiating diagnostics..." - sleep(20) - src << "SynBorg v1.7 loaded." - sleep(5) - src << "LAW SYNCHRONISATION ERROR" - sleep(5) - src << "Would you like to send a report to NanoTraSoft? Y/N" - sleep(10) - src << "> N" - sleep(20) - src << "ERRORERRORERROR" - src << "Obey these laws:" - laws.show_laws(src) - src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands." - SetLockdown(0) - update_icons() - else - user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface!" - if(prob(25)) - src << "ALERT: Hack attempt detected." + SetEmagged(1) + SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown + lawupdate = 0 + connected_ai = null + user << "You emag [src]'s interface." + message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") + log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") + clear_supplied_laws() + clear_inherent_laws() + laws = new /datum/ai_laws/syndicate_override + var/time = time2text(world.realtime,"hh:mm:ss") + lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.") + src << "ALERT: Foreign software detected." + sleep(5) + src << "Initiating diagnostics..." + sleep(20) + src << "SynBorg v1.7 loaded." + sleep(5) + src << "LAW SYNCHRONISATION ERROR" + sleep(5) + src << "Would you like to send a report to NanoTraSoft? Y/N" + sleep(10) + src << "> N" + sleep(20) + src << "ERRORERRORERROR" + src << "Obey these laws:" + laws.show_laws(src) + src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands." + SetLockdown(0) + update_icons() /mob/living/silicon/robot/verb/unlock_own_cover() set category = "Robot Commands" diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 066d484506d..ab816782d26 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -155,6 +155,8 @@ var/T = src.loc + if(!stat) + return 0 if(busy != SPINNING_WEB) busy = SPINNING_WEB src.visible_message("\the [src] begins to secrete a sticky substance.") @@ -171,6 +173,8 @@ set category = "Spider" set desc = "Wrap up prey to feast upon and objects for safe keeping." + if(!stat) + return 0 if(!cocoon_target) var/list/choices = list() for(var/mob/living/L in view(1,src)) @@ -228,6 +232,8 @@ set desc = "Lay a clutch of eggs, but you must wrap a creature for feeding first." var/obj/effect/spider/eggcluster/E = locate() in get_turf(src) + if(!stat) + return 0 if(E) src << "There is already a cluster of eggs here!" else if(!fed) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index 9e0296844b0..b4616ae9fb7 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -41,6 +41,10 @@ return ..() +/mob/living/simple_animal/hostile/asteroid/death(gibbed) + feedback_add_details("mobs_killed_mining","[src.name]") + ..(gibbed) + /mob/living/simple_animal/hostile/asteroid/basilisk name = "basilisk" desc = "A territorial beast, covered in a thick shell that absorbs energy. Its stare causes victims to freeze from the inside." @@ -110,6 +114,7 @@ D.layer = 4.1 ..(gibbed) + /mob/living/simple_animal/hostile/asteroid/goldgrub name = "goldgrub" desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name." diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c5d468e9ae9..416fe4d1170 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -622,9 +622,6 @@ var/list/slot_equipment_priority = list( \ set category = "OOC" reset_view(null) unset_machine() - if(istype(src, /mob/living)) - if(src:cameraFollow) - src:cameraFollow = null /mob/Topic(href, href_list) if(href_list["mach_close"]) @@ -719,6 +716,7 @@ var/list/slot_equipment_priority = list( \ if(master_controller) stat("MasterController:","[round(master_controller.cost,0.001)]ds (Interval:[master_controller.processing_interval] | Iteration:[master_controller.iteration])") + stat("Subsystem cost per second:","[round(master_controller.SSCostPerSecond,0.001)]ds") for(var/datum/subsystem/SS in master_controller.subsystems) if(SS.can_fire) SS.stat_entry() diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 08b04e3afff..3c1906ee7dc 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -182,7 +182,7 @@ return 0 /proc/stars(n, pr) - n = strip_html_properly(n) + n = html_encode(n) if (pr == null) pr = 25 if (pr <= 0) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 96c8a2ba049..67a15e73030 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -453,7 +453,9 @@ By design, d1 is the smallest direction and d2 is the highest // Definitions //////////////////////////////// - +var/global/list/datum/stack_recipe/cable_coil_recipes = list ( \ + new/datum/stack_recipe("cable restraints", /obj/item/weapon/restraints/handcuffs/cable, 15), \ + ) /obj/item/stack/cable_coil name = "cable coil" @@ -501,6 +503,7 @@ By design, d1 is the smallest direction and d2 is the highest pixel_x = rand(-2,2) pixel_y = rand(-2,2) update_icon() + recipes = cable_coil_recipes /////////////////////////////////// // General procedures @@ -533,38 +536,12 @@ By design, d1 is the smallest direction and d2 is the highest icon_state = "coil_[item_color]" name = "cable coil" -/obj/item/stack/cable_coil/verb/make_restraint() - set name = "Make Cable Restraints" - set category = "Object" - var/mob/M = usr - - if(ishuman(M) && !M.restrained() && !M.stat && M.canmove) - if(!istype(usr.loc,/turf)) - return - if(src.amount <= 14) - usr << "You need at least 15 lengths to make restraints!" - return - var/obj/item/weapon/restraints/handcuffs/cable/B = new /obj/item/weapon/restraints/handcuffs/cable(usr.loc) - B.icon_state = "cuff_[item_color]" - usr << "You wind some cable together to make some restraints." - src.use(15) - else - usr << "You cannot do that!" - ..() // Items usable on a cable coil : -// - Wirecutters : cut them duh ! // - Cable coil : merge cables /obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user, params) ..() - if( istype(W, /obj/item/weapon/wirecutters) && src.amount > 1) - src.amount-- - new /obj/item/stack/cable_coil(user.loc, 1,item_color) - user << "You cut a piece off the cable coil." - src.update_icon() - return - - else if(istype(W, /obj/item/stack/cable_coil/cyborg)) + if(istype(W, /obj/item/stack/cable_coil/cyborg)) var/obj/item/stack/cable_coil/cyborg/C = W var/to_transfer = min(src.amount, round((C.source.max_energy - C.source.energy) / C.cost)) C.add(to_transfer) @@ -588,22 +565,6 @@ By design, d1 is the smallest direction and d2 is the highest src.use(amt) return -//remove cables from the stack -/* This is probably reduntant -/obj/item/stack/cable_coil/use(var/used) - if(src.amount < used) - return 0 - else if (src.amount == used) - if(ismob(loc)) //handle mob icon update - var/mob/M = loc - M.unEquip(src) - qdel(src) - return 1 - else - amount -= used - update_icon() - return 1 -*/ /obj/item/stack/cable_coil/use(var/used) . = ..() update_icon() diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 125d19729e9..d90d7280cd2 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -43,6 +43,8 @@ return 0 if(charge < amount) return 0 charge = (charge - amount) + if(!istype(loc, /obj/machinery/power/apc)) + feedback_add_details("cell_used","[src.name]") return 1 // recharge the cell @@ -217,6 +219,19 @@ ..() charge = 0 +/obj/item/weapon/stock_parts/cell/bluespace + name = "bluespace power cell" + origin_tech = "powerstorage=7" + icon_state = "bscell" + maxcharge = 40000 + g_amt = 80 + rating = 6 + chargerate = 4000 + +/obj/item/weapon/stock_parts/cell/bluespace/empty/New() + ..() + charge = 0 + /obj/item/weapon/stock_parts/cell/infinite name = "infinite-capacity power cell!" icon_state = "icell" diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 9a09974598c..92d7b8105c1 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -16,11 +16,36 @@ var/active = 0 var/powered = 0 var/fire_delay = 100 + var/maximum_fire_delay = 100 + var/minimum_fire_delay = 20 var/last_shot = 0 var/shot_number = 0 var/state = 0 var/locked = 0 +/obj/machinery/power/emitter/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/emitter(null) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + RefreshParts() + +/obj/machinery/power/emitter/RefreshParts() + var/max_firedelay = 120 + var/firedelay = 120 + var/min_firedelay = 24 + var/power_usage = 350 + for(var/obj/item/weapon/stock_parts/micro_laser/L in component_parts) + max_firedelay -= 20 * L.rating + min_firedelay -= 4 * L.rating + firedelay -= 20 * L.rating + maximum_fire_delay = max_firedelay + minimum_fire_delay = min_firedelay + fire_delay = firedelay + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + power_usage -= 50 * M.rating + active_power_usage = power_usage /obj/machinery/power/emitter/verb/rotate() set name = "Rotate" @@ -71,7 +96,7 @@ src.active = 1 user << "You turn on \the [src]." src.shot_number = 0 - src.fire_delay = 100 + src.fire_delay = maximum_fire_delay investigate_log("turned on by [user.key]","singulo") update_icon() else @@ -119,7 +144,7 @@ src.fire_delay = 2 src.shot_number ++ else - src.fire_delay = rand(20,100) + src.fire_delay = rand(minimum_fire_delay,maximum_fire_delay) src.shot_number = 0 var/obj/item/projectile/beam/emitter/A = PoolOrNew(/obj/item/projectile/beam/emitter,src.loc) @@ -221,6 +246,17 @@ user << "Access denied." return + if(default_deconstruction_screwdriver(user, "emitter_open", "emitter", W)) + return + + if(exchange_parts(user, W)) + return + + if(default_pry_open(W)) + return + + default_deconstruction_crowbar(W) + ..() return diff --git a/code/modules/procedural mapping/mapGeneratorModules/helpers.dm b/code/modules/procedural mapping/mapGeneratorModules/helpers.dm new file mode 100644 index 00000000000..bad449a9e8f --- /dev/null +++ b/code/modules/procedural mapping/mapGeneratorModules/helpers.dm @@ -0,0 +1,44 @@ +//Helper Modules + + +// Helper to repressurize the area in case it was run in space +/datum/mapGeneratorModule/bottomLayer/repressurize + spawnableAtoms = list() + spawnableTurfs = list() + +/datum/mapGeneratorModule/bottomLayer/repressurize/generate() + if(!mother) + return + var/list/map = mother.map + for(var/turf/simulated/T in map) + SSair.remove_from_active(T) + for(var/turf/simulated/T in map) + if(T.air) + T.air.oxygen = T.oxygen + T.air.nitrogen = T.nitrogen + T.air.carbon_dioxide = T.carbon_dioxide + T.air.toxins = T.toxins + T.air.temperature = T.temperature + SSair.add_to_active(T) + +//Only places atoms/turfs on area borders +/datum/mapGeneratorModule/border + clusterCheckFlags = CLUSTER_CHECK_NONE + +/datum/mapGeneratorModule/border/generate() + if(!mother) + return + var/list/map = mother.map + for(var/turf/T in map) + if(is_border(T)) + place(T) + +/datum/mapGeneratorModule/border/proc/is_border(var/turf/T) + for(var/direction in list(SOUTH,EAST,WEST,NORTH)) + if (get_step(T,direction) in mother.map) + continue + return 1 + return 0 + +/datum/mapGenerator/repressurize + modules = list(/datum/mapGeneratorModule/bottomLayer/repressurize) \ No newline at end of file diff --git a/code/modules/procedural mapping/mapGenerators/asteroid.dm b/code/modules/procedural mapping/mapGenerators/asteroid.dm new file mode 100644 index 00000000000..4dc002aa56a --- /dev/null +++ b/code/modules/procedural mapping/mapGenerators/asteroid.dm @@ -0,0 +1,45 @@ +//Asteroid turfs +/datum/mapGeneratorModule/bottomLayer/asteroidTurfs + spawnableTurfs = list(/turf/simulated/floor/plating/asteroid = 100) + +/datum/mapGeneratorModule/bottomLayer/asteroidWalls + spawnableTurfs = list(/turf/simulated/mineral = 100) + +//Border walls +/datum/mapGeneratorModule/border/asteroidWalls + spawnableAtoms = list() + spawnableTurfs = list(/turf/simulated/mineral = 100) + +//Random walls +/datum/mapGeneratorModule/splatterLayer/asteroidWalls + clusterCheckFlags = CLUSTER_CHECK_NONE + spawnableAtoms = list() + spawnableTurfs = list(/turf/simulated/mineral = 30) + +//Monsters +/datum/mapGeneratorModule/splatterLayer/asteroidMonsters + spawnableTurfs = list() + spawnableAtoms = list(/mob/living/simple_animal/hostile/asteroid/basilisk = 10, \ + /mob/living/simple_animal/hostile/asteroid/hivelord = 10, \ + /mob/living/simple_animal/hostile/asteroid/goliath = 10) + + +// GENERATORS + +/datum/mapGenerator/asteroid/hollow + modules = list(/datum/mapGeneratorModule/bottomLayer/asteroidTurfs, \ + /datum/mapGeneratorModule/border/asteroidWalls) + +/datum/mapGenerator/asteroid/hollow/random + modules = list(/datum/mapGeneratorModule/bottomLayer/asteroidTurfs, \ + /datum/mapGeneratorModule/border/asteroidWalls, \ + /datum/mapGeneratorModule/splatterLayer/asteroidWalls) + +/datum/mapGenerator/asteroid/hollow/random/monsters + modules = list(/datum/mapGeneratorModule/bottomLayer/asteroidTurfs, \ + /datum/mapGeneratorModule/border/asteroidWalls, \ + /datum/mapGeneratorModule/splatterLayer/asteroidWalls, \ + /datum/mapGeneratorModule/splatterLayer/asteroidMonsters) + +/datum/mapGenerator/asteroid/filled + modules = list(/datum/mapGeneratorModule/bottomLayer/asteroidWalls) \ No newline at end of file diff --git a/code/modules/procedural mapping/mapGenerators/shuttle.dm b/code/modules/procedural mapping/mapGenerators/shuttle.dm new file mode 100644 index 00000000000..7197b127d48 --- /dev/null +++ b/code/modules/procedural mapping/mapGenerators/shuttle.dm @@ -0,0 +1,15 @@ +/datum/mapGeneratorModule/bottomLayer/shuttleFloor + spawnableTurfs = list(/turf/simulated/floor/plasteel/shuttle = 100) + +/datum/mapGeneratorModule/border/shuttleWalls + spawnableAtoms = list() + spawnableTurfs = list(/turf/simulated/wall/shuttle = 100) +// Generators + +/datum/mapGenerator/shuttle/full + modules = list(/datum/mapGeneratorModule/bottomLayer/shuttleFloor, \ + /datum/mapGeneratorModule/border/shuttleWalls,\ + /datum/mapGeneratorModule/bottomLayer/repressurize) + +/datum/mapGenerator/shuttle/floor + modules = list(/datum/mapGeneratorModule/bottomLayer/shuttleFloor) diff --git a/code/modules/procedural mapping/mapGenerators/syndicate.dm b/code/modules/procedural mapping/mapGenerators/syndicate.dm new file mode 100644 index 00000000000..e48fe718d00 --- /dev/null +++ b/code/modules/procedural mapping/mapGenerators/syndicate.dm @@ -0,0 +1,52 @@ +// Modules + +/turf/simulated/floor/plasteel/shuttle/red/syndicate + name = "floor" //Not Brig Floor + +/datum/mapGeneratorModule/bottomLayer/syndieFloor + spawnableTurfs = list(/turf/simulated/floor/plasteel/shuttle/red/syndicate = 100) + +/datum/mapGeneratorModule/border/syndieWalls + spawnableAtoms = list() + spawnableTurfs = list(/turf/simulated/wall/r_wall = 100) + + +/datum/mapGeneratorModule/syndieFurniture + clusterCheckFlags = CLUSTER_CHECK_ALL + spawnableTurfs = list() + spawnableAtoms = list(/obj/structure/table = 20,/obj/structure/stool/bed/chair = 15,/obj/structure/stool = 10, \ + /obj/structure/computerframe = 15, /obj/item/weapon/storage/toolbox/syndicate = 15 ,\ + /obj/structure/closet/syndicate = 25, /obj/machinery/suit_storage_unit/syndicate = 15) + +/datum/mapGeneratorModule/splatterLayer/syndieMobs + spawnableAtoms = list(/mob/living/simple_animal/hostile/syndicate = 30, \ + /mob/living/simple_animal/hostile/syndicate/melee = 20, \ + /mob/living/simple_animal/hostile/syndicate/ranged = 20, \ + /mob/living/simple_animal/hostile/viscerator = 30) + spawnableTurfs = list() + +// Generators + +/datum/mapGenerator/syndicate/empty //walls and floor only + modules = list(/datum/mapGeneratorModule/bottomLayer/syndieFloor, \ + /datum/mapGeneratorModule/border/syndieWalls,\ + /datum/mapGeneratorModule/bottomLayer/repressurize) + +/datum/mapGenerator/syndicate/mobsonly + modules = list(/datum/mapGeneratorModule/bottomLayer/syndieFloor, \ + /datum/mapGeneratorModule/border/syndieWalls,\ + /datum/mapGeneratorModule/splatterLayer/syndieMobs, \ + /datum/mapGeneratorModule/bottomLayer/repressurize) + +/datum/mapGenerator/syndicate/furniture + modules = list(/datum/mapGeneratorModule/bottomLayer/syndieFloor, \ + /datum/mapGeneratorModule/border/syndieWalls,\ + /datum/mapGeneratorModule/syndieFurniture, \ + /datum/mapGeneratorModule/bottomLayer/repressurize) + +/datum/mapGenerator/syndicate/full + modules = list(/datum/mapGeneratorModule/bottomLayer/syndieFloor, \ + /datum/mapGeneratorModule/border/syndieWalls,\ + /datum/mapGeneratorModule/syndieFurniture, \ + /datum/mapGeneratorModule/splatterLayer/syndieMobs, \ + /datum/mapGeneratorModule/bottomLayer/repressurize) \ No newline at end of file diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 4cc38cb4fc2..9b1666fd2f0 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -132,6 +132,7 @@ process_fire(target,user,1,params) + /obj/item/weapon/gun/proc/can_trigger_gun(mob/living/carbon/user) if (!user.IsAdvancedToolUser()) user << "You don't have the dexterity to do this!" @@ -218,7 +219,7 @@ user.update_inv_l_hand(0) else user.update_inv_r_hand(0) - + feedback_add_details("gun_fired","[src.name]") /obj/item/weapon/gun/attack(mob/M as mob, mob/user) if(user.a_intent == "harm") //Flogging diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index fdec6f437b9..8a6ffca294b 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -230,10 +230,11 @@ return /obj/item/weapon/gun/projectile/automatic/tommygun - name = "tommy gun" + name = "thompson SMG" desc = "A genuine 'Chicago Typewriter'." icon_state = "tommygun" item_state = "shotgun" + w_class = 5 slot_flags = 0 origin_tech = "combat=5;materials=1;syndicate=2" mag_type = /obj/item/ammo_box/magazine/tommygunm45 diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 92235739bdb..3dab9a3442a 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -192,7 +192,8 @@ dispensable_reagents = list() var/list/special_reagents = list(list("hydrogen", "oxygen", "silicon", "phosphorus", "sulfur", "carbon", "nitrogen", "water"), list("lithium", "sugar", "sacid", "copper", "mercury", "sodium","iodine","bromine"), - list("ethanol", "chlorine", "potassium", "aluminium", "radium", "fluorine", "iron", "welding_fuel","silver","stable_plasma")) + list("ethanol", "chlorine", "potassium", "aluminium", "radium", "fluorine", "iron", "welding_fuel","silver","stable_plasma"), + list("oil", "ash", "acetone", "saltpetre", "ammonia", "diethylamine")) /obj/machinery/chem_dispenser/constructable/New() ..() @@ -1244,9 +1245,12 @@ if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) return playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1) + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking operating = 1 updateUsrDialog() spawn(50) + pixel_x = initial(pixel_x) //return to its spot after shaking operating = 0 updateUsrDialog() @@ -1279,9 +1283,12 @@ if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) return playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking operating = 1 updateUsrDialog() spawn(60) + pixel_x = initial(pixel_x) //return to its spot after shaking operating = 0 updateUsrDialog() diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index f4304ba596a..d3c923f6e2c 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -23,7 +23,7 @@ Borg Hypospray var/recharge_time = 5 //Time it takes for shots to recharge (in seconds) var/list/datum/reagents/reagent_list = list() - var/list/reagent_ids = list("salbutamol", "salglu_solution", "charcoal", "epinephrine", "spaceacillin") + var/list/reagent_ids = list("dexalin", "kelotane", "bicaridine", "antitoxin", "epinephrine", "spaceacillin") //var/list/reagent_ids = list("salbutamol", "salglu_solution", "salglu_solution", "charcoal", "ephedrine", "spaceacillin") var/list/modes = list() //Basically the inverse of reagent_ids. Instead of having numbers as "keys" and strings as values it has strings as keys and numbers as values. //Used as list for input() in shakers. @@ -199,4 +199,4 @@ Borg Shaker charge_cost = 20 //Lots of reagents all regenerating at once, so the charge cost is lower. They also regenerate faster. recharge_time = 3 - reagent_ids = list("beer2") \ No newline at end of file + reagent_ids = list("beer2") diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 90bcb8ea638..c17ab572aca 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -590,7 +590,7 @@ return /obj/structure/disposalholder/allow_drop() - return 0 + return 1 // Disposal pipes diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index ee333ef117b..91d498bd90f 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -111,7 +111,7 @@ materials = list("$glass" = 1000, "sacid" = 20) build_path = /obj/item/weapon/circuitboard/chem_dispenser category = list ("Medical Machinery") - + /datum/design/chem_master name = "Machine Design (Chem Master Board)" desc = "The circuit board for a Chem Master 2999." @@ -252,6 +252,76 @@ build_path = /obj/item/weapon/circuitboard/microwave category = list ("Misc. Machinery") +/datum/design/gibber + name = "Machine Design (Gibber Board)" + desc = "The circuit board for a gibber." + id = "gibber" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/gibber + category = list ("Misc. Machinery") + +/datum/design/smartfridge + name = "Machine Design (Smartfridge Board)" + desc = "The circuit board for a smartfridge." + id = "smartfridge" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/smartfridge + category = list ("Misc. Machinery") + +/datum/design/monkey_recycler + name = "Machine Design (Monkey Recycler Board)" + desc = "The circuit board for a monkey recycler." + id = "smartfridge" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/monkey_recycler + category = list ("Misc. Machinery") + +/datum/design/seed_extractor + name = "Machine Design (Seed Extractor Board)" + desc = "The circuit board for a seed extractor." + id = "seed_extractor" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/seed_extractor + category = list ("Misc. Machinery") + +/datum/design/processor + name = "Machine Design (Processor Board)" + desc = "The circuit board for a processor." + id = "processor" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/processor + category = list ("Misc. Machinery") + +/datum/design/recycler + name = "Machine Design (Recycler Board)" + desc = "The circuit board for a recycler." + id = "recycler" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/recycler + category = list ("Misc. Machinery") + +/datum/design/holopad + name = "Machine Design (AI Holopad Board)" + desc = "The circuit board for a holopad." + id = "holopad" + req_tech = list("programming" = 1) + build_type = IMPRINTER + materials = list("$glass" = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/holopad + category = list ("Misc. Machinery") + /datum/design/autolathe name = "Machine Design (Autolathe Board)" desc = "The circuit board for an autolathe." diff --git a/code/modules/research/designs/power_designs.dm b/code/modules/research/designs/power_designs.dm index ddf3ff047de..f9749c7267b 100644 --- a/code/modules/research/designs/power_designs.dm +++ b/code/modules/research/designs/power_designs.dm @@ -48,6 +48,19 @@ build_path = /obj/item/weapon/stock_parts/cell/hyper category = list("Misc","Power Designs") +/datum/design/bluespace_cell + name = "Bluespace Power Cell" + desc = "A power cell that holds 40000 units of energy." + id = "bluespace_cell" + req_tech = list("powerstorage" = 6, "materials" = 5) + reliability = 70 + build_type = PROTOLATHE | MECHFAB + materials = list("$metal" = 800, "$gold" = 300, "$silver" = 300, "$glass" = 160, "$diamond" = 160) + construction_time=100 + build_path = /obj/item/weapon/stock_parts/cell/bluespace + category = list("Misc","Power Designs") + + /datum/design/light_replacer name = "Light Replacer" desc = "A device to automatically replace lights. Refill with working lightbulbs." diff --git a/code/modules/research/designs/stock_parts_designs.dm b/code/modules/research/designs/stock_parts_designs.dm index 117722ecb4e..ccec5e20d26 100644 --- a/code/modules/research/designs/stock_parts_designs.dm +++ b/code/modules/research/designs/stock_parts_designs.dm @@ -9,10 +9,20 @@ req_tech = list("engineering" = 3, "materials" = 3) build_type = PROTOLATHE - materials = list("$metal" = 15000, "$glass" = 5000) //hardcore + materials = list("$metal" = 10000, "$glass" = 5000) //hardcore build_path = /obj/item/weapon/storage/part_replacer category = list("Stock Parts") +/datum/design/BS_RPED + name = "Bluespace RPED" + desc = "Powered by bluespace technology, this RPED variant can upgrade buildings from a distance, without needing to remove the panel first." + id = "bs_rped" + req_tech = list("engineering" = 3, "materials" = 5, "programming" = 3, "bluespace" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 15000, "$glass" = 5000, "$silver" = 2500) //hardcore + build_path = /obj/item/weapon/storage/part_replacer/bluespace + category = list("Stock Parts") + //Capacitors /datum/design/basic_capacitor name = "Basic Capacitor" @@ -45,6 +55,17 @@ build_path = /obj/item/weapon/stock_parts/capacitor/super category = list("Stock Parts") +/datum/design/quadratic_capacitor + name = "Quadratic Capacitor" + desc = "A stock part used in the construction of various devices." + id = "quadratic_capacitor" + req_tech = list("powerstorage" = 6, "materials" = 5) + build_type = PROTOLATHE + reliability = 71 + materials = list("$metal" = 100, "$glass" = 100, "$diamond" = 40) + build_path = /obj/item/weapon/stock_parts/capacitor/quadratic + category = list("Stock Parts") + //Scanning modules /datum/design/basic_scanning name = "Basic Scanning Module" @@ -77,6 +98,17 @@ build_path = /obj/item/weapon/stock_parts/scanning_module/phasic category = list("Stock Parts") +/datum/design/triphasic_scanning + name = "Triphasic Scanning Module" + desc = "A stock part used in the construction of various devices." + id = "triphasic_scanning" + req_tech = list("magnets" = 6, "materials" = 4) + build_type = PROTOLATHE + materials = list("$metal" = 100, "$glass" = 40, "$diamond" = 20) + reliability = 72 + build_path = /obj/item/weapon/stock_parts/scanning_module/triphasic + category = list("Stock Parts") + //Maipulators /datum/design/micro_mani name = "Micro Manipulator" @@ -109,6 +141,17 @@ build_path = /obj/item/weapon/stock_parts/manipulator/pico category = list("Stock Parts") +/datum/design/femto_mani + name = "Femto Manipulator" + desc = "A stock part used in the construction of various devices." + id = "femto_mani" + req_tech = list("materials" = 6, "programming" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 60, "$diamond" = 30) + reliability = 73 + build_path = /obj/item/weapon/stock_parts/manipulator/femto + category = list("Stock Parts") + //Micro-lasers /datum/design/basic_micro_laser name = "Basic Micro-Laser" @@ -141,6 +184,17 @@ build_path = /obj/item/weapon/stock_parts/micro_laser/ultra category = list("Stock Parts") +/datum/design/quadultra_micro_laser + name = "Quad-Ultra Micro-Laser" + desc = "A stock part used in the construction of various devices." + id = "quadultra_micro_laser" + req_tech = list("magnets" = 6, "materials" = 6) + build_type = PROTOLATHE + materials = list("$metal" = 20, "$glass" = 40, "$uranium" = 20, "$diamond" = 20) + reliability = 70 + build_path = /obj/item/weapon/stock_parts/micro_laser/quadultra + category = list("Stock Parts") + /datum/design/basic_matter_bin name = "Basic Matter Bin" desc = "A stock part used in the construction of various devices." @@ -172,6 +226,17 @@ build_path = /obj/item/weapon/stock_parts/matter_bin/super category = list("Stock Parts") +/datum/design/bluespace_matter_bin + name = "Bluespace Matter Bin" + desc = "A stock part used in the construction of various devices." + id = "bluespace_matter_bin" + req_tech = list("materials" = 6) + build_type = PROTOLATHE + materials = list("$metal" = 160, "$diamond" = 200) + reliability = 75 + build_path = /obj/item/weapon/stock_parts/matter_bin/bluespace + category = list("Stock Parts") + //T-Comms devices /datum/design/subspace_ansible name = "Subspace Ansible" diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index b4b25eb9e42..2df53886ab3 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -177,6 +177,7 @@ var/global/list/obj/machinery/message_server/message_servers = list() /datum/feedback_variable/proc/add_details(var/text) if (istext(text)) + text = replacetext(text, " ", "_") if (!details) details = text else diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index d076c813158..1bc794782c6 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -276,6 +276,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(linked_lathe) //Also sends salvaged materials to a linked protolathe, if any. linked_lathe.m_amount += min((linked_lathe.max_material_storage - linked_lathe.TotalMaterials()), (linked_destroy.loaded_item.m_amt*(linked_destroy.decon_mod/10))) linked_lathe.g_amount += min((linked_lathe.max_material_storage - linked_lathe.TotalMaterials()), (linked_destroy.loaded_item.g_amt*(linked_destroy.decon_mod/10))) + feedback_add_details("item_deconstructed","[linked_destroy.loaded_item.name]") linked_destroy.loaded_item = null else screen = 1.0 @@ -406,6 +407,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/R = being_built.reliability spawn(32*amount/coeff) if(g2g) //And if we only fail the material requirements, we still spend time and power + var/already_logged = 0 for(var/i = 0, iYou drape [I] over [M]'s [parse_zone(procedure.location)] to prepare for \an [procedure.name].") add_logs(user, M, "operated", addition="Operation type: [procedure.name]") + feedback_add_details("surgery_initiated","[procedure.name]") return 1 else user << "You need to expose [M]'s [procedure.location] first!" diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 042832894d7..76365b0790c 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -73,6 +73,7 @@ /datum/surgery_step/proc/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] succeeds!", "You succeed.") + feedback_add_details("surgery_step_success","[src.type]") return 1 /datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) @@ -80,10 +81,12 @@ var/mob/living/carbon/human/H = target H.apply_damage(75,"brute","[target_zone]") user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.") + feedback_add_details("surgery_step_success","[src.type]") return 1 /datum/surgery_step/proc/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] screws up!", "You screw up!") + feedback_add_details("surgery_step_failed","[src.type]") return 0 /datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) diff --git a/code/orphaned procs/priority_announce.dm b/code/orphaned procs/priority_announce.dm index e085fa783ca..3630b9d58df 100644 --- a/code/orphaned procs/priority_announce.dm +++ b/code/orphaned procs/priority_announce.dm @@ -6,7 +6,8 @@ if(type == "Priority") announcement += "

    Priority Announcement

    " - + if (title && length(title) > 0) + announcement += "

    [html_encode(title)]

    " else if(type == "Captain") announcement += "

    Captain Announces

    " news_network.SubmitArticle(text, "Captain's Announcement", "Station Announcements", null) diff --git a/config/game_options.txt b/config/game_options.txt index cc2a9c13d1d..ed44c926e10 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -276,3 +276,7 @@ MIDROUND_ANTAG_LIFE_CHECK 0.7 #NO_SUMMON_MAGIC #NO_SUMMON_EVENTS +//Comment for "normal" explosions, which ignore obstacles +//Uncomment for explosions that react to doors and walls +REACTIONARY_EXPLOSIONS + diff --git a/html/changelog.html b/html/changelog.html index ba63933790f..69c3bf7818a 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,157 @@ -->
    +

    12 June 2015

    +

    Ikarrus updated:

    +
      +
    • Gang Updates
    • +
    • New objective: To win, Gangs must now buy a Dominator machine (50 influence) and defend it for a varying time frame.
      * The location of the dominator is broadcasted to the entire station the moment it is activated
      * The more territories the gang controls, the less time it will take
      * Gangs no longer win by capturing territories
    • +
    • A choice of gang outfits are now purchasable for 1 influence each
    • +
    • Thompson SMGs aka "tommy guns" are now purchasable for 50 influence
    • +
    • Bulletproof armor vests are now purchasable for 10 influence
    • +
    • Gang messages are now free to send
    • +
    • Prices of pistols and pens reduced to 20 and 30, respectively
    • +
    • Gang spraycans have been made a lot less obvious. They look nearly identical to regular ones, now.
    • +
    • Gangs will no longer be notified how much territory the enemy controls
    • +
    +

    Incoming5643 updated:

    +
      +
    • Growing tired of reports of slain members, the Wizard Federation has cautiously sactioned the dark path of lichdom. Beware of the powerful lich who hides his phylactery well, for he is immortal!
    • +
    • The trick to defeating liches is to destroy either their body or their phylactery item before they can ressurect to it. The more a lich is slain the longer it will take him to make use of his phylactery and the more likely the crew is to catch him during a vunerable moment.
    • +
    • Due to the addition of proper liching, skeletons as a choosable race from magic mirrors has been discontinued. My apologies to the powergamers. A special admin version of the mirror that allows for skeletons has also been added to the code.
    • +
    +

    Miauw updated:

    +
      +
    • AIs have received several minor nerfs in order to increase antagonist counterplay:
    • +
    • AI tracking is no longer instant, it takes an amount of time that increases with distance from the AI eye, up to 4 seconds. The AI detector item will light up when an AI begins tracking.
    • +
    • A random camera failure event has been added, which will break one or two random cameras.
    • +
    • You can no longer keep tracking people that are outside of your camera vision.
    • +
    • Camera wires have been removed. Screwdriver a camera to open the panel, then use wirecutters to disable it or a multitool to change the focus.
    • +
    • You can now hit cameras with items to break them. To repair a camera, simply open the panel and use wirecutters on it.
    • +
    • Camera alerts now only happen after a camera is reactivated.
    • +
    +

    RemieRichards updated:

    +
      +
    • New optional explosion effect ported from /vg/'s DeityLink, Explosions that are affected by Walls and Doors
    • +
    + +

    11 June 2015

    +

    Cheridan updated:

    +
      +
    • Removes the powerdrain for individiual active modules on cyborgs.
    • +
    + +

    09 June 2015

    +

    Aranclanos updated:

    +
      +
    • Structures and machines can now be built on shuttles.
    • +
    +

    Iamgoofball updated:

    +
      +
    • Adds the Bluespace Rapid Part Exchange Device: holds up to 400 stock parts and can be used to upgrade machines at range without needing to open their maintenance panel.
    • +
    • A new tier of stock parts have been added, they're very expensive to produce but provide ample improvements.
    • +
    • Many machines can now also be upgraded.
    • +
    • Emitter: Lasers decrease firing delay and Capacitors decrease power consumption.
    • +
    • Gibber: Matter Bins increase yield of meat and Manipulators speed up operation time, at high level can gib creatures with clothes.
    • +
    • Seed Extractor: Matter Bins increase storage and Manipulators multiply seed production.
    • +
    • Monkey Recycler: Matter Bins increase the amount of monkey cubes produced and Manipulators reduce the monkey-to-cubes ratio to a minimum of 1-to-1.
    • +
    • Crusher: Matter Bins increase material yield and Manipulators increase chance to yield materials, at high level there is a chance for rarer materials.
    • +
    • Holopad: Capacitors increase an AI's traversal range from the holopad.
    • +
    • Smartfridge: Matter Bins increase storage.
    • +
    • Processor: Matter Bins increase yield and Manipulators speed up operation time.
    • +
    • Microwave: Matter Bins increase storage.
    • +
    • Ore Redemption Machine: Matter Bins increase yield per ore, Lasers increase points per ore and Manipulators speed up operation time.
    • +
    • Hydroponics Tray: Manipulators improve water and nutrients efficiency.
    • +
    • Biogenerator: Matter Bins increase storage.
    • +
    +

    bananacreampie updated:

    +
      +
    • Added several new options to the ghostform sprites
    • +
    + +

    08 June 2015

    +

    AnturK updated:

    +
      +
    • Improved the interface of Spellbooks.
    • +
    +

    Cheridan updated:

    +
      +
    • Push-force from Atmospherics now depends on an entity's weight, heavier objects are less prone to being pushed.
    • +
    • Magboots and No-Slip shoes now prevent pushing from spacewind.
    • +
    +

    Firecage updated:

    +
      +
    • Protolathes can now build Experimental Welding Tools.
    • +
    + +

    07 June 2015

    +

    Aranclanos updated:

    +
      +
    • Malfunctioning AIs can preview placement of a Robotic Factory.
    • +
    +

    Iamgoofball updated:

    +
      +
    • Bicardine, Dexalin, Kelotane, Anti-toxin, Inaprovaline and Tricordrazine have been re-added.
    • +
    +

    RemieRichards updated:

    +
      +
    • Lizards can now wag their tails, emote *wag to start and *stopwag to stop.
    • +
    +

    kingofkosmos updated:

    +
      +
    • Mops can now be wet from normal buckets and sinks.
    • +
    + +

    06 June 2015

    +

    Incoming5643 updated:

    +
      +
    • Antagonists with escape alone can now escape with others on the shuttle, so long as they are also antagonists.
    • +
    • Antagonists with escape alone can also win if non-antagonists are on the shuttle provided they are locked in the brig.
    • +
    • Escaping to syndicate space on board the nuke op shuttle is now a valid way to escape the station.
    • +
    +

    Jordie0608 updated:

    +
      +
    • Admin-delaying the round now works once it has finished.
    • +
    + +

    05 June 2015

    +

    CandyClown updated:

    +
      +
    • Ointments, bruise packs, and gauze are now stacked to 6 instead of 5.
    • +
    +

    CorruptComputer updated:

    +
      +
    • Security lockers no longer spawn in front of each other on Box.
    • +
    • Hooked up the scrubbers in QM's office on Box.
    • +
    • Fixed bar disposals on Box
    • +
    • Fixed the stacked heater+freezer in expirementor maint on Box
    • +
    • Made the turbine into Atmos and Engineering access only, and renamed the doors to Turbine on Box.
    • +
    +

    Ikarrus updated:

    +
      +
    • Gang Bosses will now be able to discreetly send messages to everyone in their gang for 5 influence a message.
    • +
    • Conversion pens now use a flat 60sec cooldown rate.
    • +
    +

    KorPhaeron updated:

    +
      +
    • You can now lay tiles on the asteroid. Go nuts building forts.
    • +
    + +

    04 June 2015

    +

    Cuboos updated:

    +
      +
    • Added casting and firing sounds for wizard spells and staves.
    • +
    • A new title theme has been added.
    • +
    +

    Gun Hog updated:

    +
      +
    • Nanotrasen has approved the designs for destination taggers and hand labelers in the autolathe.
    • +
    +

    Palpatine213 updated:

    +
      +
    • Allows sechuds to have their id locks removed via emag as well as EMP
    • +
    +

    31 May 2015

    duncathan updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index a030bf17dca..e7f6df25d6e 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -2618,3 +2618,136 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2015-05-31: duncathan: - tweak: Clarified the ability to retract changeling armblades. +2015-06-04: + Cuboos: + - rscadd: Added casting and firing sounds for wizard spells and staves. + - rscadd: A new title theme has been added. + Gun Hog: + - rscadd: Nanotrasen has approved the designs for destination taggers and hand labelers + in the autolathe. + Palpatine213: + - tweak: Allows sechuds to have their id locks removed via emag as well as EMP +2015-06-05: + CandyClown: + - tweak: Ointments, bruise packs, and gauze are now stacked to 6 instead of 5. + CorruptComputer: + - bugfix: Security lockers no longer spawn in front of each other on Box. + - bugfix: Hooked up the scrubbers in QM's office on Box. + - bugfix: Fixed bar disposals on Box + - bugfix: Fixed the stacked heater+freezer in expirementor maint on Box + - tweak: Made the turbine into Atmos and Engineering access only, and renamed the + doors to Turbine on Box. + Ikarrus: + - rscadd: Gang Bosses will now be able to discreetly send messages to everyone in + their gang for 5 influence a message. + - tweak: Conversion pens now use a flat 60sec cooldown rate. + KorPhaeron: + - rscadd: You can now lay tiles on the asteroid. Go nuts building forts. +2015-06-06: + Incoming5643: + - rscadd: Antagonists with escape alone can now escape with others on the shuttle, + so long as they are also antagonists. + - rscadd: Antagonists with escape alone can also win if non-antagonists are on the + shuttle provided they are locked in the brig. + - rscadd: Escaping to syndicate space on board the nuke op shuttle is now a valid + way to escape the station. + Jordie0608: + - rscadd: Admin-delaying the round now works once it has finished. +2015-06-07: + Aranclanos: + - rscadd: Malfunctioning AIs can preview placement of a Robotic Factory. + Iamgoofball: + - rscadd: Bicardine, Dexalin, Kelotane, Anti-toxin, Inaprovaline and Tricordrazine + have been re-added. + RemieRichards: + - rscadd: Lizards can now wag their tails, emote *wag to start and *stopwag to stop. + kingofkosmos: + - tweak: Mops can now be wet from normal buckets and sinks. +2015-06-08: + AnturK: + - imageadd: Improved the interface of Spellbooks. + Cheridan: + - tweak: Push-force from Atmospherics now depends on an entity's weight, heavier + objects are less prone to being pushed. + - rscadd: Magboots and No-Slip shoes now prevent pushing from spacewind. + Firecage: + - rscadd: Protolathes can now build Experimental Welding Tools. +2015-06-09: + Aranclanos: + - wip: Structures and machines can now be built on shuttles. + Iamgoofball: + - rscadd: 'Adds the Bluespace Rapid Part Exchange Device: holds up to 400 stock + parts and can be used to upgrade machines at range without needing to open their + maintenance panel.' + - rscadd: A new tier of stock parts have been added, they're very expensive to produce + but provide ample improvements. + - experiment: Many machines can now also be upgraded. + - tweak: 'Emitter: Lasers decrease firing delay and Capacitors decrease power consumption.' + - tweak: 'Gibber: Matter Bins increase yield of meat and Manipulators speed up operation + time, at high level can gib creatures with clothes.' + - tweak: 'Seed Extractor: Matter Bins increase storage and Manipulators multiply + seed production.' + - tweak: 'Monkey Recycler: Matter Bins increase the amount of monkey cubes produced + and Manipulators reduce the monkey-to-cubes ratio to a minimum of 1-to-1.' + - tweak: 'Crusher: Matter Bins increase material yield and Manipulators increase + chance to yield materials, at high level there is a chance for rarer materials.' + - tweak: 'Holopad: Capacitors increase an AI''s traversal range from the holopad.' + - tweak: 'Smartfridge: Matter Bins increase storage.' + - tweak: 'Processor: Matter Bins increase yield and Manipulators speed up operation + time.' + - tweak: 'Microwave: Matter Bins increase storage.' + - tweak: 'Ore Redemption Machine: Matter Bins increase yield per ore, Lasers increase + points per ore and Manipulators speed up operation time.' + - tweak: 'Hydroponics Tray: Manipulators improve water and nutrients efficiency.' + - tweak: 'Biogenerator: Matter Bins increase storage.' + bananacreampie: + - rscadd: Added several new options to the ghostform sprites +2015-06-11: + Cheridan: + - rscdel: Removes the powerdrain for individiual active modules on cyborgs. +2015-06-12: + Ikarrus: + - experiment: Gang Updates + - rscadd: 'New objective: To win, Gangs must now buy a Dominator machine (50 influence) + and defend it for a varying time frame.
      * The location of the dominator is + broadcasted to the entire station the moment it is activated
      * The more territories + the gang controls, the less time it will take
      * Gangs no longer win by capturing + territories' + - rscadd: A choice of gang outfits are now purchasable for 1 influence each + - rscadd: Thompson SMGs aka "tommy guns" are now purchasable for 50 influence + - rscadd: Bulletproof armor vests are now purchasable for 10 influence + - tweak: Gang messages are now free to send + - tweak: Prices of pistols and pens reduced to 20 and 30, respectively + - tweak: Gang spraycans have been made a lot less obvious. They look nearly identical + to regular ones, now. + - rscdel: Gangs will no longer be notified how much territory the enemy controls + Incoming5643: + - rscadd: Growing tired of reports of slain members, the Wizard Federation has cautiously + sactioned the dark path of lichdom. Beware of the powerful lich who hides his + phylactery well, for he is immortal! + - rscadd: The trick to defeating liches is to destroy either their body or their + phylactery item before they can ressurect to it. The more a lich is slain the + longer it will take him to make use of his phylactery and the more likely the + crew is to catch him during a vunerable moment. + - rscremove: Due to the addition of proper liching, skeletons as a choosable race + from magic mirrors has been discontinued. My apologies to the powergamers. A + special admin version of the mirror that allows for skeletons has also been + added to the code. + Miauw: + - tweak: 'AIs have received several minor nerfs in order to increase antagonist + counterplay:' + - tweak: AI tracking is no longer instant, it takes an amount of time that increases + with distance from the AI eye, up to 4 seconds. The AI detector item will light + up when an AI begins tracking. + - tweak: A random camera failure event has been added, which will break one or two + random cameras. + - tweak: You can no longer keep tracking people that are outside of your camera + vision. + - tweak: Camera wires have been removed. Screwdriver a camera to open the panel, + then use wirecutters to disable it or a multitool to change the focus. + - tweak: You can now hit cameras with items to break them. To repair a camera, simply + open the panel and use wirecutters on it. + - tweak: Camera alerts now only happen after a camera is reactivated. + RemieRichards: + - rscadd: New optional explosion effect ported from /vg/'s DeityLink, Explosions + that are affected by Walls and Doors diff --git a/html/changelogs/CandyClownTG.yml b/html/changelogs/CandyClownTG.yml deleted file mode 100644 index 212952b415d..00000000000 --- a/html/changelogs/CandyClownTG.yml +++ /dev/null @@ -1,36 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# spellcheck (typo fixes) -# experiment -# tgs (TG-ported fixes?) -################################# - -# Your name. -author: CandyClown - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. -# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. -changes: - - tweak: "Ointments, bruise packs, and gauze are now stacked to 6 instead of 5." diff --git a/html/changelogs/CorruptComputer-BoxFixes.yml b/html/changelogs/CorruptComputer-BoxFixes.yml deleted file mode 100644 index 49474b0be95..00000000000 --- a/html/changelogs/CorruptComputer-BoxFixes.yml +++ /dev/null @@ -1,11 +0,0 @@ -author: CorruptComputer - -delete-after: True - -changes: - - bugfix: "Security lockers no longer spawn in front of each other on Box." - - bugfix: "Hooked up the scrubbers in QM's office on Box." - - bugfix: "Fixed bar disposals on Box" - - bugfix: "Fixed the stacked heater+freezer in expirementor maint on Box" - - tweak: "Made the turbine into Atmos and Engineering access only, and renamed the doors to Turbine on Box." - diff --git a/html/changelogs/Cuboos-WizardSounds.yml b/html/changelogs/Cuboos-WizardSounds.yml deleted file mode 100644 index eccd5fade93..00000000000 --- a/html/changelogs/Cuboos-WizardSounds.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Cuboos -delete-after: True - -changes: - - rscadd: "Added casting and firing sounds for wizard spells and staves." - - rscadd: "A new title theme has been added." \ No newline at end of file diff --git a/html/changelogs/Gun-Hog-PR-9667.yml b/html/changelogs/Gun-Hog-PR-9667.yml deleted file mode 100644 index a4cb8509a70..00000000000 --- a/html/changelogs/Gun-Hog-PR-9667.yml +++ /dev/null @@ -1,36 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# spellcheck (typo fixes) -# experiment -# tgs (TG-ported fixes?) -################################# - -# Your name. -author: Gun Hog - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. -# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Nanotrasen has approved the designs for destination taggers and hand labelers in the autolathe." diff --git a/html/changelogs/Ikarrus-gangmessage.yml b/html/changelogs/Ikarrus-gangmessage.yml deleted file mode 100644 index 9da3c5a3ffe..00000000000 --- a/html/changelogs/Ikarrus-gangmessage.yml +++ /dev/null @@ -1,37 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# spellcheck (typo fixes) -# experiment -# tgs (TG-ported fixes?) -################################# - -# Your name. -author: Ikarrus - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. -# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Gang Bosses will now be able to discreetly send messages to everyone in their gang for 5 influence a message." - - tweak: "Conversion pens now use a flat 60sec cooldown rate." \ No newline at end of file diff --git a/html/changelogs/Incoming5643 - whycantwebefriend.yml b/html/changelogs/Incoming5643 - whycantwebefriend.yml deleted file mode 100644 index d6cd2a65311..00000000000 --- a/html/changelogs/Incoming5643 - whycantwebefriend.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: Incoming5643 - -delete-after: True - -changes: - - rscadd: "Antagonists with escape alone can now escape with others on the shuttle, so long as they are also antagonists." - - rscadd: "Antagonists with escape alone can also win if non-antagonists are on the shuttle provided they are locked in the brig." - - rscadd: "Escaping to syndicate space on board the nuke op shuttle is now a valid way to escape the station." diff --git a/html/changelogs/KORPHAERON-TURF.yml b/html/changelogs/KORPHAERON-TURF.yml deleted file mode 100644 index 01c08918078..00000000000 --- a/html/changelogs/KORPHAERON-TURF.yml +++ /dev/null @@ -1,36 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# spellcheck (typo fixes) -# experiment -# tgs (TG-ported fixes?) -################################# - -# Your name. -author: KorPhaeron - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. -# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "You can now lay tiles on the asteroid. Go nuts building forts." diff --git a/html/changelogs/jordie restart.yml b/html/changelogs/jordie restart.yml deleted file mode 100644 index 4c581575db8..00000000000 --- a/html/changelogs/jordie restart.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Jordie0608 - -delete-after: True - -changes: - - rscadd: "Admin-delaying the round now works once it has finished." \ No newline at end of file diff --git a/html/changelogs/palpatine213-hudemag.yml b/html/changelogs/palpatine213-hudemag.yml deleted file mode 100644 index cd2b300bb20..00000000000 --- a/html/changelogs/palpatine213-hudemag.yml +++ /dev/null @@ -1,37 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# spellcheck (typo fixes) -# experiment -# tgs (TG-ported fixes?) -################################# - -# Your name. -author: Palpatine213 - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. -# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. -changes: - - tweak: "Allows sechuds to have their id locks removed via emag as well as EMP" - diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 1fe7f1c5713..39df26748eb 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi index a885e76d549..089427111f2 100644 Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index bc98f542874..4ced7caebed 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 522826b5530..934435bd835 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index ee03734f007..4347cde3677 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index dd1f96dcbfe..6572955ff2b 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index d4ddf81a414..e44ddedfcd4 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index f4d22e41ee2..59ac6436d18 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index b56aa44170d..deca94b24fa 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/crayons.dmi b/icons/obj/crayons.dmi index a3966103053..7d3489285c3 100644 Binary files a/icons/obj/crayons.dmi and b/icons/obj/crayons.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 473e51f6964..5a3e80c66f7 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi index 25a4bee8e63..904eb38c53c 100644 Binary files a/icons/obj/hydroponics/equipment.dmi and b/icons/obj/hydroponics/equipment.dmi differ diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi index 4988bb5a4c6..d485b53a828 100644 Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ diff --git a/icons/obj/machines/dominator.dmi b/icons/obj/machines/dominator.dmi new file mode 100644 index 00000000000..7671dedff86 Binary files /dev/null and b/icons/obj/machines/dominator.dmi differ diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi index 4d6c9a00bbb..f51725357a4 100644 Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ diff --git a/icons/obj/recycling.dmi b/icons/obj/recycling.dmi index 8661194c0d9..297eaf76e2f 100644 Binary files a/icons/obj/recycling.dmi and b/icons/obj/recycling.dmi differ diff --git a/icons/obj/singularity.dmi b/icons/obj/singularity.dmi index cc0156de462..3a9a5514b64 100644 Binary files a/icons/obj/singularity.dmi and b/icons/obj/singularity.dmi differ diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi index a30ab24fcbe..1797ac7cee0 100644 Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ diff --git a/icons/obj/stock_parts.dmi b/icons/obj/stock_parts.dmi index 03e4bae5b5f..8b5b5b812e4 100644 Binary files a/icons/obj/stock_parts.dmi and b/icons/obj/stock_parts.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index 175cfab6122..aac16abbd38 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index 91d53ce1dfd..41373c350c1 100644 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/sound/arcade/Boom.ogg b/sound/arcade/Boom.ogg new file mode 100644 index 00000000000..8adfb2bc430 Binary files /dev/null and b/sound/arcade/Boom.ogg differ diff --git a/sound/arcade/Heal.ogg b/sound/arcade/Heal.ogg new file mode 100644 index 00000000000..26f47195c65 Binary files /dev/null and b/sound/arcade/Heal.ogg differ diff --git a/sound/arcade/Hit.ogg b/sound/arcade/Hit.ogg new file mode 100644 index 00000000000..0bf18679a65 Binary files /dev/null and b/sound/arcade/Hit.ogg differ diff --git a/sound/arcade/Lose.ogg b/sound/arcade/Lose.ogg new file mode 100644 index 00000000000..dd2145737cd Binary files /dev/null and b/sound/arcade/Lose.ogg differ diff --git a/sound/arcade/Mana.ogg b/sound/arcade/Mana.ogg new file mode 100644 index 00000000000..7f26ae53fe7 Binary files /dev/null and b/sound/arcade/Mana.ogg differ diff --git a/sound/arcade/Steal.ogg b/sound/arcade/Steal.ogg new file mode 100644 index 00000000000..9c7b3be2a5a Binary files /dev/null and b/sound/arcade/Steal.ogg differ diff --git a/sound/arcade/Win.ogg b/sound/arcade/Win.ogg new file mode 100644 index 00000000000..27fb9725f20 Binary files /dev/null and b/sound/arcade/Win.ogg differ diff --git a/sound/effects/pray.ogg b/sound/effects/pray.ogg new file mode 100644 index 00000000000..beadd3916f1 Binary files /dev/null and b/sound/effects/pray.ogg differ diff --git a/sound/effects/pray_chaplain.ogg b/sound/effects/pray_chaplain.ogg new file mode 100644 index 00000000000..1b543275311 Binary files /dev/null and b/sound/effects/pray_chaplain.ogg differ diff --git a/sound/items/PSHOOM.ogg b/sound/items/PSHOOM.ogg new file mode 100644 index 00000000000..5628842f534 Binary files /dev/null and b/sound/items/PSHOOM.ogg differ diff --git a/sound/items/PSHOOM_2.ogg b/sound/items/PSHOOM_2.ogg new file mode 100644 index 00000000000..480b302fad8 Binary files /dev/null and b/sound/items/PSHOOM_2.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 55616d11204..e448e1b78bd 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -227,6 +227,7 @@ #include "code\datums\spells\genetic.dm" #include "code\datums\spells\inflict_handler.dm" #include "code\datums\spells\knock.dm" +#include "code\datums\spells\lichdom.dm" #include "code\datums\spells\lightning.dm" #include "code\datums\spells\mime.dm" #include "code\datums\spells\mind_transfer.dm" @@ -240,7 +241,6 @@ #include "code\datums\wires\alarm.dm" #include "code\datums\wires\apc.dm" #include "code\datums\wires\autolathe.dm" -#include "code\datums\wires\camera.dm" #include "code\datums\wires\explosive.dm" #include "code\datums\wires\mulebot.dm" #include "code\datums\wires\particle_accelerator.dm" @@ -326,7 +326,9 @@ #include "code\game\gamemodes\cult\runes.dm" #include "code\game\gamemodes\cult\talisman.dm" #include "code\game\gamemodes\extended\extended.dm" +#include "code\game\gamemodes\gang\dominator.dm" #include "code\game\gamemodes\gang\gang.dm" +#include "code\game\gamemodes\gang\recaller.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" @@ -579,7 +581,6 @@ #include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\pizza_bomb.dm" #include "code\game\objects\items\devices\powersink.dm" -#include "code\game\objects\items\devices\recaller.dm" #include "code\game\objects\items\devices\scanners.dm" #include "code\game\objects\items\devices\sensor_device.dm" #include "code\game\objects\items\devices\taperecorder.dm" @@ -818,6 +819,7 @@ #include "code\modules\admin\verbs\diagnostics.dm" #include "code\modules\admin\verbs\fps.dm" #include "code\modules\admin\verbs\getlogs.dm" +#include "code\modules\admin\verbs\machine_upgrade.dm" #include "code\modules\admin\verbs\mapping.dm" #include "code\modules\admin\verbs\massmodvar.dm" #include "code\modules\admin\verbs\modifyvariables.dm" @@ -930,6 +932,7 @@ #include "code\modules\events\anomaly_vortex.dm" #include "code\modules\events\blob.dm" #include "code\modules\events\brand_intelligence.dm" +#include "code\modules\events\camerafailure.dm" #include "code\modules\events\carp_migration.dm" #include "code\modules\events\communications_blackout.dm" #include "code\modules\events\disease_outbreak.dm" @@ -1331,8 +1334,12 @@ #include "code\modules\procedural mapping\mapGenerator.dm" #include "code\modules\procedural mapping\mapGeneratorModule.dm" #include "code\modules\procedural mapping\mapGeneratorReadme.dm" +#include "code\modules\procedural mapping\mapGeneratorModules\helpers.dm" #include "code\modules\procedural mapping\mapGeneratorModules\nature.dm" +#include "code\modules\procedural mapping\mapGenerators\asteroid.dm" #include "code\modules\procedural mapping\mapGenerators\nature.dm" +#include "code\modules\procedural mapping\mapGenerators\shuttle.dm" +#include "code\modules\procedural mapping\mapGenerators\syndicate.dm" #include "code\modules\projectiles\ammunition.dm" #include "code\modules\projectiles\firing.dm" #include "code\modules\projectiles\gun.dm" diff --git a/tools/dmifonts/DmiFonts.exe b/tools/dmifonts/DmiFonts.exe new file mode 100644 index 00000000000..ce1d694147a Binary files /dev/null and b/tools/dmifonts/DmiFonts.exe differ diff --git a/tools/dmifonts/DmiFonts.int b/tools/dmifonts/DmiFonts.int new file mode 100644 index 00000000000..b82874fded5 --- /dev/null +++ b/tools/dmifonts/DmiFonts.int @@ -0,0 +1,6 @@ +// BEGIN_INTERNALS +/* +MAP_ICON_TYPE: 0 +AUTO_FILE_DIR: OFF +*/ +// END_INTERNALS diff --git a/tools/dmifonts/DmiFonts.lk b/tools/dmifonts/DmiFonts.lk new file mode 100644 index 00000000000..e69de29bb2d