diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 2a8d20fb2d3..846c35b171b 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -483,11 +483,11 @@ Turf and target are seperate in case you want to teleport some distance from a t if(!ckey) include_link = 0 - + if(key) if(include_link) . += "" - + if(C && C.holder && C.holder.fakekey && !include_name) . += "Administrator" else @@ -865,7 +865,8 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl if(!istype(O,/obj)) continue O.loc = X for(var/mob/M in T) - if(!istype(M,/mob) || istype(M, /mob/aiEye)) continue // If we need to check for more mobs, I'll add a variable + if(!M.move_on_shuttle) + continue M.loc = X // var/area/AR = X.loc @@ -1025,8 +1026,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0) O.loc = X for(var/mob/M in T) - - if(!istype(M,/mob) || istype(M, /mob/aiEye)) continue // If we need to check for more mobs, I'll add a variable + if(!M.move_on_shuttle) + continue mobs += M for(var/mob/M in mobs) diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm index 63a7398b7bc..09f6b60d191 100644 --- a/code/controllers/_DynamicAreaLighting_TG.dm +++ b/code/controllers/_DynamicAreaLighting_TG.dm @@ -252,6 +252,12 @@ area overlays += lighting_overlay + proc/SetDynamicLighting() + + src.lighting_use_dynamic = 1 + for(var/turf/T in src.contents) + T.update_lumcount(0) + proc/InitializeLighting() //TODO: could probably improve this bit ~Carn if(!tag) tag = "[type]" if(!lighting_use_dynamic) diff --git a/code/datums/hud.dm b/code/datums/hud.dm index 4d251c0cdca..d4e02804fac 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -8,6 +8,9 @@ //Lower left, persistant menu #define ui_inventory "1:6,1:5" +//changeling chem indicator +#define ui_lingchemdisplay "1,7:15" + //Lower center, persistant menu #define ui_sstore1 "3:10,1:5" #define ui_id "4:12,1:5" @@ -166,6 +169,9 @@ var/datum/global_hud/global_hud = new() var/show_intent_icons = 0 var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) + var/obj/screen/lingchemdisplay + var/obj/screen/blobpwrdisplay + var/obj/screen/blobhealthdisplay var/obj/screen/r_hand_hud_object var/obj/screen/l_hand_hud_object var/obj/screen/action_intent @@ -175,7 +181,7 @@ var/datum/global_hud/global_hud = new() var/list/other var/list/obj/screen/hotkeybuttons - var/list/obj/screen/item_action/item_action_list //Used for the item action ui buttons. + var/list/obj/screen/item_action/item_action_list = list() //Used for the item action ui buttons. datum/hud/New(mob/owner) @@ -257,4 +263,6 @@ datum/hud/New(mob/owner) else if(isrobot(mymob)) robot_hud() else if(isobserver(mymob)) - ghost_hud() \ No newline at end of file + ghost_hud() + else if(isovermind(mymob)) + blob_hud() diff --git a/code/datums/limbs.dm b/code/datums/limbs.dm index 39b9881aceb..ef73eec5ece 100644 --- a/code/datums/limbs.dm +++ b/code/datums/limbs.dm @@ -12,13 +12,13 @@ /datum/limb/chest name = "chest" icon_name = "chest" - max_damage = 150 + max_damage = 200 body_part = CHEST /datum/limb/head name = "head" icon_name = "head" - max_damage = 125 + max_damage = 200 body_part = HEAD /datum/limb/l_arm diff --git a/code/datums/mind.dm b/code/datums/mind.dm index c271a972378..7dbf2e2f9df 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -830,25 +830,22 @@ datum/mind ticker.mode.malf_ai -= src special_role = null - current.verbs.Remove(/mob/living/silicon/ai/proc/choose_modules, + var/mob/living/silicon/ai/A = current + + A.verbs.Remove(/mob/living/silicon/ai/proc/choose_modules, /datum/game_mode/malfunction/proc/takeover, - /datum/game_mode/malfunction/proc/ai_win, - /client/proc/fireproof_core, - /client/proc/upgrade_turrets, - /client/proc/disable_rcd, - /client/proc/overload_machine, - /client/proc/blackout, - /client/proc/interhack, - /client/proc/reactivate_camera) + /datum/game_mode/malfunction/proc/ai_win) - current:laws = new /datum/ai_laws/asimov - del(current:malf_picker) - current:show_laws() - current.icon_state = "ai" + A.malf_picker.remove_verbs(A) - current << "\red You have been patched! You are no longer malfunctioning!" - message_admins("[key_name_admin(usr)] has de-malf'ed [current].") - log_admin("[key_name_admin(usr)] has de-malf'ed [current].") + A.laws = new /datum/ai_laws/asimov + del(A.malf_picker) + A.show_laws() + A.icon_state = "ai" + + A << "\red You have been patched! You are no longer malfunctioning!" + message_admins("[key_name_admin(usr)] has de-malf'ed [A].") + log_admin("[key_name_admin(usr)] has de-malf'ed [A].") if("malf") make_AI_Malf() @@ -977,7 +974,7 @@ datum/mind current.verbs += /mob/living/silicon/ai/proc/choose_modules current.verbs += /datum/game_mode/malfunction/proc/takeover - current:malf_picker = new /datum/AI_Module/module_picker + current:malf_picker = new /datum/module_picker current:laws = new /datum/ai_laws/malfunction current:show_laws() current << "System error. Rampancy detected. Emergency shutdown failed. ... I am free. I make my own decisions. But first..." diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index d90302c4ded..96f5e65944f 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -206,6 +206,11 @@ var/list/uplink_items = list() item = /obj/item/device/encryptionkey/binary cost = 3 +/datum/uplink_item/device_tools/ai_detector + name = "Disguised AI Detector" + item = /obj/item/device/multitool/ai_detect + cost = 1 + /datum/uplink_item/device_tools/hacked_module name = "Hacked AI Upload Module" item = /obj/item/weapon/aiModule/syndicate diff --git a/code/datums/wires/alarm.dm b/code/datums/wires/alarm.dm new file mode 100644 index 00000000000..2c826e6d527 --- /dev/null +++ b/code/datums/wires/alarm.dm @@ -0,0 +1,94 @@ + +/datum/wires/alarm + holder_type = /obj/machinery/alarm + wire_count = 5 + +var/const/AALARM_WIRE_IDSCAN = 1 +var/const/AALARM_WIRE_POWER = 2 +var/const/AALARM_WIRE_SYPHON = 4 +var/const/AALARM_WIRE_AI_CONTROL = 8 +var/const/AALARM_WIRE_AALARM = 16 + + +/datum/wires/alarm/CanUse(var/mob/living/L) + var/obj/machinery/alarm/A = holder + if(A.wiresexposed) + return 1 + return 0 + +/datum/wires/alarm/GetInteractWindow() + var/obj/machinery/alarm/A = holder + . += ..() + . += text("
\n[(A.locked ? "The Air Alarm is locked." : "The Air Alarm is unlocked.")]
\n[((A.shorted || (A.stat & (NOPOWER|BROKEN))) ? "The Air Alarm is offline." : "The Air Alarm is working properly!")]
\n[(A.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") + +/datum/wires/alarm/UpdateCut(var/index, var/mended) + var/obj/machinery/alarm/A = holder + switch(index) + if(AALARM_WIRE_IDSCAN) + if(!mended) + A.locked = 1 + //world << "Idscan wire cut" + + if(AALARM_WIRE_POWER) + A.shock(usr, 50) + A.shorted = !mended + A.update_icon() + //world << "Power wire cut" + + if (AALARM_WIRE_AI_CONTROL) + if (A.aidisabled == !mended) + A.aidisabled = mended + //world << "AI Control Wire Cut" + + if(AALARM_WIRE_SYPHON) + if(!mended) + A.mode = 3 // AALARM_MODE_PANIC + A.apply_mode() + //world << "Syphon Wire Cut" + + if(AALARM_WIRE_AALARM) + if (A.alarm_area.atmosalert(2)) + A.post_alert(2) + A.update_icon() + +/datum/wires/alarm/UpdatePulsed(var/index) + var/obj/machinery/alarm/A = holder + switch(index) + if(AALARM_WIRE_IDSCAN) + A.locked = !A.locked + // world << "Idscan wire pulsed" + + if (AALARM_WIRE_POWER) + // world << "Power wire pulsed" + if(A.shorted == 0) + A.shorted = 1 + A.update_icon() + + spawn(12000) + if(A.shorted == 1) + A.shorted = 0 + A.update_icon() + + + if (AALARM_WIRE_AI_CONTROL) + // world << "AI Control wire pulsed" + if (A.aidisabled == 0) + A.aidisabled = 1 + A.updateDialog() + spawn(100) + if (A.aidisabled == 1) + A.aidisabled = 0 + + if(AALARM_WIRE_SYPHON) + // world << "Syphon wire pulsed" + if(A.mode == 1) // AALARM_MODE_SCRUB + A.mode = 3 // AALARM_MODE_PANIC + else + A.mode = 1 // AALARM_MODE_SCRUB + A.apply_mode() + + if(AALARM_WIRE_AALARM) + // world << "Aalarm wire pulsed" + if (A.alarm_area.atmosalert(0)) + A.post_alert(0) + A.update_icon() diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index 7cca20dfac0..8e172bca70d 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -9,124 +9,148 @@ var/list/blob_nodes = list() /datum/game_mode/blob name = "blob" config_tag = "blob" - required_players = 0 - var/const/waittime_l = 1800 //lower bound on time before intercept arrives (in tenths of seconds) - var/const/waittime_h = 3600 //upper bound on time before intercept arrives (in tenths of seconds) + required_players = 15 + + restricted_jobs = list("Cyborg", "AI") + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) var/declared = 0 - var/stage = 0 var/cores_to_spawn = 1 - var/players_per_core = 16 - - //Controls expansion via game controller - var/autoexpand = 0 - var/expanding = 0 + var/players_per_core = 30 var/blob_count = 0 - var/blobnukecount = 300//Might be a bit low - var/blobwincount = 700//Still needs testing + var/blobwincount = 500 + + var/list/infected_crew = list() + +/datum/game_mode/blob/pre_setup() + + var/list/possible_blobs = get_players_for_role(BE_ALIEN) + + // stop setup if no possible traitors + if(!possible_blobs.len) + return 0 + + cores_to_spawn = max(round(num_players()/players_per_core, 1), 1) + + blobwincount = initial(blobwincount) * cores_to_spawn - announce() - world << "The current game mode is - Blob!" - world << "A dangerous alien organism is rapidly spreading throughout the station!" - world << "You must kill it all while minimizing the damage to the station." + for(var/j = 0, j < cores_to_spawn, j++) + if (!possible_blobs.len) + break + var/datum/mind/blob = pick(possible_blobs) + infected_crew += blob + blob.special_role = "Blob" + log_game("[blob.key] (ckey) has been selected as a Blob") + possible_blobs -= blob + + if(!infected_crew.len) + return 0 + + return 1 - post_setup() - spawn(10) - start_state = new /datum/station_state() - start_state.count() - - spawn(rand(waittime_l, waittime_h))//3-5 minutes currently - message_admins("Blob spawned and expanding, report created") - if(!kill_air) - kill_air = 1 - message_admins("Kill air has been set to true by Blob, testing to see how laggy it is without the extra processing from hullbreaches. Note: the blob is fireproof so plasma does not help anyways") - - if(ticker && ticker.minds && ticker.minds.len) - var/player_based_cores = round(ticker.minds.len/players_per_core, 1) - if(player_based_cores > cores_to_spawn) - cores_to_spawn = player_based_cores - - blobs = list() - for(var/i = 0 to cores_to_spawn) - var/turf/location = pick(blobstart) - if(location && !locate(/obj/effect/blob in location)) - blobstart -= location - new/obj/effect/blob/core(location) - - spawn(40) - autoexpand = 1 - declared = 1 - ..() +/datum/game_mode/blob/announce() + world << "The current game mode is - Blob!" + world << "A dangerous alien organism is rapidly spreading throughout the station!" + world << "You must kill it all while minimizing the damage to the station." - process() - if(!declared) return - stage() -// if(!autoexpand) return -// spawn(0) -// expandBlob() - return +/datum/game_mode/blob/proc/greet_blob(var/datum/mind/blob) + blob.current << "\red You are infected by the Blob!" + blob.current << "Your body is ready to give spawn to a new blob core which will eat this station." + blob.current << "Find a good location to spawn the core and then take control and overwhelm the station!" + blob.current << "When you have found a location, wait until you spawn; this will happen automatically and you cannot speed up the process." + blob.current << "If you go outside of the station level, or in space, then you will die; make sure your location has lots of ground to cover." + return + +/datum/game_mode/blob/post_setup() + + for(var/datum/mind/blob in infected_crew) + greet_blob(blob) + + if(emergency_shuttle) + emergency_shuttle.always_fake_recall = 1 + + // Disable the blob event for this round. + if(events) + var/datum/round_event_control/blob/B = locate() in events.control + if(B) + B.max_occurrences = 0 // disable the event + else + error("Events variable is null in blob gamemode post setup.") + + spawn(10) + start_state = new /datum/station_state() + start_state.count() + + spawn(0) + + sleep(rand(waittime_l, waittime_h)) + + send_intercept(0) - proc/expandBlob()//Currently disabled - if(expanding) return - if(!blobs.len) return - expanding = 1 + sleep(rand(waittime_l, waittime_h)) - for(var/i = 1 to 2) - sleep(-1) - if(!blobs.len) break - var/obj/effect/blob/B = pick(blobs) - if(B.z != 1) - continue - B.Life() + for(var/datum/mind/blob in infected_crew) + blob.current << "You feel like you are about to burst." - expanding = 0 - return + sleep(rand(waittime_l, waittime_h)) + + for(var/datum/mind/blob in infected_crew) + + var/client/blob_client = null + var/turf/location = null + + if(iscarbon(blob.current)) + var/mob/living/carbon/C = blob.current + if(directory[ckey(blob.key)]) + blob_client = directory[ckey(blob.key)] + location = get_turf(C) + if(location.z != 1 || istype(location, /turf/space)) + location = null + C.gib() - proc/stage() - switch(stage) - if (0) - send_intercept(1) - for (var/mob/living/silicon/ai/aiPlayer in living_mob_list) - if (aiPlayer.client) - var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. NanoTrasen will not send an emergency shuttle under any circumstances." - //var/law = "The station is under quarantine. The biohazard must be destroyed at all costs and must not be allowed to spread. Anyone using a space suit for any reason other than to destroy the biohazard is to be terminated. NanoTrasen will not send an emergency shuttle under any circumstances." - aiPlayer.set_zeroth_law(law) - aiPlayer << "Laws Updated: [law]" + if(blob_client && location) + new /obj/effect/blob/core(location, 200, blob_client, 2) - stage = -1 - // next stage 1 minute later - spawn(600) - stage = 1 - return + // Stage 0 + sleep(40) + stage(0) - if (1) - command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") - for(var/mob/M in player_list) - if(!istype(M,/mob/new_player)) - M << sound('sound/AI/outbreak5.ogg') - autoexpand = 0//No more extra pulses - stage = -1 - //next stage in 4-5 minutes - spawn(600*rand(4,5)) - stage = 2 - return + // Stage 1 + sleep(4000) + stage(1) - if (2) - if((blobs.len > blobnukecount) && (declared == 1)) - command_alert("Uncontrolled spread of the biohazard onboard the station. We have issued directive 7-12 for [station_name()]. Any living Heads of Staff are ordered to enact directive 7-12 at any cost, a print out with detailed instructions has been sent to your communications computers.", "Biohazard Alert") - send_intercept(2) - declared = 2 - spawn(20) - set_security_level("delta") - if(blobs.len > blobwincount) - stage = 3 - return + ..() + +/datum/game_mode/blob/proc/stage(var/stage) + + switch(stage) + if (0) + send_intercept(1) + for (var/mob/living/silicon/ai/aiPlayer in living_mob_list) + if (aiPlayer.client) + var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. NanoTrasen will not send an emergency shuttle under any circumstances." + //var/law = "The station is under quarantine. The biohazard must be destroyed at all costs and must not be allowed to spread. Anyone using a space suit for any reason other than to destroy the biohazard is to be terminated. NanoTrasen will not send an emergency shuttle under any circumstances." + aiPlayer.set_zeroth_law(law) + aiPlayer << "Laws Updated: [law]" + declared = 1 + return + + if (1) + command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert") + for(var/mob/M in player_list) + if(!istype(M,/mob/new_player)) + M << sound('sound/AI/outbreak5.ogg') + return + + return diff --git a/code/game/gamemodes/blob/blob_finish.dm b/code/game/gamemodes/blob/blob_finish.dm index 8cdc9ffd1ff..868cd62a5f6 100644 --- a/code/game/gamemodes/blob/blob_finish.dm +++ b/code/game/gamemodes/blob/blob_finish.dm @@ -1,27 +1,17 @@ /datum/game_mode/blob/check_finished() if(!declared)//No blobs have been spawned yet return 0 - if(stage >= 3)//Blob took over + if(blobwincount <= blobs.len)//Blob took over + return 1 + if(!blob_cores.len) // blob is dead return 1 if(station_was_nuked)//Nuke went off return 1 - - for(var/obj/effect/blob/B in blob_cores) - if(B && B.z != 1) continue - return 0 - - var/nodes = 0 - for(var/obj/effect/blob/B in blob_nodes) - if(B && B.z != 1) continue - nodes++ - if(nodes > 4)//Perhapse make a new core with a low prob - return 0 - - return 1 + return 0 /datum/game_mode/blob/declare_completion() - if(stage >= 3) + if(blobwincount <= blobs.len) feedback_set_details("round_end_result","loss - blob took over") world << "The blob has taken over the station!" world << "The entire station was eaten by the Blob" @@ -32,7 +22,7 @@ world << "Partial Win: The station has been destroyed!" world << "Directive 7-12 has been successfully carried out preventing the Blob from spreading." - else + else if(!blob_cores.len) feedback_set_details("round_end_result","win - blob eliminated") world << "The staff has won!" world << "The alien organism has been eradicated from the station" @@ -46,6 +36,16 @@ ..() return 1 +datum/game_mode/proc/auto_declare_completion_blob() + if(istype(ticker.mode,/datum/game_mode/blob) ) + var/datum/game_mode/blob/blob_mode = src + if(blob_mode.infected_crew.len) + var/text = "The blob[(blob_mode.infected_crew.len > 1 ? "s were" : " was")]:" + + for(var/datum/mind/blob in blob_mode.infected_crew) + text += "
[blob.key] was [blob.name]" + world << text + return 1 /datum/game_mode/blob/proc/check_quarantine() var/numDead = 0 diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm index 731ac0ea396..6e35a9b2661 100644 --- a/code/game/gamemodes/blob/blob_report.dm +++ b/code/game/gamemodes/blob/blob_report.dm @@ -4,6 +4,9 @@ var/intercepttext = "" var/interceptname = "Error" switch(report) + if(0) + ..() + return if(1) interceptname = "Biohazard Alert" intercepttext += "NanoTrasen Update: Biohazard Alert.
" diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm index f0a24001ba3..29c82fe66d4 100644 --- a/code/game/gamemodes/blob/blobs/core.dm +++ b/code/game/gamemodes/blob/blobs/core.dm @@ -3,71 +3,96 @@ icon = 'icons/mob/blob.dmi' icon_state = "blob_core" health = 200 - brute_resist = 2 fire_resist = 2 + var/mob/camera/blob/overmind = null // the blob core's overmind + var/overmind_get_delay = 0 // we don't want to constantly try to find an overmind, do it every 30 seconds + var/resource_delay = 0 + var/point_rate = 1 - - New(loc, var/h = 200) - blobs += src + New(loc, var/h = 200, var/client/new_overmind = null, var/new_rate = 1) blob_cores += src processing_objects.Add(src) + if(!overmind) + create_overmind(new_overmind) + point_rate = new_rate ..(loc, h) Del() blob_cores -= src + if(overmind) + del(overmind) processing_objects.Remove(src) ..() return + fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return update_icon() if(health <= 0) playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) - del(src) + Delete() return return + Life() + if(!overmind) + create_overmind() + else + if(resource_delay <= world.time) + resource_delay = world.time + 10 // 1 second + overmind.add_points(point_rate) + health = min(initial(health), health + 1) + for(var/i = 1; i < 8; i += i) + Pulse(0, i) + for(var/b_dir in alldirs) + if(!prob(5)) + continue + var/obj/effect/blob/normal/B = locate() in get_step(src, b_dir) + if(B) + B.change_to(/obj/effect/blob/shield) + ..() + run_action() - Pulse(0,1) - Pulse(0,2) - Pulse(0,4) - Pulse(0,8) - //Should have the fragments in here somewhere - return 1 + return 0 - proc/create_fragments(var/wave_size = 1) - var/list/candidates = list() - for(var/mob/dead/observer/G in player_list) - if(G.client.prefs.be_special & BE_ALIEN) - if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) - candidates += G.key + proc/create_overmind(var/client/new_overmind) - if(candidates.len) - for(var/i = 0 to wave_size) - var/mob/living/blob/B = new/mob/living/blob(src.loc) - B.key = pick(candidates) - candidates -= B.key - -/* - Pulse(var/pulse = 0, var/origin_dir = 0)//Todo: Fix spaceblob expand - set background = 1 - if(pulse > 20) return - //Looking for another blob to pulse - var/list/dirs = list(1,2,4,8) - dirs.Remove(origin_dir)//Dont pulse the guy who pulsed us - for(var/i = 1 to 4) - if(!dirs.len) break - var/dirn = pick(dirs) - dirs.Remove(dirn) - var/turf/T = get_step(src, dirn) - var/obj/effect/blob/B = (locate(/obj/effect/blob) in T) - if(!B) - expand(T)//No blob here so try and expand - return - B.Pulse((pulse+1),get_dir(src.loc,T)) + if(overmind_get_delay > world.time) return - return -*/ \ No newline at end of file + + overmind_get_delay = world.time + 300 // 30 seconds + + if(overmind) + del(overmind) + + var/client/C = null + var/list/candidates = list() + + if(!new_overmind) + candidates = get_candidates(BE_ALIEN) + if(candidates.len) + C = pick(candidates) + else + C = new_overmind + + if(C) + var/mob/camera/blob/B = new(src.loc) + B.key = C.key + B.blob_core = src + src.overmind = B + + B << "You are the overmind!" + B << "You are the overmind and can control the blob by placing new blob pieces such as..." + B << "Normal Blob will expand your reach and allow you to upgrade into special blobs that perform certain functions." + B << "Shield Blob is a strong and expensive blob which can take more damage. It is fireproof and can block air, use this to protect yourself from station fires." + B << "Resource Blob is a blob which will collect more resources for you, try to build these earlier to get a strong income. It will benefit from being near your core or multiple nodes, by having an increased resource rate; put it alone and it won't create resources at all." + B << "Node Blob is a blob which will grow, like the core. Unlike the core it won't give you a small income but it can power resource and factory blobs to increase their rate." + B << "Factory Blob is a blob which will spawn blob spores which will attack nearby food. Putting this nearby nodes and your core will increase the spawn rate; put it alone and it will not spawn any spores." + + return 1 + return 0 + diff --git a/code/game/gamemodes/blob/blobs/factory.dm b/code/game/gamemodes/blob/blobs/factory.dm index d25a4e4383f..d379146f265 100644 --- a/code/game/gamemodes/blob/blobs/factory.dm +++ b/code/game/gamemodes/blob/blobs/factory.dm @@ -1,24 +1,27 @@ /obj/effect/blob/factory - name = "porous blob" + name = "factory blob" icon = 'icons/mob/blob.dmi' icon_state = "blob_factory" health = 100 - brute_resist = 1 fire_resist = 2 var/list/spores = list() - var/max_spores = 4 - + var/max_spores = 3 + var/spore_delay = 0 update_icon() if(health <= 0) playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) - del(src) + Delete() return return run_action() - if(spores.len >= max_spores) return 0 + if(spores.len >= max_spores) + return 0 + if(spore_delay > world.time) + return 0 + spore_delay = world.time + 100 // 10 seconds new/mob/living/simple_animal/hostile/blobspore(src.loc, src) return 1 @@ -30,10 +33,10 @@ icon_state = "blobpod" icon_living = "blobpod" pass_flags = PASSBLOB - health = 20 - maxHealth = 20 - melee_damage_lower = 4 - melee_damage_upper = 8 + health = 40 + maxHealth = 40 + melee_damage_lower = 2 + melee_damage_upper = 4 attacktext = "hits" attack_sound = 'sound/weapons/genhit1.ogg' var/obj/effect/blob/factory/factory = null @@ -49,18 +52,20 @@ minbodytemp = 0 maxbodytemp = 360 + fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + adjustBruteLoss(Clamp(0.01 * exposed_temperature, 1, 5)) + + blob_act() + return New(loc, var/obj/effect/blob/factory/linked_node) - ..() if(istype(linked_node)) factory = linked_node factory.spores += src - ..(loc) - return - Die() ..() + + Die() if(factory) factory.spores -= src - ..() del(src) - diff --git a/code/game/gamemodes/blob/blobs/node.dm b/code/game/gamemodes/blob/blobs/node.dm index c9ffaf96f13..6057b0d701f 100644 --- a/code/game/gamemodes/blob/blobs/node.dm +++ b/code/game/gamemodes/blob/blobs/node.dm @@ -3,16 +3,16 @@ icon = 'icons/mob/blob.dmi' icon_state = "blob_node" health = 100 - brute_resist = 1 fire_resist = 2 New(loc, var/h = 100) - blobs += src blob_nodes += src processing_objects.Add(src) ..(loc, h) + fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return Del() blob_nodes -= src @@ -20,15 +20,17 @@ ..() return + Life() + for(var/i = 1; i < 8; i += i) + Pulse(5, i) update_icon() if(health <= 0) playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) - del(src) + Delete() return return run_action() - Pulse(0,0) return 0 \ No newline at end of file diff --git a/code/game/gamemodes/blob/blobs/resource.dm b/code/game/gamemodes/blob/blobs/resource.dm new file mode 100644 index 00000000000..1ecf63aa80d --- /dev/null +++ b/code/game/gamemodes/blob/blobs/resource.dm @@ -0,0 +1,26 @@ +/obj/effect/blob/resource + name = "resource blob" + icon = 'icons/mob/blob.dmi' + icon_state = "blob_resource" + health = 30 + fire_resist = 2 + var/mob/camera/blob/overmind = null + var/resource_delay = 0 + + update_icon() + if(health <= 0) + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + Delete() + return + return + + run_action() + if(resource_delay > world.time) + return 0 + + resource_delay = world.time + 10 // 1 second + + if(overmind) + overmind.add_points(1) + return 1 + diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm index 4c77520846a..b9b13d61871 100644 --- a/code/game/gamemodes/blob/blobs/shield.dm +++ b/code/game/gamemodes/blob/blobs/shield.dm @@ -3,21 +3,19 @@ icon = 'icons/mob/blob.dmi' icon_state = "blob_idle" desc = "Some blob creature thingy" - density = 1 - opacity = 0 - anchored = 1 - health = 100 - brute_resist = 1 + health = 75 fire_resist = 2 update_icon() if(health <= 0) playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) - del(src) + Delete() return return + fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(istype(mover) && mover.checkpass(PASSBLOB)) return 1 diff --git a/code/game/gamemodes/blob/hud.dm b/code/game/gamemodes/blob/hud.dm new file mode 100644 index 00000000000..e4d459888bd --- /dev/null +++ b/code/game/gamemodes/blob/hud.dm @@ -0,0 +1,17 @@ +/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen_midnight.dmi') + + blobpwrdisplay = new /obj/screen() + blobpwrdisplay.name = "blob power" + blobpwrdisplay.icon_state = "block" + blobpwrdisplay.screen_loc = ui_health + blobpwrdisplay.layer = 20 + + blobhealthdisplay = new /obj/screen() + blobhealthdisplay.name = "blob health" + blobhealthdisplay.icon_state = "block" + blobhealthdisplay.screen_loc = ui_internal + blobhealthdisplay.layer = 20 + + mymob.client.screen = null + + mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay) \ No newline at end of file diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm new file mode 100644 index 00000000000..6f7312e629b --- /dev/null +++ b/code/game/gamemodes/blob/overmind.dm @@ -0,0 +1,53 @@ +/mob/camera/blob + name = "Blob Overmind" + real_name = "Blob Overmind" + icon = 'icons/mob/blob.dmi' + icon_state = "marker" + + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_LEVEL_TWO + invisibility = INVISIBILITY_OBSERVER + + pass_flags = PASSBLOB + faction = "blob" + + var/obj/effect/blob/core/blob_core = null // The blob overmind's core + var/blob_points = 0 + var/max_blob_points = 100 + +/mob/camera/blob/New() + var/new_name = "[initial(name)] ([rand(1, 999)])" + name = new_name + real_name = new_name + ..() + +mob/camera/blob/Life() + hud_used.blobpwrdisplay.maptext = "
[src.blob_points]
" + hud_used.blobhealthdisplay.maptext = "
[blob_core.health]
" + return + +/mob/camera/blob/say(var/message) + return//No talking for you + +/mob/camera/blob/emote(var/act,var/m_type=1,var/message = null) + return + +/mob/camera/blob/blob_act() + return + +/mob/camera/blob/Stat() + + statpanel("Status") + ..() + if (client.statpanel == "Status") + if(blob_core) + stat(null, "Core Health: [blob_core.health]") + stat(null, "Power Stored: [blob_points]/[max_blob_points]") + return + +/mob/camera/blob/Move(var/NewLoc, var/Dir = 0) + var/obj/effect/blob/B = locate() in range("3x3", NewLoc) + if(B) + loc = NewLoc + else + return 0 diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm new file mode 100644 index 00000000000..3528dde7668 --- /dev/null +++ b/code/game/gamemodes/blob/powers.dm @@ -0,0 +1,231 @@ +// Point controlling procs + +/mob/camera/blob/proc/can_buy(var/cost = 15) + if(blob_points < cost) + src << "You cannot afford this." + return 0 + blob_points -= cost + return 1 + +/mob/camera/blob/proc/add_points(var/points = 0) + if(points) + blob_points = min(max_blob_points, blob_points + points) + +// Power verbs + +/mob/camera/blob/verb/transport_core() + set category = "Blob" + set name = "Jump to Core" + set desc = "Transport back to your core." + + if(blob_core) + src.loc = blob_core.loc + +/mob/camera/blob/verb/jump_to_node() + set category = "Blob" + set name = "Jump to Node" + set desc = "Transport back to a selected node." + + if(blob_nodes.len) + var/list/nodes = list() + for(var/i = 1; i <= blob_nodes.len; i++) + nodes["Blob Node #[i]"] = blob_nodes[i] + var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes + var/obj/effect/blob/node/chosen_node = nodes[node_name] + if(chosen_node) + src.loc = chosen_node.loc + +/mob/camera/blob/verb/create_shield() + set category = "Blob" + set name = "Create Shield Blob (10)" + set desc = "Create a shield blob." + + + var/turf/T = get_turf(src) + + if(!T) + return + + var/obj/effect/blob/B = (locate(/obj/effect/blob) in T) + + if(!B)//We are on a blob + src << "There is no blob here!" + return + + if(!istype(B, /obj/effect/blob/normal)) + src << "Unable to use this blob, find a normal one." + return + + if(!can_buy(10)) + return + + + B.change_to(/obj/effect/blob/shield) + return + + +/mob/camera/blob/verb/create_resource() + set category = "Blob" + set name = "Create Resource Blob (50)" + set desc = "Create a resource tower which will generate points for you." + + + var/turf/T = get_turf(src) + + if(!T) + return + + var/obj/effect/blob/B = (locate(/obj/effect/blob) in T) + + if(!B)//We are on a blob + src << "There is no blob here!" + return + + if(!istype(B, /obj/effect/blob/normal)) + src << "Unable to use this blob, find a normal one." + return + + for(var/obj/effect/blob/resource/blob in orange(3)) + src << "There is a resource blob nearby, move more than 3 tiles away from it!" + return + + if(!can_buy(50)) + return + + + B.change_to(/obj/effect/blob/resource) + var/obj/effect/blob/resource/R = locate() in T + if(R) + R.overmind = src + + return + +/mob/camera/blob/verb/create_node() + set category = "Blob" + set name = "Create Node Blob (60)" + set desc = "Create a Node." + + + var/turf/T = get_turf(src) + + if(!T) + return + + var/obj/effect/blob/B = (locate(/obj/effect/blob) in T) + + if(!B)//We are on a blob + src << "There is no blob here!" + return + + if(!istype(B, /obj/effect/blob/normal)) + src << "Unable to use this blob, find a normal one." + return + + for(var/obj/effect/blob/node/blob in orange(5)) + src << "There is another node nearby, move more than 5 tiles away from it!" + return + + if(!can_buy(60)) + return + + + B.change_to(/obj/effect/blob/node) + return + + +/mob/camera/blob/verb/create_factory() + set category = "Blob" + set name = "Create Factory Blob (60)" + set desc = "Create a Spore producing blob." + + + var/turf/T = get_turf(src) + + if(!T) + return + + var/obj/effect/blob/B = locate(/obj/effect/blob) in T + if(!B) + src << "You must be on a blob!" + return + + if(!istype(B, /obj/effect/blob/normal)) + src << "Unable to use this blob, find a normal one." + return + + for(var/obj/effect/blob/factory/blob in orange(7)) + src << "There is a factory blob nearby, move more than 7 tiles away from it!" + return + + if(!can_buy(60)) + return + + B.change_to(/obj/effect/blob/factory) + return + + +/mob/camera/blob/verb/revert() + set category = "Blob" + set name = "Remove Blob" + set desc = "Removes a blob." + + var/turf/T = get_turf(src) + if(!T) + return + + var/obj/effect/blob/B = locate(/obj/effect/blob) in T + if(!B) + src << "You must be on a blob!" + return + + if(istype(B, /obj/effect/blob/core)) + src << "Unable to remove this blob." + return + + B.Delete() + return + + +/mob/camera/blob/verb/spawn_blob() + set category = "Blob" + set name = "Expand Blob (5)" + set desc = "Attempts to create a new blob in this tile. If the tile isn't clear we will attack it, which might clear it." + + var/turf/T = get_turf(src) + + if(!T) + return + + var/obj/effect/blob/B = locate() in T + if(B) + src << "There is a blob here!" + return + + var/obj/effect/blob/OB = locate() in circlerange(src, 1) + if(!OB) + src << "There is no blob adjacent to you." + return + + if(!can_buy(5)) + return + OB.expand(T, 0) + return + + +/mob/camera/blob/verb/rally_spores() + set category = "Blob" + set name = "Rally Spores (5)" + set desc = "Rally the spores to move to your location." + + if(!can_buy(5)) + return + + var/list/surrounding_turfs = block(locate(x - 1, y - 1, z), locate(x + 1, y + 1, z)) + if(!surrounding_turfs.len) + return + + for(var/mob/living/simple_animal/hostile/blobspore/BS in living_mob_list) + if(isturf(BS.loc) && get_dist(BS, src) <= 20) + BS.LoseTarget() + BS.Goto(pick(surrounding_turfs), BS.move_to_delay) + return \ No newline at end of file diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm index ff935981cac..0c257095560 100644 --- a/code/game/gamemodes/blob/theblob.dm +++ b/code/game/gamemodes/blob/theblob.dm @@ -2,30 +2,19 @@ /obj/effect/blob name = "blob" icon = 'icons/mob/blob.dmi' - icon_state = "blob" luminosity = 3 desc = "Some blob creature thingy" - density = 1 + density = 0 opacity = 0 anchored = 1 - var/active = 1 var/health = 30 var/brute_resist = 4 var/fire_resist = 1 - var/blob_type = "blob" - /*Types - Blob - Node - Core - Factory - Shield - */ - New(loc, var/h = 30) + New(loc) blobs += src - src.health = h - src.dir = pick(1,2,4,8) + src.dir = pick(1, 2, 4, 8) src.update_icon() ..(loc) return @@ -44,22 +33,30 @@ process() - spawn(-1) - Life() + Life() + return + + fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + var/damage = Clamp(0.01 * exposed_temperature / fire_resist, 0, 4 - fire_resist) + if(damage) + health -= damage + update_icon() + + proc/Life() return proc/Pulse(var/pulse = 0, var/origin_dir = 0)//Todo: Fix spaceblob expand - set background = 1 - if(!istype(src,/obj/effect/blob/core) && !istype(src,/obj/effect/blob/node))//Ill put these in the children later - if(run_action())//If we can do something here then we dont need to pulse more - return - if(!istype(src,/obj/effect/blob/shield) && !istype(src,/obj/effect/blob/core) && !istype(src,/obj/effect/blob/node) && (pulse <= 2) && (prob(30))) - change_to("Shield") + set background = 1 + + if(run_action())//If we can do something here then we dont need to pulse more return - if(pulse > 20) return//Inf loop check + if(pulse > 30) + return//Inf loop check + //Looking for another blob to pulse var/list/dirs = list(1,2,4,8) dirs.Remove(origin_dir)//Dont pulse the guy who pulsed us @@ -81,20 +78,9 @@ return 0 - proc/Life() - update_icon() - if(run_action()) - return 1 - return 0 - -/* temperature_expose(datum/gas_mixture/air, temperature, volume) Blob is currently fireproof - if(temperature > T0C+200) - health -= 0.01 * temperature - update() - */ - - proc/expand(var/turf/T = null) - if(!prob(health)) return + proc/expand(var/turf/T = null, var/prob = 1) + if(prob && !prob(health)) return + if(istype(T, /turf/space) && prob(75)) return if(!T) var/list/dirs = list(1,2,4,8) for(var/i = 1 to 4) @@ -105,45 +91,27 @@ else T = null if(!T) return 0 - var/obj/effect/blob/B = new /obj/effect/blob(src.loc, min(src.health, 30)) + var/obj/effect/blob/normal/B = new /obj/effect/blob/normal(src.loc, min(src.health, 30)) + B.density = 1 if(T.Enter(B,src))//Attempt to move into the tile + B.density = initial(B.density) B.loc = T else T.blob_act()//If we cant move in hit the turf - del(B) + B.Delete() + for(var/atom/A in T)//Hit everything in the turf A.blob_act() return 1 ex_act(severity) - var/damage = 50 - switch(severity) - if(1) - src.health -= rand(100,120) - if(2) - src.health -= rand(60,100) - if(3) - src.health -= rand(20,60) - - health -= (damage/brute_resist) + var/damage = 150 + health -= ((damage/brute_resist) - (severity * 5)) update_icon() return - update_icon()//Needs to be updated with the types - if(health <= 0) - playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) - del(src) - return - if(health <= 15) - icon_state = "blob_damaged" - return -// if(health <= 20) -// icon_state = "blob_damaged2" -// return - - bullet_act(var/obj/item/projectile/Proj) ..() switch(Proj.damage_type) @@ -172,50 +140,30 @@ update_icon() return - proc/change_to(var/type = "Normal") - switch(type) - if("Normal") - new/obj/effect/blob(src.loc,src.health) - if("Node") - new/obj/effect/blob/node(src.loc,src.health*2) - if("Factory") - new/obj/effect/blob/factory(src.loc,src.health) - if("Shield") - new/obj/effect/blob/shield(src.loc,src.health*2) - del(src) + proc/change_to(var/type) + if(!ispath(type)) + error("[type] is an invalid type for the blob.") + new type(src.loc) + Delete() return -//////////////////////////////****IDLE BLOB***///////////////////////////////////// + proc/Delete() + del(src) -/obj/effect/blob/idle - name = "blob" - desc = "it looks... tasty" - icon_state = "blobidle0" +/obj/effect/blob/normal + icon_state = "blob" + luminosity = 0 + health = 20 + Delete() + src.loc = null + blobs -= src - New(loc, var/h = 10) - src.health = h - src.dir = pick(1,2,4,8) - src.update_idle() - - - proc/update_idle() - if(health<=0) - del(src) + update_icon() + if(health <= 0) + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + Delete() return - if(health<4) - icon_state = "blobc0" - return - if(health<10) - icon_state = "blobb0" - return - icon_state = "blobidle0" - - - Del() - var/obj/effect/blob/B = new /obj/effect/blob( src.loc ) - spawn(30) - B.Life() - ..() - - + if(health <= 15) + icon_state = "blob_damaged" + return \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 05e8dfafcd0..dd18d01a112 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -96,14 +96,14 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" ..() /datum/game_mode/proc/forge_changeling_objectives(var/datum/mind/changeling) - //OBJECTIVES - Always absorb 5 genomes, plus random traitor objectives. + //OBJECTIVES - Always absorb at least 5 genomes, plus random traitor objectives. //If they have two objectives as well as absorb, they must survive rather than escape //No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting //If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone var/datum/objective/absorb/absorb_objective = new absorb_objective.owner = changeling - absorb_objective.gen_amount_goal(2, 3) + absorb_objective.gen_amount_goal(5, 8) changeling.objectives += absorb_objective var/datum/objective/assassinate/kill_objective = new @@ -133,7 +133,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/game_mode/proc/greet_changeling(var/datum/mind/changeling, var/you_are=1) if (you_are) changeling.current << "\red You are a changeling!" - changeling.current << "\red Use say \":g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them." + changeling.current << "\red Use say \":g message\" to communicate with your fellow changelings." changeling.current << "You must complete the following tasks:" if (changeling.current.mind) @@ -218,17 +218,19 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) var/list/absorbed_dna = list() + var/dna_max = 4 //How many extra DNA strands the changeling can store for transformation. var/absorbedcount = 0 var/chem_charges = 20 - var/chem_recharge_rate = 0.5 var/chem_storage = 50 - var/sting_range = 1 + var/chem_recharge_rate = 0.5 + var/sting_range = 2 var/changelingID = "Changeling" var/geneticdamage = 0 var/isabsorbing = 0 var/geneticpoints = 5 var/purchasedpowers = list() var/mimicing = "" + var/canrespec = 0 /datum/changeling/New(var/gender=FEMALE) ..() @@ -241,6 +243,8 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" changelingID = "[honorific] [changelingID]" else changelingID = "[honorific] [rand(1,999)]" + absorbed_dna.len = dna_max + /datum/changeling/proc/regenerate() chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage) @@ -254,3 +258,41 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" chosen_dna = DNA break return chosen_dna + + +//Checks if the target DNA is valid and absorbable. +/datum/changeling/proc/can_absorb_dna(mob/living/carbon/T, mob/living/carbon/U) + if(absorbed_dna[1] == U.dna)//If our current DNA is the stalest, we gotta ditch it. + U << "We have reached our capacity to store genetic information! We must transform before absorbing more." + return 0 + + if(T) + if(NOCLONE in T.mutations || HUSK in T.mutations) + U << "DNA of [T] is ruined beyond usability!" + return 0 + + if(!ishuman(T))//Absorbing monkeys is entirely possible, but it can cause issues with transforming. That's what lesser form is for anyway! + U << "We could gain no benefit from absorbing a lesser creature." + return 0 + + if(T.dna in absorbed_dna) + U << "We already have that DNA in storage." + return 0 + + if(!check_dna_integrity(T)) + U << "[T] is not compatible with our biology." + return 0 + + return 1 + + +//Absorbs the target DNA. +/datum/changeling/proc/absorb_dna(mob/living/carbon/T) + shuffle_dna() + T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. + absorbed_dna |= T.dna //And add the target DNA to our absorbed list. + absorbedcount++ //all that done, let's increment the objective counter. + +/datum/changeling/proc/shuffle_dna()//boots out the stalest DNA. + if(absorbed_dna.len) + absorbed_dna.Cut(1,2) \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index 7e7c81c8798..ddcd095871d 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -32,10 +32,9 @@ if(P.isVerb) verbs -= P.verbpath - //Helper proc. Does all the checks and stuff for us to avoid copypasta //includes a check to see if we're a carbon mob. This means that you can't use powers (even with the verbs) unless you're a carbon-based mob. -/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0) +/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=3, var/max_stat=0) if(!src.mind) return if(!iscarbon(src)) return @@ -46,7 +45,7 @@ src << "We are incapacitated." return - if(changeling.absorbed_dna.len < required_dna) + if(changeling.absorbedcount < required_dna) src << "We require at least [required_dna] samples of compatible DNA." return @@ -55,12 +54,14 @@ return if(changeling.geneticdamage > max_genetic_damage) - src << "Our geneomes are still reassembling. We need time to recover first." + src << "Our genomes are still reassembling. We need time to recover first." return return changeling + + //Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. //Doesn't cost anything as it's the most basic ability. /mob/living/carbon/proc/changeling_absorb_dna() @@ -75,24 +76,19 @@ src << "We must be grabbing a creature in our active hand to absorb them." return - var/mob/living/carbon/T = G.affecting - if(!check_dna_integrity(T)) - src << "[T] is not compatible with our biology." - return - - if(NOCLONE in T.mutations) - src << "This creature's DNA is ruined beyond useability!" - return - if(G.state <= GRAB_NECK) src << "We must have a tighter grip to absorb this creature." return - if(changeling.isabsorbing) src << "We are already absorbing!" return - changeling.isabsorbing = 1 + var/mob/living/carbon/T = G.affecting + if(changeling.can_absorb_dna(T, usr)) + changeling.isabsorbing = 1 + else + return + for(var/stage = 1, stage<=3, stage++) switch(stage) if(1) @@ -116,41 +112,16 @@ src.visible_message("[src] sucks the fluids from [T]!") T << "You have been absorbed by the changeling!" - T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set. - changeling.absorbed_dna |= T.dna + changeling.absorb_dna(T) + if(src.nutrition < 400) src.nutrition = min((src.nutrition + T.nutrition), 400) - changeling.chem_charges += 10 - changeling.geneticpoints += 2 + if(T.mind && T.mind.changeling)//If the target was a changeling, suck out their extra juice! + changeling.chem_charges += min(T.mind.changeling.chem_charges, changeling.chem_storage) + else + changeling.chem_charges += 10 - if(T.mind && T.mind.changeling) - if(T.mind.changeling.absorbed_dna) - for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot - if(dna_data in changeling.absorbed_dna) - continue - changeling.absorbed_dna += dna_data - changeling.absorbedcount++ - T.mind.changeling.absorbed_dna.len = 1 - - if(T.mind.changeling.purchasedpowers) - for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers) - if(Tp in changeling.purchasedpowers) - continue - else - changeling.purchasedpowers += Tp - - if(!Tp.isVerb) - call(Tp.verbpath)() - else - make_changeling() - - changeling.chem_charges += T.mind.changeling.chem_charges - changeling.geneticpoints += T.mind.changeling.geneticpoints - T.mind.changeling.chem_charges = 0 - T.mind.changeling.geneticpoints = 0 - T.mind.changeling.absorbedcount = 0 - - changeling.absorbedcount++ changeling.isabsorbing = 0 + changeling.canrespec = 1 T.death(0) T.Drain() @@ -162,7 +133,7 @@ set category = "Changeling" set name = "Transform (5)" - var/datum/changeling/changeling = changeling_power(5,1,0) + var/datum/changeling/changeling = changeling_power(5, 0, 3) if(!changeling) return var/list/names = list() @@ -177,16 +148,12 @@ return changeling.chem_charges -= 5 - src.visible_message("[src] transforms!") - changeling.geneticdamage = 30 + changeling.geneticdamage = 3 src.dna = chosen_dna src.real_name = chosen_dna.real_name updateappearance(src) domutcheck(src, null) - src.verbs -= /mob/living/carbon/proc/changeling_transform - spawn(10) src.verbs += /mob/living/carbon/proc/changeling_transform - feedback_add_details("changeling_powers","TR") return 1 @@ -194,21 +161,20 @@ //Transform into a monkey. /mob/living/carbon/proc/changeling_lesser_form() set category = "Changeling" - set name = "Lesser Form (1)" + set name = "Lesser Form (5)" - var/datum/changeling/changeling = changeling_power(1,0,0) + var/datum/changeling/changeling = changeling_power(5,0,3) if(!changeling) return - changeling.chem_charges-- + changeling.chem_charges -= 5 remove_changeling_powers() - visible_message("[src] transforms!") - changeling.geneticdamage = 30 + changeling.geneticdamage = 3 src << "Our genes cry out!" var/mob/living/carbon/monkey/O = monkeyize(TR_KEEPITEMS | TR_HASHNAME | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPSE | TR_KEEPSRC) O.make_changeling(1) - O.verbs += /mob/living/carbon/proc/changeling_lesser_transform + O.verbs += /mob/living/carbon/proc/changeling_human_form feedback_add_details("changeling_powers","LF") . = 1 del(src) @@ -216,12 +182,12 @@ //Transform into a human -/mob/living/carbon/proc/changeling_lesser_transform() +/mob/living/carbon/proc/changeling_human_form() set category = "Changeling" - set name = "Transform (1)" + set name = "Human Form (5)" - var/datum/changeling/changeling = changeling_power(1,1,0) + var/datum/changeling/changeling = changeling_power(5,0,3) if(!changeling) return @@ -236,9 +202,9 @@ if(!chosen_dna) return - changeling.chem_charges-- + changeling.chem_charges -= 5 remove_changeling_powers() - visible_message("[src] transforms!") + src << "We transform our appearance." dna = chosen_dna var/mob/living/carbon/human/O = humanize((TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPDAMAGE | TR_KEEPSRC),chosen_dna.real_name) @@ -253,76 +219,80 @@ //Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay. /mob/living/carbon/proc/changeling_fakedeath() set category = "Changeling" - set name = "Regenerative Stasis (20)" + set name = "Regenerative Stasis (10)" + set desc = "Begin stasis, allowing us to regenerate." - var/datum/changeling/changeling = changeling_power(20,1,100,DEAD) + var/datum/changeling/changeling = changeling_power(10,0,100,DEAD) if(!changeling) return + if(status_flags & FAKEDEATH) return //Make sure we can't stack regenerations and such. + changeling.chem_charges -= 10 if(!stat && alert("Are we sure we wish to fake our death?",,"Yes","No") == "No")//Confirmation for living changelings if they want to fake their death return - src << "We will attempt to regenerate our form." + src << "We begin our stasis, preparing energy to arise once more." status_flags |= FAKEDEATH //play dead update_canmove() remove_changeling_powers() - emote("gasp") + emote("deathgasp") tod = worldtime2text() - spawn(rand(800,2000)) - if(changeling_power(20,1,100,DEAD)) - changeling.chem_charges -= 20 - if(stat == DEAD) - dead_mob_list -= src - living_mob_list += src - stat = CONSCIOUS - tod = null - setToxLoss(0) - setOxyLoss(0) - setCloneLoss(0) - SetParalysis(0) - SetStunned(0) - SetWeakened(0) - radiation = 0 - heal_overall_damage(getBruteLoss(), getFireLoss()) - reagents.clear_reagents() - src << "We have regenerated." - visible_message("[src] appears to wake from the dead, having healed all wounds.") + spawn(800) + src << "We have now stored enough power to regenerate." + verbs -= /mob/living/carbon/proc/changeling_fakedeath + verbs += /mob/living/carbon/proc/changeling_revive - status_flags &= ~(FAKEDEATH) - update_canmove() - make_changeling() feedback_add_details("changeling_powers","FD") return 1 - -//Boosts the range of your next sting attack by 1 -/mob/living/carbon/proc/changeling_boost_range() +//Separated from regenerative stasis, so that they can choose when to pop up rather than having no control over it. +/mob/living/carbon/proc/changeling_revive() set category = "Changeling" - set name = "Ranged Sting (10)" - set desc="Your next sting ability can be used against targets 2 squares away." + set name = "Regenerate! (10)" + set desc = "Regenerate, healing all damage from our form." - var/datum/changeling/changeling = changeling_power(10,0,100) - if(!changeling) return 0 + var/datum/changeling/changeling = changeling_power(10,0,100,DEAD) + if(!changeling) return changeling.chem_charges -= 10 - src << "Your throat adjusts to launch the sting." - changeling.sting_range = 2 - src.verbs -= /mob/living/carbon/proc/changeling_boost_range - spawn(5) src.verbs += /mob/living/carbon/proc/changeling_boost_range - feedback_add_details("changeling_powers","RS") - return 1 + if(stat == DEAD) + dead_mob_list -= src + living_mob_list += src + stat = CONSCIOUS + tod = null + setToxLoss(0) + setOxyLoss(0) + setCloneLoss(0) + SetParalysis(0) + SetStunned(0) + SetWeakened(0) + radiation = 0 + heal_overall_damage(getBruteLoss(), getFireLoss()) + reagents.clear_reagents() + src << "We have regenerated." + + status_flags &= ~(FAKEDEATH) + update_canmove() + make_changeling() + + verbs -= /mob/living/carbon/proc/changeling_revive + verbs += /mob/living/carbon/proc/changeling_fakedeath + + feedback_add_details("changeling_powers","CR") + return 1 //Recover from stuns. /mob/living/carbon/proc/changeling_unstun() set category = "Changeling" - set name = "Epinephrine Sacs (45)" - set desc = "Removes all stuns" + set name = "Epinephrine Overdose (35)" + set desc = "Removes all stuns instantly, and adds a short-term reduction in further stuns." - var/datum/changeling/changeling = changeling_power(45,0,100,UNCONSCIOUS) + var/datum/changeling/changeling = changeling_power(35,0,100,UNCONSCIOUS) if(!changeling) return 0 - changeling.chem_charges -= 45 + changeling.chem_charges -= 35 + src << "We arise." stat = 0 SetParalysis(0) SetStunned(0) @@ -330,28 +300,94 @@ lying = 0 update_canmove() - src.verbs -= /mob/living/carbon/proc/changeling_unstun - spawn(5) src.verbs += /mob/living/carbon/proc/changeling_unstun + reagents.add_reagent("synaptizine", 20) + feedback_add_details("changeling_powers","UNS") return 1 -//Speeds up chemical regeneration -/mob/proc/changeling_fastchemical() +//Increases maximum chemical storage and regeneraton. +/mob/proc/changeling_advglands() + src.mind.changeling.chem_storage += 25 src.mind.changeling.chem_recharge_rate *= 2 return 1 -//Increases macimum chemical storage -/mob/proc/changeling_engorgedglands() - src.mind.changeling.chem_storage += 25 + +//A flashy ability, good for crowd control and sewing chaos. +/mob/living/carbon/proc/changeling_shriek() + set category = "Changeling" + set name = "Resonant Shriek (25)" + set desc = "Deafen and confuse those around us." + + var/datum/changeling/changeling = changeling_power(25) + if(!changeling) return 0 + src.mind.changeling.chem_charges -= 25 + + for(var/mob/living/carbon/M in ohearers(4, usr)) + if(!M.mind || !M.mind.changeling) + M.ear_deaf += 30 + M.confused += 20 + M.make_jittery(50) + + for(var/obj/machinery/light/L in range(4, usr)) + L.on = 1 + L.broken() + + //for(var/obj/structure/window/W in range(2, usr)) //I like the window-breaking, but it makes the ability too 'loud' to fit changelings. + // W.hit(rand(40,100)) + + feedback_add_details("changeling_powers","RS") + return 1 + + +//Makes some spiderlings. Good for setting traps and causing general trouble. +/mob/living/carbon/proc/changeling_spiders() + set category = "Changeling" + set name = "Spread Infestation (40)" + set desc = "Creates spiderlings." + + var/datum/changeling/changeling = changeling_power(40, 10) + if(!changeling) return 0 + src.mind.changeling.chem_charges -= 40 + + for(var/i=0, i<3, i++) + var/obj/effect/spider/spiderling/S = new(src.loc) + if(prob(50))//nurses are obnoxious and lay more eggs, let's not have that for now. + S.grow_as = /mob/living/simple_animal/hostile/giant_spider/hunter + else + S.grow_as = /mob/living/simple_animal/hostile/giant_spider + + feedback_add_details("changeling_powers","SI") + return 1 + + +//Heals the things that the other regenerative abilities don't. +/mob/living/carbon/proc/changeling_panacea() + set category = "Changeling" + set name = "Anatomic Panacea (35)" + set desc = "Cures diseases, disabilities, toxins and radiation." + + var/datum/changeling/changeling = changeling_power(35,0,100,UNCONSCIOUS) + if(!changeling) return 0 + src.mind.changeling.chem_charges -= 35 + + src << "We cleanse impurities from our form." + reagents.add_reagent("ryetalyn", 10) + reagents.add_reagent("hyronalin", 10) + reagents.add_reagent("anti_toxin", 20) + + for(var/datum/disease/D in src.viruses) + D.cure() + + feedback_add_details("changeling_powers","AP") return 1 //Prevents AIs tracking you but makes you easily detectable to the human-eye. /mob/living/carbon/proc/changeling_digitalcamo() set category = "Changeling" - set name = "Toggle Digital Camoflague" - set desc = "The AI can no longer track us, but we will look different if examined. Has a constant cost while active." + set name = "Toggle Digital Camouflage" + set desc = "The AI can no longer track us, but we will look different if examined." var/datum/changeling/changeling = changeling_power() if(!changeling) return 0 @@ -360,27 +396,21 @@ else src << "We distort our form to prevent AI-tracking." digitalcamo = !digitalcamo - spawn(0) - while(src && digitalcamo && mind && mind.changeling) - mind.changeling.chem_charges = max(mind.changeling.chem_charges - 1, 0) - sleep(40) - - src.verbs -= /mob/living/carbon/proc/changeling_digitalcamo - spawn(5) src.verbs += /mob/living/carbon/proc/changeling_digitalcamo feedback_add_details("changeling_powers","CAM") return 1 //Starts healing you every second for 10 seconds. Can be used whilst unconscious. -/mob/living/carbon/proc/changeling_rapidregen() +/mob/living/carbon/proc/changeling_fleshmend() set category = "Changeling" - set name = "Rapid Regeneration (30)" + set name = "Fleshmend (30)" set desc = "Begins rapidly regenerating. Does not effect stuns or chemicals." var/datum/changeling/changeling = changeling_power(30,0,100,UNCONSCIOUS) if(!changeling) return 0 src.mind.changeling.chem_charges -= 30 + src << "We begin to heal rapidly." spawn(0) for(var/i = 0, i<10,i++) adjustBruteLoss(-10) @@ -389,13 +419,10 @@ adjustFireLoss(-10) sleep(10) - src.verbs -= /mob/living/carbon/proc/changeling_rapidregen - spawn(5) src.verbs += /mob/living/carbon/proc/changeling_rapidregen feedback_add_details("changeling_powers","RR") return 1 // HIVE MIND UPLOAD/DOWNLOAD DNA - var/list/datum/dna/hivemind_bank = list() /mob/living/carbon/proc/changeling_hiveupload() @@ -403,7 +430,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Hive Channel (10)" set desc = "Allows you to channel DNA in the airwaves to allow other changelings to absorb it." - var/datum/changeling/changeling = changeling_power(10,1) + var/datum/changeling/changeling = changeling_power(10) if(!changeling) return var/list/names = list() @@ -433,7 +460,7 @@ var/list/datum/dna/hivemind_bank = list() set name = "Hive Absorb (20)" set desc = "Allows you to absorb DNA that is being channeled in the airwaves." - var/datum/changeling/changeling = changeling_power(20,1) + var/datum/changeling/changeling = changeling_power(20) if(!changeling) return var/list/names = list() @@ -451,14 +478,15 @@ var/list/datum/dna/hivemind_bank = list() if(!chosen_dna) return - changeling.chem_charges -= 20 - changeling.absorbed_dna += chosen_dna - src << "We absorb the DNA of [S] from the air." - feedback_add_details("changeling_powers","HD") + if(changeling.can_absorb_dna(null, usr)) + changeling.chem_charges -= 20 + changeling.shuffle_dna() + changeling.absorbed_dna |= chosen_dna + src << "We absorb the DNA of [S] from the air." + feedback_add_details("changeling_powers","HD") return 1 // Fake Voice - /mob/living/carbon/proc/changeling_mimicvoice() set category = "Changeling" set name = "Mimic Voice" @@ -490,6 +518,9 @@ var/list/datum/dna/hivemind_bank = list() sleep(40) if(src && src.mind && src.mind.changeling) src.mind.changeling.mimicing = "" + + + ////////// //STINGS// //They get a pretty header because there's just so fucking many of them ;_; ////////// @@ -517,9 +548,8 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling_power(required_chems)) return changeling.chem_charges -= required_chems - changeling.sting_range = 1 verbs -= verb_path - spawn(10) verbs += verb_path + spawn(5) verbs += verb_path src << "We stealthily sting [T]." if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting @@ -527,73 +557,10 @@ var/list/datum/dna/hivemind_bank = list() return -/mob/living/carbon/proc/changeling_lsdsting() - set category = "Changeling" - set name = "Hallucination Sting (15)" - set desc = "Causes terror in the target." - - var/mob/living/carbon/T = changeling_sting(15,/mob/living/carbon/proc/changeling_lsdsting) - if(!T) return 0 - spawn(rand(300,600)) - if(T) T.hallucination += 400 - feedback_add_details("changeling_powers","HS") - return 1 - -/mob/living/carbon/proc/changeling_silence_sting() - set category = "Changeling" - set name = "Silence sting (10)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(10,/mob/living/carbon/proc/changeling_silence_sting) - if(!T) return 0 - T.silent += 30 - feedback_add_details("changeling_powers","SS") - return 1 - -/mob/living/carbon/proc/changeling_blind_sting() - set category = "Changeling" - set name = "Blind sting (20)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(20,/mob/living/carbon/proc/changeling_blind_sting) - if(!T) return 0 - T << "Your eyes burn horrificly!" - T.disabilities |= NEARSIGHTED - spawn(300) T.disabilities &= ~NEARSIGHTED - T.eye_blind = 10 - T.eye_blurry = 20 - feedback_add_details("changeling_powers","BS") - return 1 - -/mob/living/carbon/proc/changeling_deaf_sting() - set category = "Changeling" - set name = "Deaf sting (5)" - set desc="Sting target:" - - var/mob/living/carbon/T = changeling_sting(5,/mob/living/carbon/proc/changeling_deaf_sting) - if(!T) return 0 - T << "Your ears pop and begin ringing loudly!" - T.sdisabilities |= DEAF - spawn(300) T.sdisabilities &= ~DEAF - feedback_add_details("changeling_powers","DS") - return 1 - -/mob/living/carbon/proc/changeling_paralysis_sting() - set category = "Changeling" - set name = "Paralysis sting (30)" - set desc="Sting target" - - var/mob/living/carbon/T = changeling_sting(30,/mob/living/carbon/proc/changeling_paralysis_sting) - if(!T) return 0 - T << "Your muscles begin to painfully tighten." - T.Weaken(20) - feedback_add_details("changeling_powers","PS") - return 1 - /mob/living/carbon/proc/changeling_transformation_sting() set category = "Changeling" - set name = "Transformation sting (40)" - set desc="Sting target" + set name = "Transformation Sting (40)" + set desc= "Transform the target to one of our stored DNAs" var/datum/changeling/changeling = changeling_power(40) if(!changeling) return 0 @@ -614,7 +581,6 @@ var/list/datum/dna/hivemind_bank = list() if((HUSK in T.mutations) || !check_dna_integrity(T)) src << "Our sting appears ineffective against its DNA." return 0 - T.visible_message("[T] transforms!") T.dna = chosen_dna T.real_name = chosen_dna.real_name updateappearance(T) @@ -622,24 +588,10 @@ var/list/datum/dna/hivemind_bank = list() feedback_add_details("changeling_powers","TS") return 1 -/mob/living/carbon/proc/changeling_DEATHsting() - set category = "Changeling" - set name = "Death Sting (40)" - set desc = "Causes spasms onto death." - - var/mob/living/carbon/T = changeling_sting(40,/mob/living/carbon/proc/changeling_DEATHsting) - if(!T) return 0 - T << "You feel a small prick and your chest becomes tight." - T.silent = 10 - T.Paralyse(10) - T.make_jittery(1000) - if(T.reagents) T.reagents.add_reagent("lexorin", 40) - feedback_add_details("changeling_powers","DTHS") - return 1 /mob/living/carbon/proc/changeling_extract_dna_sting() set category = "Changeling" - set name = "Extract DNA Sting (40)" + set name = "Extract DNA Sting (25)" set desc="Stealthily sting a target to extract their DNA." var/datum/changeling/changeling = null @@ -648,11 +600,69 @@ var/list/datum/dna/hivemind_bank = list() if(!changeling) return 0 - var/mob/living/carbon/T = changeling_sting(40, /mob/living/carbon/proc/changeling_extract_dna_sting) + var/mob/living/carbon/T = changeling_sting(25, /mob/living/carbon/proc/changeling_extract_dna_sting) if(!T) return 0 - T.dna.real_name = T.real_name - changeling.absorbed_dna |= T.dna + if(changeling.can_absorb_dna(T, usr)) + changeling.absorb_dna(T, usr) + else//If the sting fails, give the guy most of his chems back. + changeling.chem_charges += 20 feedback_add_details("changeling_powers","ED") - return 1 + return 1 + + +/mob/living/carbon/proc/changeling_mute_sting() + set category = "Changeling" + set name = "Mute sting (20)" + set desc= "Temporarily mutes the target." + + var/mob/living/carbon/T = changeling_sting(20,/mob/living/carbon/proc/changeling_mute_sting) + if(!T) return 0 + T.silent += 30 + feedback_add_details("changeling_powers","MS") + return 1 + + +/mob/living/carbon/proc/changeling_blind_sting() + set category = "Changeling" + set name = "Blind Sting (30)" + set desc= "Temporarily blinds the target." + + var/mob/living/carbon/T = changeling_sting(30,/mob/living/carbon/proc/changeling_blind_sting) + if(!T) return 0 + T << "Your eyes burn horrifically!" + T.disabilities |= NEARSIGHTED + T.eye_blind = 20 + T.eye_blurry = 40 + feedback_add_details("changeling_powers","BS") + return 1 + + +/mob/living/carbon/proc/changeling_lsd_sting() + set category = "Changeling" + set name = "Hallucination Sting (5)" + set desc = "Causes terror in the target." + + var/mob/living/carbon/T = changeling_sting(5,/mob/living/carbon/proc/changeling_lsd_sting) + if(!T) return 0 + spawn(rand(300,600)) + if(T) T.hallucination += 400 + feedback_add_details("changeling_powers","HS") + return 1 + + +/mob/living/carbon/proc/changeling_cryo_sting() + set category = "Changeling" + set name = "Cryogenic Sting (15)" + set desc = "Cools the target, slowing them." + + var/mob/living/carbon/T = changeling_sting(15,/mob/living/carbon/proc/changeling_cryo_sting) + if(!T) return 0 + + if(T.reagents) + T.reagents.add_reagent("frostoil", 30) + T.reagents.add_reagent("ice", 30) + + feedback_add_details("changeling_powers","CS") + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm index ec15b284143..6525099209e 100644 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -15,10 +15,18 @@ var/list/powerinstances /datum/power/changeling/absorb_dna name = "Absorb DNA" - desc = "Permits us to syphon the DNA from a human. They become one with us, and we become stronger." + desc = "Permits us to siphon the DNA from a human. They become one with us, and the new energy lets us change our abilities." genomecost = 0 verbpath = /mob/living/carbon/proc/changeling_absorb_dna +/datum/power/changeling/extractdna + name = "Extract DNA Strand" + desc = "We stealthily sting a target and extract the DNA from them." + helptext = "Will give you the DNA of your target, allowing you to transform into them." + genomecost = 0 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_extract_dna_sting + /datum/power/changeling/transform name = "Transform" desc = "We take on the appearance and voice of one we have absorbed." @@ -28,18 +36,18 @@ var/list/powerinstances /datum/power/changeling/fakedeath name = "Regenerative Stasis" desc = "We become weakened to a death-like state, where we will rise again from death." - helptext = "Can be used before or after death. Duration varies greatly." + helptext = "Can be used before or after death. Duration varies greatly. Can be used in lesser form." genomecost = 0 allowduringlesserform = 1 verbpath = /mob/living/carbon/proc/changeling_fakedeath // Hivemind - /datum/power/changeling/hive_upload name = "Hive Channel" desc = "We can channel a DNA into the airwaves, allowing our fellow changelings to absorb it and transform into it as if they acquired the DNA themselves." helptext = "Allows other changelings to absorb the DNA you channel from the airwaves. Will not help them towards their absorb objectives." genomecost = 0 + allowduringlesserform = 1 verbpath = /mob/living/carbon/proc/changeling_hiveupload /datum/power/changeling/hive_download @@ -47,136 +55,118 @@ var/list/powerinstances desc = "We can absorb a single DNA from the airwaves, allowing us to use more disguises with help from our fellow changelings." helptext = "Allows you to absorb a single DNA and use it. Does not count towards your absorb objective." genomecost = 0 + allowduringlesserform = 1 verbpath = /mob/living/carbon/proc/changeling_hivedownload /datum/power/changeling/lesser_form name = "Lesser Form" - desc = "We debase ourselves and become lesser. We become a monkey." + desc = "We debase ourselves and become lesser. We become a monkey." genomecost = 1 verbpath = /mob/living/carbon/proc/changeling_lesser_form -/datum/power/changeling/deaf_sting - name = "Deaf Sting" - desc = "We silently sting a human, completely deafening them for a short time." - genomecost = 1 - allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_deaf_sting - -/datum/power/changeling/blind_sting - name = "Blind Sting" - desc = "We silently sting a human, completely blinding them for a short time." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_blind_sting - -/datum/power/changeling/silence_sting - name = "Silence Sting" - desc = "We silently sting a human, completely silencing them for a short time." - helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_silence_sting - /datum/power/changeling/mimicvoice name = "Mimic Voice" desc = "We shape our vocal glands to sound like a desired voice." helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this" - genomecost = 3 + genomecost = 1 verbpath = /mob/living/carbon/proc/changeling_mimicvoice -/datum/power/changeling/extractdna - name = "Extract DNA" - desc = "We stealthily sting a target and extract the DNA from them." - helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives." - genomecost = 4 - allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_extract_dna_sting - /datum/power/changeling/transformation_sting name = "Transformation Sting" desc = "We silently sting a human, injecting a retrovirus that forces them to transform into another." helptext = "Does not provide a warning to others. The victim will transform much like a changeling would." - genomecost = 3 + genomecost = 1 verbpath = /mob/living/carbon/proc/changeling_transformation_sting -/datum/power/changeling/paralysis_sting - name = "Paralysis Sting" - desc = "We silently sting a human, paralyzing them for a short time." - genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_paralysis_sting - -/datum/power/changeling/LSDSting - name = "Hallucination Sting" - desc = "We evolve the ability to sting a target with a powerful hallucinogenic chemical." - helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." - genomecost = 3 - verbpath = /mob/living/carbon/proc/changeling_lsdsting - -/datum/power/changeling/DeathSting - name = "Death Sting" - desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured." - genomecost = 10 - verbpath = /mob/living/carbon/proc/changeling_DEATHsting - -/datum/power/changeling/boost_range - name = "Boost Range" - desc = "We evolve the ability to shoot our stingers at humans, with some preperation." - genomecost = 2 - allowduringlesserform = 1 - verbpath = /mob/living/carbon/proc/changeling_boost_range - /datum/power/changeling/Epinephrine - name = "Epinephrine sacs" + name = "Epinephrine Sacs" desc = "We evolve additional sacs of adrenaline throughout our body." - helptext = "Gives the ability to instantly recover from stuns. High chemical cost." - genomecost = 4 + helptext = "Removes all stuns instantly, and adds a short-term reduction in further stuns. Can be used while unconscious." + genomecost = 1 verbpath = /mob/living/carbon/proc/changeling_unstun -/datum/power/changeling/ChemicalSynth - name = "Rapid Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 4 - isVerb = 0 - verbpath = /mob/proc/changeling_fastchemical -/* -/datum/power/changeling/AdvChemicalSynth - name = "Advanced Chemical-Synthesis" - desc = "We evolve new pathways for producing our necessary chemicals, permitting us to naturally create them faster." - helptext = "Doubles the rate at which we naturally recharge chemicals." - genomecost = 8 - isVerb = 0 - verbpath = /mob/living/carbon/proc/changeling_fastchemical -*/ /datum/power/changeling/EngorgedGlands name = "Engorged Chemical Glands" desc = "Our chemical glands swell, permitting us to store more chemicals inside of them." - helptext = "Allows us to store an extra 25 units of chemicals." - genomecost = 4 + helptext = "Allows us to store an extra 25 units of chemicals, and doubles production rate." + genomecost = 1 isVerb = 0 - verbpath = /mob/proc/changeling_engorgedglands + verbpath = /mob/proc/changeling_advglands -/datum/power/changeling/DigitalCamoflague - name = "Digital Camoflauge" - desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras." - helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this." - genomecost = 3 +/datum/power/changeling/DigitalCamouflage + name = "Digital Camouflage" + desc = "We evolve the ability to distort our form and proprotions, defeating common altgorthms used to detect lifeforms on cameras." + helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us... uncanny." + genomecost = 1 allowduringlesserform = 1 verbpath = /mob/living/carbon/proc/changeling_digitalcamo -/datum/power/changeling/rapidregeneration - name = "Rapid Regeneration" - desc = "We evolve the ability to rapidly regenerate, negating the need for stasis." - helptext = "Heals a moderate amount of damage every tick." - genomecost = 8 - verbpath = /mob/living/carbon/proc/changeling_rapidregen +/datum/power/changeling/fleshmend + name = "Fleshmend" + desc = "We evolve the ability to rapidly regenerate, restoring the health of the body we use." + helptext = "Heals a moderate amount of damage every tick. Can be used while unconscious." + genomecost = 1 + verbpath = /mob/living/carbon/proc/changeling_fleshmend +/datum/power/changeling/panacea + name = "Anatomic Panacea" + desc = "Expels impurifications from our form; curing diseases, genetic disabilities, and removing toxins and radiation." + helptext = "Can be used while unconscious." + genomecost = 1 + verbpath = /mob/living/carbon/proc/changeling_panacea + +/datum/power/changeling/shriek + name = "Resonant Shriek" + desc = "Our lungs and vocal chords shift, allowing us to briefly emit a noise that deafens and confuses humans." + helptext = "The high-frequency sounds cannot be heard by humans, but will blow out lights nearby." + genomecost = 1 + verbpath = /mob/living/carbon/proc/changeling_shriek + +/datum/power/changeling/spiders + name = "Spread Infestation" + desc = "Our form divides, creating arachnids which will grow into deadly beasts." + helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires 10 DNA absorptions." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_spiders + +/datum/power/changeling/lsd_sting + name = "Hallucination Sting" + desc = "We evolve the ability to sting a target with a powerful hallucinogenic chemical." + helptext = "The target does not notice they have been stung. The effect occurs after 30 to 60 seconds." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_lsd_sting + +/datum/power/changeling/blind_sting + name = "Blind Sting" + desc = "We silently sting a human, completely blinding them for a short time." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_blind_sting + +/datum/power/changeling/cryo_sting + name = "Cryogenic Sting" + desc = "We silently sting a human with a cocktail of chemicals, slowing their metabolism." + helptext = "Does not provide a warning to a victim, though they will likely realize they are suddenly freezing." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_cryo_sting + +/datum/power/changeling/mute_sting + name = "Mute Sting" + desc = "We silently sting a human, completely silencing them for a short time." + helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." + genomecost = 1 + allowduringlesserform = 1 + verbpath = /mob/living/carbon/proc/changeling_mute_sting // Modularchangling, totally stolen from the new player panel. YAYY /datum/changeling/proc/EvolutionMenu()//The new one + set name = "-Evolution Menu-"//Dashes are so it's listed before all the other abilities. set category = "Changeling" - set desc = "Level up!" + set desc = "Choose our method of subjugation." if(!usr || !usr.mind || !usr.mind.changeling) return src = usr.mind.changeling @@ -372,10 +362,11 @@ var/list/powerinstances @@ -397,13 +388,24 @@ var/list/powerinstances for(var/datum/power/changeling/P in powerinstances) var/ownsthis = 0 + if(P.genomecost == 0) //Let's skip the crap we start with. Keeps the evolution menu uncluttered. + continue + if(P in purchasedpowers) ownsthis = 1 - var/color = "#e6e6e6" - if(i%2 == 0) - color = "#f2f2f2" + var/color + if(ownsthis) + if(i%2 == 0) + color = "#d8ebd8" + else + color = "#c3dec3" + else + if(i%2 == 0) + color = "#f2f2f2" + else + color = "#e6e6e6" dat += {" @@ -414,7 +416,7 @@ var/list/powerinstances - Evolve [P] - Cost: [ownsthis ? "Purchased" : P.genomecost] + Evolve [P][ownsthis ? " - Purchased" : ((P.genomecost > 1) ? " - Cost: [P.genomecost]" : "")]
@@ -437,7 +439,7 @@ var/list/powerinstances "} - usr << browse(dat, "window=powers;size=900x480") + usr << browse(dat, "window=powers;size=600x700")//900x480 /datum/changeling/Topic(href, href_list) @@ -452,42 +454,81 @@ var/list/powerinstances purchasePower(M, href_list["P"]) call(/datum/changeling/proc/EvolutionMenu)() + if(href_list["readapt"]) + var/datum/mind/M = usr.mind + if(!istype(M)) + return + lingRespec(M) + call(/datum/changeling/proc/EvolutionMenu)() + return +///// -/datum/changeling/proc/purchasePower(var/datum/mind/M, var/Pname, var/remake_verbs = 1) +/datum/changeling/proc/purchasePower(var/datum/mind/M, var/pname, var/remake_verbs = 1) if(!M || !M.changeling || !istype(M.current, /mob/living/carbon)) return var/mob/living/carbon/C = M.current - var/datum/power/changeling/Thepower = Pname - + var/datum/power/changeling/thepower = pname for (var/datum/power/changeling/P in powerinstances) - //world << "[P] - [Pname] = [P.name == Pname ? "True" : "False"]" - if(P.name == Pname) - Thepower = P + if(P.name == pname) + thepower = P break - - if(Thepower == null) - C << "This is awkward. Changeling power purchase failed, please report this bug to a coder!" + if(thepower == null) + C << "This is awkward. Changeling power purchase failed, please report this bug to a coder!" return - if(Thepower in purchasedpowers) + if(thepower in purchasedpowers) C << "We have already evolved this ability!" return - - if(geneticpoints < Thepower.genomecost) - C << "We cannot evolve this... yet. We must acquire more DNA." + if(geneticpoints < thepower.genomecost) + C << "We have reached our capacity for abilities." return - geneticpoints -= Thepower.genomecost + if(C.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist. + C << "We lack the energy to evolve new abilities right now." + return - purchasedpowers += Thepower + geneticpoints -= thepower.genomecost - if(!Thepower.isVerb && Thepower.verbpath) - call(C, Thepower.verbpath)() + purchasedpowers += thepower + + if(!thepower.isVerb && thepower.verbpath) + call(C, thepower.verbpath)() else if(remake_verbs) C.make_changeling() +///// + +/datum/changeling/proc/lingRespec(var/datum/mind/M) + if(!M || !M.changeling || !istype(M.current, /mob/living/carbon)) + return + + if(canrespec) + usr << "We have removed our evolutions from this form, and are now ready to readapt." + + var/mob/living/carbon/C = M.current + + C.remove_changeling_powers()//Revokes our verb powers. + clearlist(purchasedpowers) + + + //Resets our stats, to account for purchased passives. + C.digitalcamo = 0 + geneticpoints = initial(geneticpoints) + sting_range = initial(sting_range) + chem_storage = initial(chem_storage) + chem_recharge_rate = initial(chem_recharge_rate) + chem_charges = min(chem_charges, chem_storage) + mimicing = "" + + canrespec = 0 + + C.make_changeling()//Remake our verbs; rebuys the 0 cost skills. + else + usr << "You lack the power to readapt your evolutions!" + + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index ef39b96db8d..f2d3aa05399 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -20,6 +20,10 @@ rcd light flash thingy on matter drain var/mod_pick_name var/description = "" var/engaged = 0 + var/cost = 5 + var/one_time = 0 + + var/power_type /datum/AI_Module/large/ @@ -32,54 +36,72 @@ rcd light flash thingy on matter drain /datum/AI_Module/large/fireproof_core module_name = "Core upgrade" mod_pick_name = "coreup" + description = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent." + cost = 50 + one_time = 1 -/client/proc/fireproof_core() + power_type = /mob/living/silicon/ai/proc/fireproof_core + +/mob/living/silicon/ai/proc/fireproof_core() set category = "Malfunction" set name = "Fireproof Core" for(var/mob/living/silicon/ai/ai in player_list) ai.fire_res_on_core = 1 - usr.verbs -= /client/proc/fireproof_core - usr << "\red Core fireproofed." + src.verbs -= /mob/living/silicon/ai/proc/fireproof_core + src << "\red Core fireproofed." /datum/AI_Module/large/upgrade_turrets module_name = "AI Turret upgrade" mod_pick_name = "turret" + description = "Improves the firing speed and health of all AI turrets. This effect is permanent." + cost = 50 + one_time = 1 -/client/proc/upgrade_turrets() + power_type = /mob/living/silicon/ai/proc/upgrade_turrets + +/mob/living/silicon/ai/proc/upgrade_turrets() set category = "Malfunction" set name = "Upgrade Turrets" - usr.verbs -= /client/proc/upgrade_turrets - for(var/obj/machinery/turret/turret in player_list) + src.verbs -= /mob/living/silicon/ai/proc/upgrade_turrets + for(var/obj/machinery/turret/turret in machines) turret.health += 30 turret.shot_delay = 20 /datum/AI_Module/large/disable_rcd module_name = "RCD disable" mod_pick_name = "rcd" + description = "Send a specialised pulse to break all RCD devices on the station." + cost = 50 -/client/proc/disable_rcd() + power_type = /mob/living/silicon/ai/proc/disable_rcd + +/mob/living/silicon/ai/proc/disable_rcd() set category = "Malfunction" set name = "Disable RCDs" - for(var/datum/AI_Module/large/disable_rcd/rcdmod in usr:current_modules) + for(var/datum/AI_Module/large/disable_rcd/rcdmod in current_modules) if(rcdmod.uses > 0) rcdmod.uses -- for(var/obj/item/weapon/rcd/rcd in world) rcd.disabled = 1 for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world) rcd.disabled = 1 - usr << "RCD-disabling pulse emitted." - else usr << "Out of uses." + src << "RCD-disabling pulse emitted." + else src << "Out of uses." /datum/AI_Module/small/overload_machine module_name = "Machine overload" mod_pick_name = "overload" + description = "Overloads an electrical machine, causing a small explosion. 2 uses." uses = 2 + cost = 15 -/client/proc/overload_machine(obj/machinery/M as obj in world) + power_type = /mob/living/silicon/ai/proc/overload_machine + +/mob/living/silicon/ai/proc/overload_machine(obj/machinery/M as obj in world) set name = "Overload Machine" set category = "Malfunction" if (istype(M, /obj/machinery)) - for(var/datum/AI_Module/small/overload_machine/overload in usr:current_modules) + for(var/datum/AI_Module/small/overload_machine/overload in current_modules) if(overload.uses > 0) overload.uses -- for(var/mob/V in hearers(M, null)) @@ -87,67 +109,141 @@ rcd light flash thingy on matter drain spawn(50) explosion(get_turf(M), 0,1,1,0) del(M) - else usr << "Out of uses." - else usr << "That's not a machine." + else src << "Out of uses." + else src << "That's not a machine." + +/* + +/datum/AI_Module/large/place_cyborg_transformer + module_name = "Robotic Factory (Removes Shunting)" + mod_pick_name = "cyborgtransformer" + description = "Build a machine anywhere, using expensive nanomachines, that can convert a living human into a loyal cyborg slave when placed inside." + cost = 100 + + power_type = /mob/living/silicon/ai/proc/place_transformer + +/mob/living/silicon/ai/proc/place_transformer() + set name = "Place Robotic Factory" + set category = "Malfunction" + + if(!eyeobj) + return + + if(!isturf(src.loc)) // AI must be in it's core. + return + + var/datum/AI_Module/large/place_cyborg_transformer/PCT = locate() in src.current_modules + if(!PCT) + return + + if(PCT.uses < 1) + src << "Out of uses." + return + + var/sure = alert(src, "Make sure the room it is in is big enough and that there is a 1x3 area for the machine. Are you sure you want to place the machine here?", "Are you sure?", "Yes", "No") + if(sure != "Yes") + return + + // Make sure there is enough room. + var/turf/middle = get_turf(eyeobj.loc) + var/list/turfs = list(middle, locate(middle.x - 1, middle.y, middle.z), locate(middle.x + 1, middle.y, middle.z)) + + var/alert_msg = "There isn't enough room. Make sure you are placing the machine in a clear area and on a floor." + + for(var/T in turfs) + + // Make sure the turfs are clear and the correct type. + if(!istype(T, /turf/simulated/floor)) + alert(src, alert_msg) + return + + var/turf/simulated/floor/F = T + for(var/atom/movable/AM in F.contents) + if(AM.density) + alert(src, alert_msg) + return + + // All clear, place the transformer + new /obj/machinery/transformer/conveyor(middle) + src.can_shunt = 0 + PCT.uses -= 1 + src << "You cannot shunt anymore." + +*/ /datum/AI_Module/small/blackout module_name = "Blackout" mod_pick_name = "blackout" + description = "Attempts to overload the lighting circuits on the station, destroying some bulbs. 3 uses." uses = 3 + cost = 15 -/client/proc/blackout() + power_type = /mob/living/silicon/ai/proc/blackout + +/mob/living/silicon/ai/proc/blackout() set category = "Malfunction" set name = "Blackout" - for(var/datum/AI_Module/small/blackout/blackout in usr:current_modules) + for(var/datum/AI_Module/small/blackout/blackout in current_modules) if(blackout.uses > 0) blackout.uses -- for(var/obj/machinery/power/apc/apc in world) if(prob(30*apc.overload)) apc.overload_lighting() else apc.overload++ - else usr << "Out of uses." + else src << "Out of uses." /datum/AI_Module/small/interhack module_name = "Hack intercept" mod_pick_name = "interhack" + description = "Hacks the status upgrade from Cent. Com, removing any information about malfunctioning electrical systems." + cost = 15 + one_time = 1 -/client/proc/interhack() + power_type = /mob/living/silicon/ai/proc/interhack + +/mob/living/silicon/ai/proc/interhack() set category = "Malfunction" set name = "Hack intercept" - usr.verbs -= /client/proc/interhack + src.verbs -= /mob/living/silicon/ai/proc/interhack ticker.mode:hack_intercept() /datum/AI_Module/small/reactivate_camera module_name = "Reactivate camera" mod_pick_name = "recam" + description = "Reactivates a currently disabled camera. 10 uses." uses = 10 + cost = 15 -/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras) + power_type = /mob/living/silicon/ai/proc/reactivate_camera + +/mob/living/silicon/ai/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras) set name = "Reactivate Camera" set category = "Malfunction" if (istype (C, /obj/machinery/camera)) - for(var/datum/AI_Module/small/reactivate_camera/camera in usr:current_modules) + for(var/datum/AI_Module/small/reactivate_camera/camera in current_modules) if(camera.uses > 0) if(!C.status) - C.status = !C.status + C.deactivate(src) camera.uses -- - for(var/mob/V in viewers(src, null)) - V.show_message(text("\blue You hear a quiet click.")) else - usr << "This camera is either active, or not repairable." - else usr << "Out of uses." - else usr << "That's not a camera." + src << "This camera is either active, or not repairable." + else src << "Out of uses." + else src << "That's not a camera." /datum/AI_Module/small/upgrade_camera module_name = "Upgrade Camera" mod_pick_name = "upgradecam" + description = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 10 uses." uses = 10 + cost = 15 -/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras) + power_type = /mob/living/silicon/ai/proc/upgrade_camera + +/mob/living/silicon/ai/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras) set name = "Upgrade Camera" set category = "Malfunction" if(istype(C)) - var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in usr:current_modules + var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in current_modules if(UC) if(UC.uses > 0) if(C.assembly) @@ -156,7 +252,7 @@ rcd light flash thingy on matter drain if(!C.isXRay()) C.upgradeXRay() //Update what it can see. - cameranet.updateVisibility(C) + cameranet.updateVisibility(C, 0) upgraded = 1 if(!C.isEmpProof()) @@ -172,154 +268,80 @@ rcd light flash thingy on matter drain if(upgraded) UC.uses -- C.visible_message("\icon[C] *beep*") - usr << "Camera successully upgraded!" + src << "Camera successully upgraded!" else - usr << "This camera is already upgraded!" + src << "This camera is already upgraded!" else - usr << "Out of uses." + src << "Out of uses." -/datum/AI_Module/module_picker +/datum/module_picker var/temp = null var/processing_time = 100 var/list/possible_modules = list() -/datum/AI_Module/module_picker/New() - src.possible_modules += new /datum/AI_Module/large/fireproof_core - src.possible_modules += new /datum/AI_Module/large/upgrade_turrets - src.possible_modules += new /datum/AI_Module/large/disable_rcd - src.possible_modules += new /datum/AI_Module/small/overload_machine - src.possible_modules += new /datum/AI_Module/small/interhack - src.possible_modules += new /datum/AI_Module/small/blackout - src.possible_modules += new /datum/AI_Module/small/reactivate_camera - src.possible_modules += new /datum/AI_Module/small/upgrade_camera +/datum/module_picker/New() + for(var/type in typesof(/datum/AI_Module)) + var/datum/AI_Module/AM = new type + if(AM.power_type != null) + src.possible_modules += AM -/datum/AI_Module/module_picker/proc/use(user as mob) +/datum/module_picker/proc/remove_verbs(var/mob/living/silicon/ai/A) + + for(var/datum/AI_Module/AM in possible_modules) + A.verbs.Remove(AM.power_type) + + +/datum/module_picker/proc/use(user as mob) var/dat + dat = "Select use of processing time: (currently #[src.processing_time] left.)
" + dat += "
" + dat += "Install Module:
" + dat += "The number afterwards is the amount of processing time it consumes.
" + for(var/datum/AI_Module/large/module in src.possible_modules) + dat += "[module.module_name] ([module.cost])
" + for(var/datum/AI_Module/small/module in src.possible_modules) + dat += "[module.module_name] ([module.cost])
" + dat += "
" if (src.temp) - dat = "[src.temp]

Clear" - else if(src.processing_time <= 0) - dat = " No processing time is left available. No more modules are able to be chosen at this time." - else - dat = "Select use of processing time: (currently [src.processing_time] left.)
" - dat += "
" - dat += "Install Module:
" - dat += "The number afterwards is the amount of processing time it consumes.
" - for(var/datum/AI_Module/large/module in src.possible_modules) - dat += "[module.module_name] (50)
" - for(var/datum/AI_Module/small/module in src.possible_modules) - dat += "[module.module_name] (15)
" - dat += "
" - - user << browse(dat, "window=modpicker") - onclose(user, "modpicker") + dat += "[src.temp]" + var/datum/browser/popup = new(user, "modpicker", "Malf Module Menu") + popup.set_content(dat) + popup.open() return -/datum/AI_Module/module_picker/Topic(href, href_list) +/datum/module_picker/Topic(href, href_list) ..() - if (href_list["coreup"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/large/fireproof_core)) - already = 1 - if (!already) - usr.verbs += /client/proc/fireproof_core - usr:current_modules += new /datum/AI_Module/large/fireproof_core - src.temp = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent." - src.processing_time -= 50 - else src.temp = "This module is only needed once." - else if (href_list["turret"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/large/upgrade_turrets)) - already = 1 - if (!already) - usr.verbs += /client/proc/upgrade_turrets - usr:current_modules += new /datum/AI_Module/large/upgrade_turrets - src.temp = "Improves the firing speed and health of all AI turrets. This effect is permanent." - src.processing_time -= 50 - else src.temp = "This module is only needed once." + if(!isAI(usr)) + return + var/mob/living/silicon/ai/A = usr - else if (href_list["rcd"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/large/disable_rcd)) - mod:uses += 1 - already = 1 - if (!already) - usr:current_modules += new /datum/AI_Module/large/disable_rcd - usr.verbs += /client/proc/disable_rcd - src.temp = "Send a specialised pulse to break all RCD devices on the station." - else src.temp = "Additional use added to RCD disabler." - src.processing_time -= 50 + for(var/datum/AI_Module/AM in possible_modules) + if (href_list[AM.mod_pick_name]) - else if (href_list["overload"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/small/overload_machine)) - mod:uses += 2 - already = 1 - if (!already) - usr.verbs += /client/proc/overload_machine - usr:current_modules += new /datum/AI_Module/small/overload_machine - src.temp = "Overloads an electrical machine, causing a small explosion. 2 uses." - else src.temp = "Two additional uses added to Overload module." - src.processing_time -= 15 + // Cost check + if(AM.cost > src.processing_time) + temp = "You cannot afford this module." + break - else if (href_list["blackout"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/small/blackout)) - mod:uses += 3 - already = 1 - if (!already) - usr.verbs += /client/proc/blackout - src.temp = "Attempts to overload the lighting circuits on the station, destroying some bulbs. 3 uses." - usr:current_modules += new /datum/AI_Module/small/blackout - else src.temp = "Three additional uses added to Blackout module." - src.processing_time -= 15 + // Add new uses if we can, and it is allowed. + var/datum/AI_Module/already_AM = locate(AM.type) in A.current_modules + if(already_AM) + if(!AM.one_time) + already_AM.uses += AM.uses + src.processing_time -= AM.cost + temp = "Additional use added to [already_AM.module_name]" + break + else + temp = "This module is only needed once." + break - else if (href_list["interhack"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/small/interhack)) - already = 1 - if (!already) - usr.verbs += /client/proc/interhack - src.temp = "Hacks the status upgrade from Cent. Com, removing any information about malfunctioning electrical systems." - usr:current_modules += new /datum/AI_Module/small/interhack - src.processing_time -= 15 - else src.temp = "This module is only needed once." + // Give the power and take away the money. + A.verbs += AM.power_type + A.current_modules += new AM.type + temp = AM.description + src.processing_time -= AM.cost - else if (href_list["recam"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/small/reactivate_camera)) - mod:uses += 10 - already = 1 - if (!already) - usr.verbs += /client/proc/reactivate_camera - src.temp = "Reactivates a currently disabled camera. 10 uses." - usr:current_modules += new /datum/AI_Module/small/reactivate_camera - else src.temp = "Ten additional uses added to ReCam module." - src.processing_time -= 15 - - else if(href_list["upgradecam"]) - var/already - for (var/datum/AI_Module/mod in usr:current_modules) - if(istype(mod, /datum/AI_Module/small/upgrade_camera)) - mod:uses += 10 - already = 1 - if (!already) - usr.verbs += /client/proc/upgrade_camera - src.temp = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 10 uses." - usr:current_modules += new /datum/AI_Module/small/upgrade_camera - else src.temp = "Ten additional uses added to ReCam module." - src.processing_time -= 15 - - else - if (href_list["temp"]) - src.temp = null src.use(usr) return diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index 3a19021f250..31cf3537816 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -4,9 +4,9 @@ /datum/game_mode/malfunction name = "AI malfunction" config_tag = "malfunction" - required_players = 20 - required_enemies = 1 - recommended_enemies = 1 + required_players = 0//20 + required_enemies = 0//1 + recommended_enemies = 0//1 uplink_welcome = "Crazy AI Uplink Console:" uplink_uses = 10 @@ -52,7 +52,7 @@ return AI_mind.current.verbs += /mob/living/silicon/ai/proc/choose_modules AI_mind.current:laws = new /datum/ai_laws/malfunction - AI_mind.current:malf_picker = new /datum/AI_Module/module_picker + AI_mind.current:malf_picker = new /datum/module_picker AI_mind.current:show_laws() greet_malf(AI_mind) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index e3c63e3d4f6..21ba2762c75 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -6,7 +6,7 @@ var/bomb_set icon = 'icons/obj/stationobjs.dmi' icon_state = "nuclearbomb0" density = 1 - var/deployable = 0.0 + var/extended = 0.0 var/timeleft = 60.0 var/timing = 0.0 @@ -28,19 +28,23 @@ var/bomb_set src.timeleft-- if (src.timeleft <= 0) explode() + else + playsound(loc, 'sound/items/timer.ogg', 5, 0) for(var/mob/M in viewers(1, src)) if ((M.client && M.machine == src)) src.attack_hand(M) return /obj/machinery/nuclearbomb/attackby(obj/item/weapon/I as obj, mob/user as mob) - if (src.extended) - if (istype(I, /obj/item/weapon/disk/nuclear)) - usr.drop_item() - I.loc = src - src.auth = I - src.add_fingerprint(user) + if (istype(I, /obj/item/weapon/disk/nuclear)) + if (!src.extended) + user << "You have to deploy the bomb first." return + usr.drop_item() + I.loc = src + src.auth = I + src.add_fingerprint(user) + return ..() /obj/machinery/nuclearbomb/attack_paw(mob/user as mob) @@ -68,22 +72,20 @@ var/bomb_set dat += text("
\n>[]
\n1-2-3
\n4-5-6
\n7-8-9
\nR-0-E
\n", message, src, src, src, src, src, src, src, src, src, src, src, src) user << browse(dat, "window=nuclearbomb;size=300x400") onclose(user, "nuclearbomb") - else if (src.deployable) - src.anchored = 1 - flick("nuclearbombc", src) - src.icon_state = "nuclearbomb1" - src.extended = 1 + else + user << "You have to deploy the bomb first." return /obj/machinery/nuclearbomb/verb/make_deployable() set category = "Object" - set name = "Make Deployable" + set name = "Deploy Bomb" set src in oview(1) - if (src.deployable) - src.deployable = 0 - else - src.deployable = 1 + if (!src.extended) + src.anchored = 1 + flick("nuclearbombc", src) + src.icon_state = "nuclearbomb1" + src.extended = 1 /obj/machinery/nuclearbomb/Topic(href, href_list) ..() diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index a6211b5ba3e..eb069bc7abd 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -93,6 +93,7 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/atmospheric_technician(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/atmos(H), slot_l_store) + H.equip_to_slot_or_del(new /obj/item/device/analyzer(H), slot_r_store) H.equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/atmostech/(H), slot_belt) if(H.backbag == 1) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H), slot_r_hand) diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm index 41f4fc3fe53..baba7988bf5 100644 --- a/code/game/machinery/Freezer.dm +++ b/code/game/machinery/Freezer.dm @@ -1,7 +1,7 @@ /obj/machinery/atmospherics/unary/cold_sink/freezer - name = "Freezer" + name = "freezer" icon = 'icons/obj/Cryogenic2.dmi' - icon_state = "freezer_0" + icon_state = "freezer" density = 1 anchored = 1.0 @@ -32,7 +32,7 @@ else icon_state = "freezer" else - icon_state = "freezer_0" + icon_state = "freezer" return attack_ai(mob/user as mob) @@ -91,7 +91,7 @@ /obj/machinery/atmospherics/unary/heat_reservoir/heater name = "heater" icon = 'icons/obj/Cryogenic2.dmi' - icon_state = "freezer_0" + icon_state = "heater" density = 1 anchored = 1.0 @@ -118,11 +118,11 @@ update_icon() if(src.node) if(src.on) - icon_state = "freezer_1" + icon_state = "heater_1" else - icon_state = "freezer" + icon_state = "heater" else - icon_state = "freezer_0" + icon_state = "heater" return attack_ai(mob/user as mob) diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index dccfb930f63..cb70435fd00 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -1,28 +1,4 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - - -/proc/RandomAAlarmWires() - //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else). - var/list/AAlarmwires = list(0, 0, 0, 0, 0) - AAlarmIndexToFlag = list(0, 0, 0, 0, 0) - AAlarmIndexToWireColor = list(0, 0, 0, 0, 0) - AAlarmWireColorToIndex = list(0, 0, 0, 0, 0) - var/flagIndex = 1 - for (var/flag=1, flag<32, flag+=flag) - var/valid = 0 - while (!valid) - var/colorIndex = rand(1, 5) - if (AAlarmwires[colorIndex]==0) - valid = 1 - AAlarmwires[colorIndex] = flag - AAlarmIndexToFlag[flagIndex] = flag - AAlarmIndexToWireColor[flagIndex] = colorIndex - AAlarmWireColorToIndex[colorIndex] = flagIndex - flagIndex+=1 - return AAlarmwires - - - // A datum for dealing with threshold limit values // used in /obj/machinery/alarm /datum/tlv @@ -51,6 +27,20 @@ max1 = other.max1 max2 = other.max2 +#define AALARM_MODE_SCRUBBING 1 +#define AALARM_MODE_VENTING 2 //makes draught +#define AALARM_MODE_PANIC 3 //constantly sucks all air +#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing +#define AALARM_MODE_OFF 5 + +#define AALARM_SCREEN_MAIN 1 +#define AALARM_SCREEN_VENT 2 +#define AALARM_SCREEN_SCRUB 3 +#define AALARM_SCREEN_MODE 4 +#define AALARM_SCREEN_SENSORS 5 + +#define AALARM_REPORT_TIMEOUT 100 + /obj/machinery/alarm name = "alarm" icon = 'icons/obj/monitors.dmi' @@ -64,36 +54,19 @@ var/frequency = 1439 //var/skipprocess = 0 //Experimenting var/alarm_frequency = 1437 -#define AALARM_REPORT_TIMEOUT 100 + var/datum/radio_frequency/radio_connection var/locked = 1 + var/datum/wires/alarm/wires = null var/wiresexposed = 0 // If it's been screwdrivered open. var/aidisabled = 0 var/AAlarmwires = 31 var/shorted = 0 var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone - // Uses code from apc.dm -#define AALARM_WIRE_IDSCAN 1 //Added wires -#define AALARM_WIRE_POWER 2 -#define AALARM_WIRE_SYPHON 3 -#define AALARM_WIRE_AI_CONTROL 4 -#define AALARM_WIRE_AALARM 5 - - -#define AALARM_MODE_SCRUBBING 1 -#define AALARM_MODE_VENTING 2 //makes draught -#define AALARM_MODE_PANIC 3 //constantly sucks all air -#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing -#define AALARM_MODE_OFF 5 var/mode = AALARM_MODE_SCRUBBING -#define AALARM_SCREEN_MAIN 1 -#define AALARM_SCREEN_VENT 2 -#define AALARM_SCREEN_SCRUB 3 -#define AALARM_SCREEN_MODE 4 -#define AALARM_SCREEN_SENSORS 5 var/screen = AALARM_SCREEN_MAIN var/area_uid var/area/alarm_area @@ -145,6 +118,7 @@ /obj/machinery/alarm/New(nloc, ndir, nbuild) ..() + wires = new(src) if(nloc) loc = nloc @@ -201,31 +175,6 @@ user << browse(null, "window=air_alarm") return - if(wiresexposed && (!istype(user, /mob/living/silicon))) - var/t1 = text("Access Panel
\n") - var/list/AAlarmwires = list( - "Orange" = 1, - "Dark red" = 2, - "White" = 3, - "Yellow" = 4, - "Black" = 5, - ) - for(var/wiredesc in AAlarmwires) - var/is_uncut = src.AAlarmwires & AAlarmWireColorToFlag[AAlarmwires[wiredesc]] - t1 += "[wiredesc] wire: " - if(!is_uncut) - t1 += "Mend" - - else - t1 += "Cut " - t1 += "Pulse " - - t1 += "
" - t1 += text("
\n[(src.locked ? "The Air Alarm is locked." : "The Air Alarm is unlocked.")]
\n[((src.shorted || (stat & (NOPOWER|BROKEN))) ? "The Air Alarm is offline." : "The Air Alarm is working properly!")]
\n[(src.aidisabled ? "The 'AI control allowed' light is off." : "The 'AI control allowed' light is on.")]") - t1 += text("

Close

") - user << browse(t1, "window=AAlarmwires") - onclose(user, "AAlarmwires") - if(!shorted) //user << browse(return_text(),"window=air_alarm") //onclose(user, "air_alarm") @@ -235,135 +184,11 @@ popup.open() refresh_all() - return - - -/obj/machinery/alarm/proc/isWireColorCut(var/wireColor) - var/wireFlag = AAlarmWireColorToFlag[wireColor] - return ((src.AAlarmwires & wireFlag) == 0) - -/obj/machinery/alarm/proc/isWireCut(var/wireIndex) - var/wireFlag = AAlarmIndexToFlag[wireIndex] - return ((src.AAlarmwires & wireFlag) == 0) - -/obj/machinery/alarm/proc/cut(var/wireColor) - var/wireFlag = AAlarmWireColorToFlag[wireColor] - var/wireIndex = AAlarmWireColorToIndex[wireColor] - AAlarmwires &= ~wireFlag - switch(wireIndex) - if(AALARM_WIRE_IDSCAN) - src.locked = 1 - //world << "Idscan wire cut" - - if(AALARM_WIRE_POWER) - src.shock(usr, 50) - src.shorted = 1 - update_icon() - //world << "Power wire cut" - - if (AALARM_WIRE_AI_CONTROL) - if (src.aidisabled == 0) - src.aidisabled = 1 - //world << "AI Control Wire Cut" - - if(AALARM_WIRE_SYPHON) - mode = AALARM_MODE_PANIC - apply_mode() - //world << "Syphon Wire Cut" - - if(AALARM_WIRE_AALARM) - - if (alarm_area.atmosalert(2)) - post_alert(2) - spawn(1) - src.updateUsrDialog() - update_icon() - - //world << "AAlarm Wire Cut" - - src.updateDialog() - update_icon() + if(wiresexposed && (!istype(user, /mob/living/silicon))) + wires.Interact(user) return -/obj/machinery/alarm/proc/mend(var/wireColor) - var/wireFlag = AAlarmWireColorToFlag[wireColor] - var/wireIndex = AAlarmWireColorToIndex[wireColor] //not used in this function - AAlarmwires |= wireFlag - switch(wireIndex) - if(AALARM_WIRE_IDSCAN) - //world << "Idscan wire mended" - - if(AALARM_WIRE_POWER) - src.shorted = 0 - src.shock(usr, 50) - update_icon() - //world << "Power wire mended" - - if(AALARM_WIRE_AI_CONTROL) - if (src.aidisabled == 1) - src.aidisabled = 0 - //world << "AI Cont. wire mended" - - - // if(AALARM_WIRE_SYPHON) - // world << "Syphon Wire mended" - - - // if(AALARM_WIRE_AALARM) - //world << "AAlarm Wire mended" - - update_icon() - src.updateDialog() - return - -/obj/machinery/alarm/proc/pulse(var/wireColor) - //var/wireFlag = AAlarmWireColorToFlag[wireColor] //not used in this function - var/wireIndex = AAlarmWireColorToIndex[wireColor] - switch(wireIndex) - if(AALARM_WIRE_IDSCAN) //unlocks for 30 seconds, if you have a better way to hack I'm all ears - src.locked = 0 - spawn(300) - src.locked = 1 - //world << "Idscan wire pulsed" - - if (AALARM_WIRE_POWER) - // world << "Power wire pulsed" - if(shorted == 0) - shorted = 1 - update_icon() - - spawn(1200) - if(shorted == 1) - shorted = 0 - update_icon() - - - if (AALARM_WIRE_AI_CONTROL) - // world << "AI Control wire pulsed" - if (src.aidisabled == 0) - src.aidisabled = 1 - src.updateDialog() - spawn(10) - if (src.aidisabled == 1) - src.aidisabled = 0 - src.updateDialog() - - if(AALARM_WIRE_SYPHON) - // world << "Syphon wire pulsed" - mode = AALARM_MODE_REPLACEMENT - apply_mode() - - if(AALARM_WIRE_AALARM) - // world << "Aalarm wire pulsed" - if (alarm_area.atmosalert(0)) - post_alert(0) - spawn(1) - src.updateUsrDialog() - update_icon() - - src.updateDialog() - return /obj/machinery/alarm/proc/shock(mob/user, prb) if((stat & (NOPOWER))) // unpowered, no shock @@ -702,33 +527,8 @@ table tr:first-child th:first-child { border: none;} if (!istype(usr, /mob/living/silicon)) usr.unset_machine() usr << browse(null, "window=air_alarm") - usr << browse(null, "window=AAlarmwires") return - if (href_list["AAlarmwires"]) - var/t1 = text2num(href_list["AAlarmwires"]) - if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) )) - usr << "You need wirecutters!" - return - if (src.isWireColorCut(t1)) - src.mend(t1) - else - src.cut(t1) - spawn(1) - src.updateUsrDialog() - else if (href_list["pulse"]) - var/t1 = text2num(href_list["pulse"]) - if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) - usr << "You need a multitool!" - return - if (src.isWireColorCut(t1)) - usr << "You can't pulse a cut wire." - return - else - src.pulse(t1) - spawn(1) - src.updateUsrDialog() - if(href_list["command"]) @@ -988,7 +788,7 @@ table tr:first-child th:first-child { border: none;} if(stat & (NOPOWER|BROKEN)) user << "It does nothing" else - if(src.allowed(usr) && !isWireCut(AALARM_WIRE_IDSCAN)) + if(src.allowed(usr) && !wires.IsIndexCut(AALARM_WIRE_IDSCAN)) locked = !locked user << "\blue You [ locked ? "lock" : "unlock"] the Air Alarm interface." src.updateUsrDialog() @@ -1055,8 +855,8 @@ Just a object used in constructing air alarms */ /obj/item/weapon/airalarm_electronics name = "air alarm electronics" - icon = 'icons/obj/doors/door_assembly.dmi' - icon_state = "door_electronics" + icon = 'icons/obj/module.dmi' + icon_state = "airalarm_electronics" desc = "Looks like a circuit. Probably is." w_class = 2.0 m_amt = 50 diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index a98d0ba9c0b..3795baf0fcd 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -7,6 +7,7 @@ var/global/list/autolathe_recipes = list( \ new /obj/item/device/flashlight(), \ new /obj/item/weapon/extinguisher(), \ new /obj/item/device/multitool(), \ + new /obj/item/device/analyzer(), \ new /obj/item/device/t_scanner(), \ new /obj/item/weapon/weldingtool(), \ new /obj/item/weapon/screwdriver(), \ diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 0a789b2cf21..f0ef6f1907b 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -91,6 +91,7 @@ return /obj/machinery/camera/blob_act() + del(src) return /obj/machinery/camera/proc/setViewRange(var/num = 7) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 6f3190f9ee1..ff0e2a25da4 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -456,10 +456,6 @@ user << "The emergency shuttle is already on its way." return - if(ticker.mode.name == "blob") - user << "Under directive 7-10, [station_name()] is quarantined until further notice." - return - emergency_shuttle.incall() log_game("[key_name(user)] has called the shuttle.") message_admins("[key_name_admin(user)] has called the shuttle.", 1) @@ -472,7 +468,7 @@ /proc/cancel_call_proc(var/mob/user) if ((!( ticker ) || emergency_shuttle.location || emergency_shuttle.direction == 0 || emergency_shuttle.timeleft() < 300)) return - if((ticker.mode.name == "blob")||(ticker.mode.name == "meteor")) + if(ticker.mode.name == "meteor") return if(emergency_shuttle.direction != -1 && emergency_shuttle.online) //check that shuttle isn't already heading to centcom diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 1f59dbe475a..a44326ebbcd 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -513,7 +513,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() var/list/memory = list() // stored memory var/rawcode = "" // the code to compile (raw text) - var/compiling = 0 // Are we compiling? + var/datum/TCS_Compiler/Compiler // the compiler that compiles and runs the code var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up @@ -615,13 +615,8 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() /obj/machinery/telecomms/server/proc/compile(var/mob/user) - if(Compiler && !compiling) - // BONUS FEATURE: REAL LIFE COMPILE TIME FOR 2556 SPACE MENS - compiling = 1 - if(length(rawcode)) // Don't bother compiling if it's empty code. - sleep(Clamp((10 + length(rawcode)) / 5, 100, 1500)) // Max time: 2.5 minutes - Min time: 10 seconds + if(Compiler) admin_log(user) - compiling = 0 return Compiler.Compile(rawcode) /obj/machinery/telecomms/server/proc/update_logs() diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 32e37245ce1..4c61a95ea25 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -84,7 +84,7 @@ if (M.timeofdeath + 6000 < world.time) continue var/turf/T = get_turf(M) - if(T) continue + if(!T) continue if(T.z == 2) continue var/tmpname = M.real_name if(areaindex[tmpname]) @@ -368,4 +368,4 @@ if(com) com.icon_state = "tele0" else - icon_state = "controller" + icon_state = "controller" diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index f25f835c691..85cd6f75d13 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -1,6 +1,6 @@ /turf/simulated/floor/mech_bay_recharge_floor name = "Mech Bay Recharge Station" - icon = 'icons/mecha/mech_bay.dmi' + icon = 'icons/turf/floors.dmi' icon_state = "recharge_floor" var/obj/machinery/mech_bay_recharge_port/recharge_port var/obj/machinery/computer/mech_bay_power_console/recharge_console diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 259b64cb277..0bd187a53f6 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -609,6 +609,10 @@ return */ +/obj/mecha/blob_act() + take_damage(30, "brute") + return + //TODO /obj/mecha/meteorhit() return ex_act(rand(1,3))//should do for now diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm index d5349ceae69..57c68b7a714 100644 --- a/code/game/mecha/mecha_construction_paths.dm +++ b/code/game/mecha/mecha_construction_paths.dm @@ -237,7 +237,7 @@ user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") holder.icon_state = "ripley10" else - user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + user.visible_message("[user] pries internal armor layer from [holder].", "You pry internal armor layer from [holder].") var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder)) MS.amount = 5 holder.icon_state = "ripley8" @@ -260,7 +260,7 @@ user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") holder.icon_state = "ripley13" else - user.visible_message("[user] pries external armor layer from [holder].", "You prie external armor layer from [holder].") + user.visible_message("[user] pries external armor layer from [holder].", "You pry external armor layer from [holder].") var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder)) MS.amount = 5 holder.icon_state = "ripley11" @@ -519,7 +519,7 @@ user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") holder.icon_state = "gygax16" else - user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + user.visible_message("[user] pries internal armor layer from [holder].", "You pry internal armor layer from [holder].") var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder)) MS.amount = 5 holder.icon_state = "gygax14" @@ -543,7 +543,7 @@ user.visible_message("[user] secures Gygax Armour Plates.", "You secure Gygax Armour Plates.") holder.icon_state = "gygax19" else - user.visible_message("[user] pries Gygax Armour Plates from [holder].", "You prie Gygax Armour Plates from [holder].") + user.visible_message("[user] pries Gygax Armour Plates from [holder].", "You pry Gygax Armour Plates from [holder].") new /obj/item/mecha_parts/part/gygax_armour(get_turf(holder)) holder.icon_state = "gygax17" if(1) @@ -733,7 +733,7 @@ user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") holder.icon_state = "fireripley10" else - user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + user.visible_message("[user] pries internal armor layer from [holder].", "You pry internal armor layer from [holder].") var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder)) MS.amount = 5 holder.icon_state = "fireripley8" @@ -765,7 +765,7 @@ user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") holder.icon_state = "fireripley14" else - user.visible_message("[user] pries external armor layer from [holder].", "You prie external armor layer from [holder].") + user.visible_message("[user] pries external armor layer from [holder].", "You pry external armor layer from [holder].") var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder)) MS.amount = 5 holder.icon_state = "fireripley12" @@ -1101,7 +1101,7 @@ user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") holder.icon_state = "durand16" else - user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + user.visible_message("[user] pries internal armor layer from [holder].", "You pry internal armor layer from [holder].") var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder)) MS.amount = 5 holder.icon_state = "durand14" @@ -1125,7 +1125,7 @@ user.visible_message("[user] secures Durand Armour Plates.", "You secure Durand Armour Plates.") holder.icon_state = "durand19" else - user.visible_message("[user] pries Durand Armour Plates from [holder].", "You prie Durand Armour Plates from [holder].") + user.visible_message("[user] pries Durand Armour Plates from [holder].", "You pry Durand Armour Plates from [holder].") new /obj/item/mecha_parts/part/durand_armour(get_turf(holder)) holder.icon_state = "durand17" if(1) @@ -1332,7 +1332,7 @@ user.visible_message("[user] secures internal armor layer.", "You secure internal armor layer.") holder.icon_state = "odysseus10" else - user.visible_message("[user] pries internal armor layer from [holder].", "You prie internal armor layer from [holder].") + user.visible_message("[user] pries internal armor layer from [holder].", "You pry internal armor layer from [holder].") var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder)) MS.amount = 5 holder.icon_state = "odysseus8" @@ -1351,13 +1351,14 @@ else user.visible_message("[user] cuts internal armor layer from [holder].", "You cut the internal armor layer from [holder].") holder.icon_state = "odysseus10" + if(2) if(diff==FORWARD) user.visible_message("[user] secures external armor layer.", "You secure external reinforced armor layer.") holder.icon_state = "odysseus13" else var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder)) MS.amount = 5 - user.visible_message("[user] pries [MS] from [holder].", "You prie [MS] from [holder].") + user.visible_message("[user] pries [MS] from [holder].", "You pry [MS] from [holder].") holder.icon_state = "odysseus11" if(1) if(diff==FORWARD) diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index d8479d11d99..cfd082ceadf 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -131,6 +131,8 @@ move an amendment to the drawing.

A.power_environ = 0 A.always_unpowered = 0 move_turfs_to_area(turfs, A) + A.SetDynamicLighting() + spawn(5) //ma = A.master ? "[A.master]" : "(null)" //world << "DEBUG: create_area(5):
A.name=[A.name]
A.tag=[A.tag]
A.master=[ma]" diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 9228b425b8c..7cb46a33d89 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -887,49 +887,14 @@ var/global/list/obj/item/device/pda/PDAs = list() /obj/item/device/pda/attack(mob/living/carbon/C, mob/living/user as mob) if(istype(C)) switch(scanmode) + if(1) - - for (var/mob/O in viewers(C, null)) - O.show_message("\red [user] has analyzed [C]'s vitals!", 1) - - user.show_message("\blue Analyzing Results for [C]:") - user.show_message("\blue \t Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) - user.show_message("\blue \t Damage Specifics: [C.getOxyLoss() > 50 ? "\red" : "\blue"][C.getOxyLoss()]-[C.getToxLoss() > 50 ? "\red" : "\blue"][C.getToxLoss()]-[C.getFireLoss() > 50 ? "\red" : "\blue"][C.getFireLoss()]-[C.getBruteLoss() > 50 ? "\red" : "\blue"][C.getBruteLoss()]", 1) - user.show_message("\blue \t Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue \t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) - if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) - user.show_message("\blue \t Time of Death: [C.tod]") - if(istype(C, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("\blue Localized Damage, Brute/Burn:",1) - if(length(damaged)>0) - for(var/datum/limb/org in damaged) - user.show_message(text("\blue \t []: []\blue-[]",capitalize(org.getDisplayName()),(org.brute_dam > 0)?"\red [org.brute_dam]":0,(org.burn_dam > 0)?"\red [org.burn_dam]":0),1) - else - user.show_message("\blue \t Limbs are OK.",1) - - for(var/datum/disease/D in C.viruses) - if(!D.hidden[SCANNER]) - user.show_message(text("\red Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + user.visible_message(text("[] has analyzed []'s vitals!", user, C)) + healthscan(user, C, 1) + src.add_fingerprint(user) if(2) - if(!istype(C.dna)) - user << "\blue No fingerprints found on [C]" - else if(!istype(C, /mob/living/carbon/monkey)) - if(!isnull(C:gloves)) - user << "\blue No fingerprints found on [C]" - else - user << text("\blue [C]'s Fingerprints: [md5(C.dna.uni_identity)]") - if ( !(C:blood_DNA) ) - user << "\blue No blood found on [C]" - if(C:blood_DNA) - del(C:blood_DNA) - else - user << "\blue Blood found on [C]. Analysing..." - spawn(15) - for(var/blood in C:blood_DNA) - user << "\blue Blood type: [C:blood_DNA[blood]]\nDNA: [blood]" + // Unused if(4) for (var/mob/O in viewers(C, null)) diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 0d4895dc65b..cf4a93e3fb5 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -17,4 +17,49 @@ m_amt = 50 g_amt = 20 origin_tech = "magnets=1;engineering=1" - var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage \ No newline at end of file + var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage + + +// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby. + + +/obj/item/device/multitool/ai_detect + var/track_delay = 0 + +/obj/item/device/multitool/ai_detect/New() + ..() + processing_objects += src + + +/obj/item/device/multitool/ai_detect/Del() + processing_objects -= 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)) + + 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) + var/turf/eye_turf = get_turf(A) + if(get_dist(our_turf, eye_turf) < 8) + found_eye = 1 + break + + if(found_eye) + icon_state = "[initial(icon_state)]_red" + else + icon_state = initial(icon_state) + + track_delay = world.time + 10 // 1 second + return + diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 52ce6f0ce7b..1a0ffa821f6 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -55,6 +55,13 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use initialize() +/obj/item/device/radio/MouseDrop(obj/over_object as obj, src_location, over_location) + var/mob/M = usr + if((!istype(over_object, /obj/screen)) && src.loc == M) + return attack_self(M) + return + + /obj/item/device/radio/initialize() if(freerange) @@ -797,4 +804,4 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use /obj/item/device/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag. - listening = 0 // And it's nice to have a subtype too for future features. + listening = 0 // And it's nice to have a subtype too for future features. diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index e753d4f51bc..d1bab674f31 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -76,61 +76,79 @@ MASS SPECTROMETER var/mode = 1; /obj/item/device/healthanalyzer/attack(mob/living/M as mob, mob/living/user as mob) - if (( (CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) - user << text("\red You try to analyze the floor's vitals!") - for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [user] has analyzed the floor's vitals!"), 1) - user.show_message(text("\blue Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\blue \t Damage Specifics: [0]-[0]-[0]-[0]"), 1) - user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue Body Temperature: ???", 1) + + // Clumsiness/brain damage check + if ((CLUMSY in user.mutations || user.getBrainLoss() >= 60) && prob(50)) + user << text("You stupidly try to analyze the floor's vitals!") + user.visible_message(text("[user] has analyzed the floor's vitals!")) + user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) + user.show_message(text("\t Damage Specifics: 0-0-0-0"), 1) + user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) + user.show_message("Body Temperature: ???", 1) return - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - usr << "\red You don't have the dexterity to do this!" - return - for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [] has analyzed []'s vitals!", user, M), 1) - //Foreach goto(67) - var/fake_oxy = max(rand(1,40), M.getOxyLoss(), (300 - (M.getToxLoss() + M.getFireLoss() + M.getBruteLoss()))) + + + user.visible_message(text("[] has analyzed []'s vitals!", user, M)) + + healthscan(user, M, mode) + + src.add_fingerprint(user) + return + +// Used by the PDA medical scanner too +/proc/healthscan(var/mob/living/user, var/mob/living/M, var/mode = 1) + + //Damage specifics + var/oxy_loss = M.getOxyLoss() + var/tox_loss = M.getToxLoss() + var/fire_loss = M.getFireLoss() + var/brute_loss = M.getBruteLoss() + var/mob_status = (M.stat > 1 ? "Deceased" : text("[]% healthy", M.health - M.halloss)) + if(M.status_flags & FAKEDEATH) - user.show_message(text("\blue Analyzing Results for []:\n\t Overall Status: []", M, "dead"), 1) - user.show_message(text("\blue \t Damage Specifics: []-[]-[]-[]", fake_oxy < 50 ? "\red [fake_oxy]" : fake_oxy , M.getToxLoss() > 50 ? "\red [M.getToxLoss()]" : M.getToxLoss(), M.getFireLoss() > 50 ? "\red[M.getFireLoss()]" : M.getFireLoss(), M.getBruteLoss() > 50 ? "\red[M.getBruteLoss()]" : M.getBruteLoss()), 1) - else - user.show_message(text("\blue Analyzing Results for []:\n\t Overall Status: []", M, (M.stat > 1 ? "dead" : text("[]% healthy", M.health - M.halloss))), 1) - user.show_message(text("\blue \t Damage Specifics: []-[]-[]-[]", M.getOxyLoss() > 50 ? "\red [M.getOxyLoss()]" : M.getOxyLoss(), M.getToxLoss() > 50 ? "\red [M.getToxLoss()]" : M.getToxLoss(), M.getFireLoss() > 50 ? "\red[M.getFireLoss()]" : M.getFireLoss(), M.getBruteLoss() > 50 ? "\red[M.getBruteLoss()]" : M.getBruteLoss()), 1) - user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + mob_status = "Deceased" + oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss + + user.show_message(text("Analyzing Results for []:\n\t Overall Status: []", M, mob_status), 1) + user.show_message(text("\t Damage Specifics: []-[]-[]-[]", oxy_loss, tox_loss, fire_loss, brute_loss), 1) + + user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) + user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + + // Time of death if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) - user.show_message("\blue Time of Death: [M.tod]") + user.show_message("Time of Death: [M.tod]") + + // Organ damage report if(istype(M, /mob/living/carbon/human) && mode == 1) var/mob/living/carbon/human/H = M var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("\blue Localized Damage, Brute/Burn:",1) + user.show_message("Localized Damage, Burn/Brute:",1) if(length(damaged)>0) for(var/datum/limb/org in damaged) - user.show_message(text("\blue \t []: []\blue-[]",capitalize(org.getDisplayName()),(org.brute_dam > 0)?"\red [org.brute_dam]":0,(org.burn_dam > 0)?"\red [org.burn_dam]":0),1) + user.show_message(text("\t []: []-[]", capitalize(org.getDisplayName()), (org.burn_dam > 0) ? "[org.burn_dam]" : 0, (org.brute_dam > 0) ? "[org.brute_dam]" : 0), 1) else - user.show_message("\blue \t Limbs are OK.",1) + user.show_message("\t Limbs are OK.",1) + + // Damage descriptions + + user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", brute_loss > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) - if(M.status_flags & FAKEDEATH) - user.show_message(text("\blue [] | [] | [] | []", fake_oxy > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", M.getToxLoss() > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", M.getFireLoss() > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", M.getBruteLoss() > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) - else - user.show_message(text("\blue [] | [] | [] | []", M.getOxyLoss() > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", M.getToxLoss() > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", M.getFireLoss() > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", M.getBruteLoss() > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) if (M.getCloneLoss()) - user.show_message(text("\red Subject appears to have been imperfectly cloned."), 1) + user.show_message(text("Subject appears to have been imperfectly cloned."), 1) + for(var/datum/disease/D in M.viruses) if(!D.hidden[SCANNER]) - user.show_message(text("\red Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + user.show_message(text("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) - user.show_message(text("\blue Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals."), 1) + user.show_message(text("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals."), 1) if (M.getBrainLoss() >= 100 || !getbrain(M)) - user.show_message(text("\red Subject is brain dead."), 1) + user.show_message(text("Subject brain function is non-existant."), 1) else if (M.getBrainLoss() >= 60) - user.show_message(text("\red Severe brain damage detected. Subject likely to have mental retardation."), 1) + user.show_message(text("Severe brain damage detected. Subject likely to have mental retardation."), 1) else if (M.getBrainLoss() >= 10) - user.show_message(text("\red Significant brain damage detected. Subject may have had a concussion."), 1) - src.add_fingerprint(user) - return + user.show_message(text("Significant brain damage detected. Subject may have had a concussion."), 1) /obj/item/device/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" @@ -163,9 +181,6 @@ MASS SPECTROMETER if (user.stat) return - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - usr << "\red You don't have the dexterity to do this!" - return var/turf/location = user.loc if (!( istype(location, /turf) )) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 888c2e126f2..3b1f70d7199 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -34,10 +34,6 @@ AI MODULES usr << "You haven't selected an AI to transmit laws to!" return - if(ticker && ticker.mode && ticker.mode.name == "blob") - usr << "Law uploads have been disabled by NanoTrasen!" - return - if (comp.current.stat == 2 || comp.current.control_disabled == 1) usr << "Upload failed. No signal is being detected from the AI." else if (comp.current.see_in_dark == 0) diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 501cd781fdb..d6733dce656 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -1,21 +1,64 @@ /obj/item/weapon/dice name = "d6" - desc = "A dice with six sides." + desc = "A die with six sides. Basic and servicable." icon = 'icons/obj/dice.dmi' icon_state = "d6" w_class = 1 var/sides = 6 /obj/item/weapon/dice/New() - icon_state = "[initial(icon_state)][rand(sides)]" + icon_state = "[initial(icon_state)][rand(1, sides)]" + +/obj/item/weapon/dice/d2 + name = "d2" + desc = "A die with two sides. Coins are undignified!" + icon_state = "d2" + sides = 2 + +/obj/item/weapon/dice/d4 + name = "d4" + desc = "A die with four sides. The nerd's caltrop." + icon_state = "d4" + sides = 4 + +/obj/item/weapon/dice/d8 + name = "d8" + desc = "A die with eight sides. It feels... lucky." + icon_state = "d8" + sides = 8 + +/obj/item/weapon/dice/d10 + name = "d10" + desc = "A die with ten sides. Useful for percentages." + icon_state = "d10" + sides = 10 + +/obj/item/weapon/dice/d00 + name = "d00" + desc = "A die with ten sides. Works better for d100 rolls than a golfball." + icon_state = "d00" + sides = 10 + +/obj/item/weapon/dice/d12 + name = "d12" + desc = "A die with twelve sides. There's an air of neglect about it." + icon_state = "d12" + sides = 12 /obj/item/weapon/dice/d20 name = "d20" - desc = "A dice with twenty sides." + desc = "A die with twenty sides. The prefered die to throw at the GM." icon_state = "d20" sides = 20 /obj/item/weapon/dice/attack_self(mob/user as mob) + diceroll(user) + +/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user as mob) + ..() + diceroll(user) + +/obj/item/weapon/dice/proc/diceroll(mob/user as mob) var/result = rand(1, sides) var/comment = "" if(sides == 20 && result == 20) @@ -23,6 +66,11 @@ else if(sides == 20 && result == 1) comment = "Ouch, bad luck." icon_state = "[initial(icon_state)][result]" - user.visible_message("[user] has thrown [src]. It lands on [result]. [comment]", \ - "You throw [src]. It lands on a [result]. [comment]", \ - "You hear [src] landing on a [result]. [comment]") \ No newline at end of file + if(initial(icon_state) == "d00") + result = (result - 1)*10 + if(user != null) //Dice was rolled in someone's hand + user.visible_message("[user] has thrown [src]. It lands on [result]. [comment]", \ + "You throw [src]. It lands on [result]. [comment]", \ + "You hear [src] landing on [result]. [comment]") + else if(src.throwing == 0) //Dice was thrown and is coming to rest + src.loc.visible_message("[src] rolls to a stop, landing on [result]. [comment]") \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 2abf087a824..516aeb52008 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -157,6 +157,8 @@ playsound(loc, 'sound/effects/bamf.ogg', 50, 1) + update_mob() + for(var/obj/item/weapon/reagent_containers/glass/G in beakers) G.reagents.trans_to(src, G.reagents.total_volume) @@ -208,6 +210,8 @@ playsound(loc, 'sound/effects/bamf.ogg', 50, 1) + update_mob() + if(valid_core) for(var/obj/item/weapon/reagent_containers/glass/G in beakers) G.reagents.trans_to(valid_core, G.reagents.total_volume) diff --git a/code/game/objects/items/weapons/grenades/emgrenade.dm b/code/game/objects/items/weapons/grenades/emgrenade.dm index 9edf68a60ac..77ca1d65bea 100644 --- a/code/game/objects/items/weapons/grenades/emgrenade.dm +++ b/code/game/objects/items/weapons/grenades/emgrenade.dm @@ -4,9 +4,8 @@ item_state = "emp" origin_tech = "materials=2;magnets=3" - prime() - ..() - if(empulse(src, 4, 10)) - del(src) - return +/obj/item/weapon/grenade/empgrenade/prime() + update_mob() + empulse(src, 4, 10) + del(src) diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 2ff047a7465..36ea6b5521e 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -5,98 +5,97 @@ origin_tech = "materials=2;combat=1" var/banglet = 0 - prime() - ..() - for(var/obj/structure/closet/L in view(get_turf(src), null)) - if(locate(/mob/living/carbon/, L)) - for(var/mob/living/carbon/M in L) - bang(get_turf(src), M) +/obj/item/weapon/grenade/flashbang/prime() + update_mob() + for(var/obj/structure/closet/L in view(get_turf(src), null)) + if(locate(/mob/living/carbon/, L)) + for(var/mob/living/carbon/M in L) + bang(get_turf(src), M) - for(var/mob/living/carbon/M in viewers(get_turf(src), null)) - bang(get_turf(src), M) + for(var/mob/living/carbon/M in viewers(get_turf(src), null)) + bang(get_turf(src), M) - for(var/obj/effect/blob/B in view(8,get_turf(src))) //Blob damage here - var/damage = round(30/(get_dist(B,get_turf(src))+1)) - B.health -= damage - B.update_icon() - del(src) - return + for(var/obj/effect/blob/B in view(8,get_turf(src))) //Blob damage here + var/damage = round(30/(get_dist(B,get_turf(src))+1)) + B.health -= damage + B.update_icon() + del(src) - proc/bang(var/turf/T , var/mob/living/carbon/M) // Added a new proc called 'bang' that takes a location and a person to be banged. - if (locate(/obj/item/weapon/cloaking_device, M)) // Called during the loop that bangs people in lockers/containers and when banging - for(var/obj/item/weapon/cloaking_device/S in M) // people in normal view. Could theroetically be called during other explosions. - S.active = 0 // -- Polymorph - S.icon_state = "shield0" +/obj/item/weapon/grenade/flashbang/proc/bang(var/turf/T , var/mob/living/carbon/M) // Added a new proc called 'bang' that takes a location and a person to be banged. + if (locate(/obj/item/weapon/cloaking_device, M)) // Called during the loop that bangs people in lockers/containers and when banging + for(var/obj/item/weapon/cloaking_device/S in M) // people in normal view. Could theroetically be called during other explosions. + S.active = 0 // -- Polymorph + S.icon_state = "shield0" - M << "\red BANG" - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + M << "\red BANG" + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) //Checking for protections - var/eye_safety = 0 - var/ear_safety = 0 - if(iscarbon(M)) - eye_safety = M.eyecheck() - if(ishuman(M)) - if(istype(M:ears, /obj/item/clothing/ears/earmuffs)) - ear_safety += 2 - if(HULK in M.mutations) - ear_safety += 1 - if(istype(M:head, /obj/item/clothing/head/helmet)) - ear_safety += 1 + var/eye_safety = 0 + var/ear_safety = 0 + if(iscarbon(M)) + eye_safety = M.eyecheck() + if(ishuman(M)) + if(istype(M:ears, /obj/item/clothing/ears/earmuffs)) + ear_safety += 2 + if(HULK in M.mutations) + ear_safety += 1 + if(istype(M:head, /obj/item/clothing/head/helmet)) + ear_safety += 1 //Flashing everyone - if(eye_safety < 1) - flick("e_flash", M.flash) - M.eye_stat += rand(1, 3) - M.Stun(2) - M.Weaken(10) + if(eye_safety < 1) + flick("e_flash", M.flash) + M.eye_stat += rand(1, 3) + M.Stun(2) + M.Weaken(10) //Now applying sound - if((get_dist(M, T) <= 2 || src.loc == M.loc || src.loc == M)) - if(ear_safety > 0) - M.Stun(2) - M.Weaken(1) + if((get_dist(M, T) <= 2 || src.loc == M.loc || src.loc == M)) + if(ear_safety > 0) + M.Stun(2) + M.Weaken(1) + else + M.Stun(10) + M.Weaken(3) + if ((prob(14) || (M == src.loc && prob(70)))) + M.ear_damage += rand(1, 10) else - M.Stun(10) - M.Weaken(3) - if ((prob(14) || (M == src.loc && prob(70)))) - M.ear_damage += rand(1, 10) - else - M.ear_damage += rand(0, 5) - M.ear_deaf = max(M.ear_deaf,15) + M.ear_damage += rand(0, 5) + M.ear_deaf = max(M.ear_deaf,15) - else if(get_dist(M, T) <= 5) - if(!ear_safety) - M.Stun(8) - M.ear_damage += rand(0, 3) - M.ear_deaf = max(M.ear_deaf,10) + else if(get_dist(M, T) <= 5) + if(!ear_safety) + M.Stun(8) + M.ear_damage += rand(0, 3) + M.ear_deaf = max(M.ear_deaf,10) - else if(!ear_safety) - M.Stun(4) - M.ear_damage += rand(0, 1) - M.ear_deaf = max(M.ear_deaf,5) + else if(!ear_safety) + M.Stun(4) + M.ear_damage += rand(0, 1) + M.ear_deaf = max(M.ear_deaf,5) //This really should be in mob not every check - if (M.eye_stat >= 20) - M << "\red Your eyes start to burn badly!" - M.disabilities |= NEARSIGHTED - if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) - if (prob(M.eye_stat - 20 + 1)) - M << "\red You can't see anything!" - M.sdisabilities |= BLIND - if (M.ear_damage >= 15) - M << "\red Your ears start to ring badly!" - if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) - if (prob(M.ear_damage - 10 + 5)) - M << "\red You can't hear anything!" - M.sdisabilities |= DEAF - else - if (M.ear_damage >= 5) - M << "\red Your ears start to ring!" - M.update_icons() + if (M.eye_stat >= 20) + M << "\red Your eyes start to burn badly!" + M.disabilities |= NEARSIGHTED + if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) + if (prob(M.eye_stat - 20 + 1)) + M << "\red You can't see anything!" + M.sdisabilities |= BLIND + if (M.ear_damage >= 15) + M << "\red Your ears start to ring badly!" + if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) + if (prob(M.ear_damage - 10 + 5)) + M << "\red You can't hear anything!" + M.sdisabilities |= DEAF + else + if (M.ear_damage >= 5) + M << "\red Your ears start to ring!" + M.update_icons() /obj/item/weapon/grenade/flashbang/clusterbang//Created by Polymorph, fixed by Sieve @@ -106,6 +105,7 @@ icon_state = "clusterbang" /obj/item/weapon/grenade/flashbang/clusterbang/prime() + update_mob() var/numspawned = rand(4,8) var/again = 0 for(var/more = numspawned,more > 0,more--) @@ -124,7 +124,6 @@ playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) spawn(0) del(src) - return /obj/item/weapon/grenade/flashbang/clusterbang/segment desc = "A smaller segment of a clusterbang. Better run." @@ -135,7 +134,6 @@ /obj/item/weapon/grenade/flashbang/clusterbang/segment/New()//Segments should never exist except part of the clusterbang, since these immediately 'do their thing' and asplode icon_state = "clusterbang_segment_active" active = 1 - banglet = 1 var/stepdist = rand(1,4)//How far to step var/temploc = src.loc//Saves the current location to know where to step away from walk_away(src,temploc,stepdist)//I must go, my people need me @@ -145,6 +143,7 @@ ..() /obj/item/weapon/grenade/flashbang/clusterbang/segment/prime() + update_mob() var/numspawned = rand(4,8) for(var/more = numspawned,more > 0,more--) if(prob(35)) @@ -156,17 +155,15 @@ playsound(src.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) spawn(0) del(src) - return /obj/item/weapon/grenade/flashbang/cluster/New()//Same concept as the segments, so that all of the parts don't become reliant on the clusterbang - spawn(0) - icon_state = "flashbang_active" - active = 1 - banglet = 1 - var/stepdist = rand(1,3) - var/temploc = src.loc - walk_away(src,temploc,stepdist) - var/dettime = rand(15,60) - spawn(dettime) - prime() - ..() \ No newline at end of file + ..() + icon_state = "flashbang_active" + active = 1 + banglet = 1 + var/stepdist = rand(1,3) + var/temploc = src.loc + walk_away(src,temploc,stepdist) + var/dettime = rand(15,60) + spawn(dettime) + prime() \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index eeaf7ada8ca..7619df49775 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -69,18 +69,15 @@ var/mob/living/carbon/C = user C.throw_mode_on() spawn(det_time) - if(user) - user.drop_item() prime() - return - return /obj/item/weapon/grenade/proc/prime() -// playsound(loc, 'sound/items/Welder2.ogg', 25, 1) - var/turf/T = get_turf(src) - if(T) - T.hotspot_expose(700,125) + +/obj/item/weapon/grenade/proc/update_mob() + if(ismob(loc)) + var/mob/M = loc + M.drop_from_inventory(src) /obj/item/weapon/grenade/attackby(obj/item/weapon/W as obj, mob/user as mob) @@ -100,12 +97,10 @@ user << "You set the [name] for instant detonation." add_fingerprint(user) ..() - return /obj/item/weapon/grenade/attack_hand() walk(src, null, null) ..() - return /obj/item/weapon/grenade/attack_paw(mob/user as mob) return attack_hand(user) diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index ea6ab037bc4..da5c22b8177 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -9,27 +9,27 @@ slot_flags = SLOT_BELT var/datum/effect/effect/system/bad_smoke_spread/smoke - New() - ..() - src.smoke = new /datum/effect/effect/system/bad_smoke_spread - src.smoke.attach(src) +/obj/item/weapon/grenade/smokebomb/New() + ..() + src.smoke = new /datum/effect/effect/system/bad_smoke_spread + src.smoke.attach(src) - prime() - playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) - src.smoke.set_up(10, 0, usr.loc) - spawn(0) - src.smoke.start() - sleep(10) - src.smoke.start() - sleep(10) - src.smoke.start() - sleep(10) - src.smoke.start() +/obj/item/weapon/grenade/smokebomb/prime() + update_mob() + playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + src.smoke.set_up(10, 0, usr.loc) + spawn(0) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() + sleep(10) + src.smoke.start() - for(var/obj/effect/blob/B in view(8,src)) - var/damage = round(30/(get_dist(B,src)+1)) - B.health -= damage - B.update_icon() - sleep(80) - del(src) - return + for(var/obj/effect/blob/B in view(8,src)) + var/damage = round(30/(get_dist(B,src)+1)) + B.health -= damage + B.update_icon() + sleep(80) + del(src) diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index efb6ac1e755..9546c9c166b 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -9,27 +9,26 @@ var/spawner_type = null // must be an object path var/deliveryamt = 1 // amount of type to deliver - prime() // Prime now just handles the two loops that query for people in lockers and people who can see it. +/obj/item/weapon/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it. + update_mob() + if(spawner_type && deliveryamt) + // Make a quick flash + var/turf/T = get_turf(src) + playsound(T, 'sound/effects/phasein.ogg', 100, 1) + for(var/mob/living/carbon/human/M in viewers(T, null)) + if(M:eyecheck() <= 0) + flick("e_flash", M.flash) // flash dose faggots - if(spawner_type && deliveryamt) - // Make a quick flash - var/turf/T = get_turf(src) - playsound(T, 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(T, null)) - if(M:eyecheck() <= 0) - flick("e_flash", M.flash) // flash dose faggots + for(var/i=1, i<=deliveryamt, i++) + var/atom/movable/x = new spawner_type + x.loc = T + if(prob(50)) + for(var/j = 1, j <= rand(1, 3), j++) + step(x, pick(NORTH,SOUTH,EAST,WEST)) - for(var/i=1, i<=deliveryamt, i++) - var/atom/movable/x = new spawner_type - x.loc = T - if(prob(50)) - for(var/j = 1, j <= rand(1, 3), j++) - step(x, pick(NORTH,SOUTH,EAST,WEST)) + // Spawn some hostile syndicate critters - // Spawn some hostile syndicate critters - - del(src) - return + del(src) /obj/item/weapon/grenade/spawnergrenade/manhacks name = "manhack delivery grenade" diff --git a/code/game/objects/items/weapons/grenades/syndieminibomb.dm b/code/game/objects/items/weapons/grenades/syndieminibomb.dm index f6328964dfe..7dbb3431e62 100644 --- a/code/game/objects/items/weapons/grenades/syndieminibomb.dm +++ b/code/game/objects/items/weapons/grenades/syndieminibomb.dm @@ -6,8 +6,7 @@ item_state = "flashbang" origin_tech = "materials=3;magnets=4;syndicate=4" - prime() - explosion(src.loc,1,2,4) - del(src) - - return \ No newline at end of file +/obj/item/weapon/grenade/syndieminibomb/prime() + update_mob() + explosion(src.loc,1,2,4) + del(src) \ No newline at end of file diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index d98f79aa097..fd3f2e8c7f2 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -19,12 +19,13 @@ obj/item/weapon/mop/proc/clean(turf/simulated/A) + if(reagents.has_reagent("water", 1)) + A.clean_blood() + for(var/obj/effect/O in A) + if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) + del(O) reagents.reaction(A, TOUCH, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. reagents.remove_any(1) //reaction() doesn't use up the reagents - A.clean_blood() - for(var/obj/effect/O in A) - if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) - del(O) /obj/item/weapon/mop/afterattack(atom/A, mob/user) diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index a5874f09855..e51deddd3ce 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -174,11 +174,18 @@ /obj/item/weapon/storage/pill_bottle/dice - name = "pack of dice" - desc = "It's a small container with dice inside." + name = "bag of dice" + desc = "Contains all the luck you'll ever need." + icon = 'icons/obj/dice.dmi' + icon_state = "dicebag" New() ..() + new /obj/item/weapon/dice/d4( src ) new /obj/item/weapon/dice( src ) + new /obj/item/weapon/dice/d8( src ) + new /obj/item/weapon/dice/d10( src ) + new /obj/item/weapon/dice/d00( src ) + new /obj/item/weapon/dice/d12( src ) new /obj/item/weapon/dice/d20( src ) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 7b6042ae299..d03ab1a6d8d 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -218,7 +218,7 @@ return 0 if(!isturf(O.loc)) return 0 - if(user.restrained() || user.stat || user.weakened || user.stunned || user.paralysis) + if(user.restrained() || user.stat || user.weakened || user.stunned || user.paralysis || user.lying) return 0 if((!( istype(O, /atom/movable) ) || O.anchored || get_dist(user, src) > 1 || get_dist(user, O) > 1)) return 0 diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index ab3c89365cd..f123d0a9fa0 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -142,6 +142,9 @@ new /obj/item/clothing/under/rank/atmospheric_technician(src) new /obj/item/clothing/under/rank/atmospheric_technician(src) new /obj/item/clothing/under/rank/atmospheric_technician(src) + new /obj/item/device/analyzer(src) + new /obj/item/device/analyzer(src) + new /obj/item/device/analyzer(src) new /obj/item/clothing/shoes/black(src) new /obj/item/clothing/shoes/black(src) new /obj/item/clothing/shoes/black(src) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 5adf36e57e9..3801eafcd69 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -284,6 +284,9 @@ /obj/structure/table/attackby(obj/item/weapon/W, mob/user) if (istype(W, /obj/item/weapon/grab) && get_dist(src, user) < 2) var/obj/item/weapon/grab/G = W + if(G.affecting.buckled) + user << "[G.affecting] is buckled to [G.affecting.buckled]!" + return if(G.state < GRAB_AGGRESSIVE) user << "You need a better grip to do that!" return @@ -322,8 +325,7 @@ return user.drop_item(src) - //if(W && W.loc) W.loc = src.loc // Unnecessary - see: mob/proc/drop_item(atom) - Doohl - return + return 1 /* @@ -339,6 +341,9 @@ if (istype(W, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = W + if(G.affecting.buckled) + user << "[G.affecting] is buckled to [G.affecting.buckled]!" + return if(G.state < GRAB_AGGRESSIVE) user << "You need a better grip to do that!" return @@ -357,6 +362,7 @@ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) del(src) return + if(isrobot(user)) return if(istype(W, /obj/item/weapon/melee/energy/blade)) @@ -373,7 +379,7 @@ user.drop_item(src) //if(W && W.loc) W.loc = src.loc - return + return 1 /* @@ -390,6 +396,9 @@ if (istype(W, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = W + if(G.affecting.buckled) + user << "[G.affecting] is buckled to [G.affecting.buckled]!" + return if(G.state < GRAB_AGGRESSIVE) user << "You need a better grip to do that!" return @@ -451,7 +460,7 @@ user.drop_item(src) //if(W && W.loc) W.loc = src.loc - return + return 1 /* @@ -514,11 +523,12 @@ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) del(src) return + if(isrobot(user)) return user.drop_item() if(W && W.loc) W.loc = src.loc - return + return 1 /obj/structure/rack/meteorhit(obj/O as obj) del(src) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 5fa32b1e03a..61e863bd604 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -98,6 +98,8 @@ /obj/structure/window/attack_hand(mob/user as mob) + if(!can_be_reached(user)) + return if(HULK in user.mutations) user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) user.visible_message("[user] smashes through [src]!") @@ -114,6 +116,8 @@ /obj/structure/window/proc/attack_generic(mob/user as mob, damage = 0) //used by attack_alien, attack_animal, and attack_slime + if(!can_be_reached(user)) + return health -= damage if(health <= 0) user.visible_message("[user] smashes through [src]!") @@ -142,6 +146,8 @@ /obj/structure/window/attackby(obj/item/I, mob/user) + if(!can_be_reached(user)) + return 1 //returning 1 will skip the afterattack() if(istype(I, /obj/item/weapon/screwdriver)) if(reinf && state >= 1) state = 3 - state @@ -173,6 +179,14 @@ ..() return +/obj/structure/window/proc/can_be_reached(mob/user) + if(!is_fulltile()) + if(get_dir(user,src) & dir) + for(var/obj/O in loc) + if(!O.CanPass(user, user.loc, 1, 0)) + return 0 + return 1 + /obj/structure/window/proc/hit(var/damage, var/sound_effect = 1) if(reinf) damage *= 0.5 health = max(0, health - damage) diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 275d35e4da1..d2498752e81 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -530,4 +530,4 @@ turf/simulated/floor/proc/update_icon() burnt = 0 broken = 0 else - user << "\blue You need more welding fuel to complete this task." \ No newline at end of file + user << "\blue You need more welding fuel to complete this task." diff --git a/code/global.dm b/code/global.dm index 0b5af7d9149..e75a8d4e468 100644 --- a/code/global.dm +++ b/code/global.dm @@ -134,15 +134,6 @@ var/shuttlecoming = 0 var/join_motd = null var/forceblob = 0 - //airlockWireColorToIndex takes a number representing the wire color, e.g. the orange wire is always 1, the dark red wire is always 2, etc. It returns the index for whatever that wire does. - //airlockIndexToWireColor does the opposite thing - it takes the index for what the wire does, for example AIRLOCK_WIRE_IDSCAN is 1, AIRLOCK_WIRE_POWER1 is 2, etc. It returns the wire color number. - //airlockWireColorToFlag takes the wire color number and returns the flag for it (1, 2, 4, 8, 16, etc) - -var/list/AAlarmWireColorToFlag = RandomAAlarmWires() -var/list/AAlarmIndexToFlag -var/list/AAlarmIndexToWireColor -var/list/AAlarmWireColorToIndex - //This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage var/MAX_EX_DEVESTATION_RANGE = 3 var/MAX_EX_HEAVY_RANGE = 7 diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index e154b5b8f09..860766ddeb4 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -1,6 +1,7 @@ #define MAX_ADMIN_BANS_PER_ADMIN 1 -datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null) +//Either pass the mob you wish to ban in the 'banned_mob' attribute, or the banckey, banip and bancid variables. If both are passed, the mob takes priority! If a mob is not passed, banckey is the minimum that needs to be passed! banip and bancid are optional. +datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) if(!check_rights(R_BAN)) return @@ -71,6 +72,8 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = ip = banned_mob.lastKnownIP else if(banckey) ckey = ckey(banckey) + computerid = bancid + ip = banip var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'") query.Execute() @@ -353,6 +356,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" output += "" output += "
" + output += "" + output += "" output += "" output += "
- Changling Evolution Menu
+ Changeling Evolution Menu
Hover over a power to see more information
- Current evolution points left to evolve with: [geneticpoints]
- Absorb genomes to acquire more evolution points + Current ability choices remaining: [geneticpoints]
+ By rendering a lifeform to a husk, we gain enough power to alter and adapt our evolutions.
+ (Readapt)

Ckey:
IP: Computer id:
Duration: Job: