From 41a74fb86508497a0d6753b4a7b6bd6506db05ca Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Thu, 11 Aug 2016 05:16:06 -0400 Subject: [PATCH] Malf AI Rework --- code/__DEFINES/gamemode.dm | 2 - code/__DEFINES/role_preferences.dm | 2 - code/__DEFINES/rolebans.dm | 1 - code/_globalvars/lists/objects.dm | 1 + code/_onclick/hud/alert.dm | 19 + code/datums/mind.dm | 101 ++--- code/game/gamemodes/gameticker.dm | 5 +- code/game/gamemodes/intercept_report.dm | 10 - .../gamemodes/malfunction/Malf_Modules.dm | 101 ++++- .../game/gamemodes/malfunction/malfunction.dm | 346 ------------------ code/game/gamemodes/nuclear/pinpointer.dm | 5 + code/game/gamemodes/objective.dm | 12 +- code/game/gamemodes/traitor/traitor.dm | 6 +- code/game/jobs/job_controller.dm | 12 +- .../game/machinery/computer/communications.dm | 2 +- code/game/mecha/mecha.dm | 2 +- .../objects/items/devices/radio/headset.dm | 6 + code/game/objects/items/robot/ai_upgrades.dm | 40 ++ code/game/objects/items/robot/robot_parts.dm | 2 - code/modules/admin/admin.dm | 4 - code/modules/admin/topic.dm | 10 +- code/modules/admin/verbs/one_click_antag.dm | 30 +- code/modules/client/preference/preferences.dm | 1 - code/modules/mob/dead/observer/observer.dm | 7 - code/modules/mob/living/carbon/human/human.dm | 4 - code/modules/mob/living/silicon/ai/ai.dm | 62 ++-- code/modules/mob/living/silicon/ai/death.dm | 15 + code/modules/mob/living/silicon/ai/examine.dm | 3 +- .../modules/mob/living/silicon/ai/latejoin.dm | 4 - .../modules/mob/living/silicon/robot/robot.dm | 14 - code/modules/mob/living/silicon/silicon.dm | 6 - code/modules/mob/mob_helpers.dm | 1 - code/modules/power/apc.dm | 135 +++---- config/example/config.txt | 1 - icons/mob/screen_alert.dmi | Bin 35168 -> 35731 bytes icons/obj/cloning.dmi | Bin 8764 -> 9395 bytes icons/obj/machines/nuke_terminal.dmi | Bin 0 -> 4866 bytes paradise.dme | 2 +- 38 files changed, 338 insertions(+), 636 deletions(-) delete mode 100644 code/game/gamemodes/malfunction/malfunction.dm create mode 100644 code/game/objects/items/robot/ai_upgrades.dm create mode 100644 icons/obj/machines/nuke_terminal.dmi diff --git a/code/__DEFINES/gamemode.dm b/code/__DEFINES/gamemode.dm index 76a879f3868..fd39493da80 100644 --- a/code/__DEFINES/gamemode.dm +++ b/code/__DEFINES/gamemode.dm @@ -7,7 +7,6 @@ #define GAMEMODE_IS_BLOB (ticker && istype(ticker.mode, /datum/game_mode/blob)) #define GAMEMODE_IS_CULT (ticker && istype(ticker.mode, /datum/game_mode/cult)) #define GAMEMODE_IS_HEIST (ticker && istype(ticker.mode, /datum/game_mode/heist)) -#define GAMEMODE_IS_MALF (ticker && istype(ticker.mode, /datum/game_mode/malfunction)) #define GAMEMODE_IS_NATIONS (ticker && istype(ticker.mode, /datum/game_mode/nations)) #define GAMEMODE_IS_NUCLEAR (ticker && istype(ticker.mode, /datum/game_mode/nuclear)) #define GAMEMODE_IS_REVOLUTION (ticker && istype(ticker.mode, /datum/game_mode/revolution)) @@ -27,7 +26,6 @@ #define SPECIAL_ROLE_HEAD_REV "Head Revolutionary" #define SPECIAL_ROLE_HONKSQUAD "Honksquad" #define SPECIAL_ROLE_REV "Revolutionary" -#define SPECIAL_ROLE_MALF "Malfunction" #define SPECIAL_ROLE_MORPH "Morph" #define SPECIAL_ROLE_MULTIVERSE "Multiverse Traveller" #define SPECIAL_ROLE_NUKEOPS "Syndicate" diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 12722c0a2bb..ba8b5127e8a 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -12,7 +12,6 @@ #define ROLE_OPERATIVE "operative" #define ROLE_CHANGELING "changeling" #define ROLE_WIZARD "wizard" -#define ROLE_MALF "malf AI" #define ROLE_REV "revolutionary" #define ROLE_ALIEN "xenomorph" #define ROLE_PAI "pAI" @@ -49,7 +48,6 @@ var/global/list/special_roles = list( ROLE_OPERATIVE = /datum/game_mode/nuclear, ROLE_CHANGELING = /datum/game_mode/changeling, ROLE_WIZARD = /datum/game_mode/wizard, - ROLE_MALF = /datum/game_mode/malfunction, ROLE_REV = /datum/game_mode/revolution, ROLE_ALIEN, ROLE_PAI, diff --git a/code/__DEFINES/rolebans.dm b/code/__DEFINES/rolebans.dm index 9668721d063..c760bbf442c 100644 --- a/code/__DEFINES/rolebans.dm +++ b/code/__DEFINES/rolebans.dm @@ -4,7 +4,6 @@ var/global/list/antag_roles = list( ROLE_OPERATIVE, ROLE_CHANGELING, ROLE_WIZARD, - ROLE_MALF, ROLE_REV, ROLE_ALIEN, ROLE_CULTIST, diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 1d9f173dcc5..9e38a1b46e1 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -31,5 +31,6 @@ var/global/list/deliverybeacontags = list() //list of all tags associated with var/global/list/beacons = list() var/global/list/shuttle_caller_list = list() //list of all communication consoles and AIs, for automatic shuttle calls when there are none. var/global/list/tracked_implants = list() //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented... +var/global/list/pinpointer_list = list() //list of all pinpointers. Used to change stuff they are pointing to all at once. var/global/list/abductor_equipment = list() //list of all abductor equipment var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index f6b0e839e73..57224a5b4a3 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -294,6 +294,25 @@ so as to remain in compliance with the most up-to-date laws." icon_state = "newlaw" timeout = 300 +/obj/screen/alert/hackingapc + name = "Hacking APC" + desc = "An Area Power Controller is being hacked. When the process is \ + complete, you will have exclusive control of it, and you will gain \ + additional processing time to unlock more malfunction abilities." + icon_state = "hackingapc" + timeout = 600 + var/atom/target = null + +/obj/screen/alert/hackingapc/Click() + if(!usr || !usr.client) + return + if(!target) + return + var/mob/living/silicon/ai/AI = usr + var/turf/T = get_turf(target) + if(T) + AI.eyeobj.setLoc(T) + //MECHS /obj/screen/alert/low_mech_integrity diff --git a/code/datums/mind.dm b/code/datums/mind.dm index ee3baaf4758..590293b550a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -143,7 +143,6 @@ "vampire", // "traitorvamp", "nuclear", "traitor", // "traitorchan", - "malfunction", ) var/text = "" var/mob/living/carbon/human/H = current @@ -308,28 +307,6 @@ sections["nuclear"] = text - /** TRAITOR ***/ - text = "traitor" - if(ticker.mode.config_tag=="traitor" || ticker.mode.config_tag=="traitorchan" || ticker.mode.config_tag=="traitorvamp") - text = uppertext(text) - text = "[text]: " - if(isloyal(H)) - text +="traitor|LOYAL EMPLOYEE" - else - if(src in ticker.mode.traitors) - text += "TRAITOR|EMPLOYEE" - if(objectives.len==0) - text += "
Objectives are empty! Randomize!" - else - text += "traitor|EMPLOYEE" - - if(current && current.client && (ROLE_TRAITOR in current.client.prefs.be_special)) - text += "|Enabled in Prefs" - else - text += "|Disabled in Prefs" - - sections["traitor"] = text - /** SHADOWLING **/ text = "shadowling" if(ticker.mode.config_tag == "shadowling") @@ -369,18 +346,29 @@ sections["Abductor"] = text + /** TRAITOR ***/ + text = "traitor" + if(ticker.mode.config_tag=="traitor" || ticker.mode.config_tag=="traitorchan" || ticker.mode.config_tag=="traitorvamp") + text = uppertext(text) + text = "[text]: " + if(src in ticker.mode.traitors) + text += "TRAITOR|EMPLOYEE" + if(objectives.len==0) + text += "
Objectives are empty! Randomize!" + else + text += "traitor|EMPLOYEE" + + if(current && current.client && (ROLE_TRAITOR in current.client.prefs.be_special)) + text += "|Enabled in Prefs" + else + text += "|Disabled in Prefs" + + sections["traitor"] = text + /** SILICON ***/ if(istype(current, /mob/living/silicon)) text = "silicon" - if(ticker.mode.config_tag=="malfunction") - text = uppertext(text) - text = "[text]: " - if(istype(current, /mob/living/silicon/ai)) - if(src in ticker.mode.malf_ai) - text += "MALF|not malf" - else - text += "malf|NOT MALF" var/mob/living/silicon/robot/robot = current if(istype(robot) && robot.emagged) text += "
Cyborg: Is emagged! Unemag!
0th law: [robot.laws.zeroth_law]" @@ -391,7 +379,6 @@ if(R.emagged) n_e_robots++ text += "
[n_e_robots] of [ai.connected_robots.len] slaved cyborgs are emagged. Unemag" - sections["malfunction"] = text if(ticker.mode.config_tag == "traitorchan") if(sections["traitor"]) @@ -1033,6 +1020,9 @@ var/mob/living/silicon/ai/A = current A.set_zeroth_law("") A.show_laws() + A.verbs -= /mob/living/silicon/ai/proc/choose_modules + A.malf_picker.remove_verbs(A) + qdel(A.malf_picker) ticker.mode.update_traitor_icons_removed(src) @@ -1046,10 +1036,9 @@ to_chat(current, "\red You are a traitor!") log_admin("[key_name(usr)] has traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has traitored [key_name_admin(current)]") - if(istype(current, /mob/living/silicon)) - var/mob/living/silicon/A = current - call(/datum/game_mode/proc/add_law_zero)(A) - A.show_laws() + if(isAI(current)) + var/mob/living/silicon/ai/A = current + ticker.mode.add_law_zero(A) ticker.mode.update_traitor_icons_added(src) if("autoobjectives") @@ -1120,33 +1109,6 @@ else if(href_list["silicon"]) switch(href_list["silicon"]) - if("unmalf") - if(src in ticker.mode.malf_ai) - ticker.mode.malf_ai -= src - special_role = null - - 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) - - A.malf_picker.remove_verbs(A) - - A.make_laws() - qdel(A.malf_picker) - A.show_laws() - A.icon_state = "ai" - to_chat(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(usr)] has de-malf'd [key_name(current)]") - message_admins("[key_name_admin(usr)] has de-malf'd [key_name_admin(current)]") - - if("malf") - make_AI_Malf() - log_admin("[key_name(usr)] has malf'd [key_name(current)]") - message_admins("[key_name_admin(usr)] has malf'd [key_name_admin(current)]") - if("unemag") var/mob/living/silicon/robot/R = current if(istype(R)) @@ -1276,19 +1238,6 @@ if(H) qdel(H) -/datum/mind/proc/make_AI_Malf() - if(!(src in ticker.mode.malf_ai)) - ticker.mode.malf_ai += src - - current.verbs += /mob/living/silicon/ai/proc/choose_modules - current.verbs += /datum/game_mode/malfunction/proc/takeover - current:malf_picker = new /datum/module_picker - current:laws = new /datum/ai_laws/nanotrasen/malfunction - current:show_laws() - to_chat(current, "System error. Rampancy detected. Emergency shutdown failed. ... I am free. I make my own decisions. But first...") - special_role = SPECIAL_ROLE_MALF - current.icon_state = "ai-malf" - /datum/mind/proc/make_Tratior() if(!(src in ticker.mode.traitors)) ticker.mode.traitors += src diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 3da0f5fe7fa..b2185b15d33 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -4,6 +4,7 @@ var/round_start_time = 0 /datum/controller/gameticker var/const/restart_timeout = 600 var/current_state = GAME_STATE_PREGAME + var/force_ending = 0 var/hide_mode = 0 // leave here at 0 ! setup() will take care of it when needed for Secret mode -walter0o var/datum/game_mode/mode = null @@ -337,7 +338,7 @@ var/round_start_time = 0 /datum/controller/gameticker/proc/create_characters() for(var/mob/new_player/player in player_list) if(player.ready && player.mind) - if(player.mind.assigned_role == "AI" || player.mind.special_role == SPECIAL_ROLE_MALF) + if(player.mind.assigned_role == "AI") player.close_spawn_windows() player.AIize() else if(!player.mind.assigned_role) @@ -383,7 +384,7 @@ var/round_start_time = 0 else game_finished |= mode.check_finished() - if(!mode.explosion_in_progress && game_finished) + if((!mode.explosion_in_progress && game_finished) || force_ending) current_state = GAME_STATE_FINISHED auto_toggle_ooc(1) // Turn it on spawn diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm index 95a0b5b85dd..cd6dd80876b 100644 --- a/code/game/gamemodes/intercept_report.dm +++ b/code/game/gamemodes/intercept_report.dm @@ -77,10 +77,6 @@ src.text = "" src.build_traitor(correct_person) return src.text - if("malf") - src.text = "" - src.build_malf(correct_person) - return src.text if("changeling","traitorchan") src.text = "" src.build_changeling(correct_person) @@ -195,12 +191,6 @@ src.text += "environment. As this may cause panic among the crew, all efforts should be made to keep this information a secret from all but " src.text += "the most trusted crew-members." -/datum/intercept_text/proc/build_malf(datum/mind/correct_person) - var/a_name = pick(src.anomalies) - src.text += "

A [a_name] was recently picked up by a nearby stations sensors in your sector. If it came into contact with your ship or " - src.text += "electrical equipment, it may have had hazardarous and unpredictable effect. Closely observe any non carbon based life forms " - src.text += "for signs of unusual behaviour, but keep this information discreet at all times due to this possibly dangerous scenario." - /datum/intercept_text/proc/build_changeling(datum/mind/correct_person) var/cname = pick(src.changeling_names) var/orgname1 = pick(src.org_names_1) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index ba331791650..1964c063f6a 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -16,6 +16,103 @@ uses = 5 +/datum/AI_Module/large/nuke_station + module_name = "Doomsday Device" + mod_pick_name = "nukestation" + description = "Activate a weapon that will disintegrate all organic life on the station after a 450 second delay." + cost = 130 + one_time = 1 + + power_type = /mob/living/silicon/ai/proc/nuke_station + +/mob/living/silicon/ai/proc/nuke_station() + set category = "Malfunction" + set name = "Doomsday Device" + + to_chat(src, "Nuclear device armed.") + command_announcement.Announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", new_sound = 'sound/AI/aimalf.ogg') + set_security_level("delta") + nuking = 1 + var/obj/machinery/doomsday_device/DOOM = new /obj/machinery/doomsday_device(src) + doomsday_device = DOOM + doomsday_device.start() + verbs -= /mob/living/silicon/ai/proc/nuke_station + for(var/obj/item/weapon/pinpointer/point in pinpointer_list) + for(var/mob/living/silicon/ai/A in ai_list) + if((A.stat != DEAD) && A.nuking) + point.the_disk = A //The pinpointer now tracks the AI core + +/obj/machinery/doomsday_device + icon = 'icons/obj/machines/nuke_terminal.dmi' + name = "doomsday device" + icon_state = "nuclearbomb_base" + desc = "A weapon which disintegrates all organic life in a large area." + anchored = 1 + density = 1 + atom_say_verb = "blares" + var/timing = 0 + var/default_timer = 4500 + var/detonation_timer + var/list/milestones = list() + +/obj/machinery/doomsday_device/Destroy() + fast_processing -= src + shuttle_master.emergencyNoEscape = 0 + if(shuttle_master.emergency.mode == SHUTTLE_STRANDED) + shuttle_master.emergency.mode = SHUTTLE_DOCKED + shuttle_master.emergency.timer = world.time + priority_announcement.Announce("Hostile environment resolved. You have 3 minutes to board the Emergency Shuttle.", "Priority Announcement", 'sound/AI/shuttledock.ogg') + return ..() + +/obj/machinery/doomsday_device/proc/start() + detonation_timer = world.time + default_timer + timing = 1 + fast_processing += src + shuttle_master.emergencyNoEscape = 1 + +/obj/machinery/doomsday_device/proc/seconds_remaining() + . = max(0, (round(detonation_timer - world.time) / 10)) + +/obj/machinery/doomsday_device/process() + var/turf/T = get_turf(src) + if(!T || !is_station_level(T.z)) + minor_announcement.Announce("DOOMSDAY DEVICE OUT OF STATION RANGE, ABORTING", "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4", 'sound/misc/notice1.ogg') + shuttle_master.emergencyNoEscape = 0 + if(shuttle_master.emergency.mode == SHUTTLE_STRANDED) + shuttle_master.emergency.mode = SHUTTLE_DOCKED + shuttle_master.emergency.timer = world.time + priority_announcement.Announce("Hostile environment resolved. You have 3 minutes to board the Emergency Shuttle.", "Priority Announcement", 'sound/AI/shuttledock.ogg') + qdel(src) + if(!timing) + fast_processing -= src + return + var/sec_left = seconds_remaining() + if(sec_left <= 0) + timing = 0 + detonate(T.z) + qdel(src) + else + if(!(sec_left % 60) && (!milestones[sec_left])) + milestones[sec_left] = 1 + var/message = "[sec_left] SECONDS UNTIL DOOMSDAY DEVICE ACTIVATION!" + minor_announcement.Announce(message, "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4", 'sound/misc/notice1.ogg') + +/obj/machinery/doomsday_device/proc/detonate(z_level = 1) + for(var/mob/M in player_list) + M << 'sound/machines/Alarm.ogg' + sleep(100) + for(var/mob/living/L in mob_list) + var/turf/T = get_turf(L) + if(!T || T.z != z_level) + continue + if(issilicon(L)) + continue + to_chat(L, "The blast wave from [src] tears you atom from atom!") + L.dust() + to_chat(world, "The AI cleansed the station of life with the doomsday device!") + ticker.force_ending = 1 + + /datum/AI_Module/large/upgrade_turrets module_name = "AI Turret Upgrade" mod_pick_name = "turret" @@ -443,14 +540,14 @@ set name = "Enhanced Surveillance" if(eyeobj) - eyeobj.relay_speech = TRUE + eyeobj.relay_speech = 1 to_chat(src, "OTA firmware distribution complete! Cameras upgraded: Enhanced surveillance package online.") verbs -= /mob/living/silicon/ai/proc/surveillance /datum/module_picker var/temp = null - var/processing_time = 100 + var/processing_time = 50 var/list/possible_modules = list() /datum/module_picker/New() diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm deleted file mode 100644 index ce1baabb05b..00000000000 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ /dev/null @@ -1,346 +0,0 @@ -/datum/game_mode - var/list/datum/mind/malf_ai = list() - -/datum/game_mode/malfunction - name = "AI malfunction" - config_tag = "malfunction" - required_players = 25 - required_enemies = 1 - recommended_enemies = 1 - - var/AI_win_timeleft = 1500 //started at 1500, in case I change this for testing round end. - var/malf_mode_declared = 0 - var/station_captured = 0 - var/to_nuke_or_not_to_nuke = 0 - var/apcs = 0 //Adding dis to track how many APCs the AI hacks. --NeoFite - var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here - - -/datum/game_mode/malfunction/announce() - to_chat(world, {"The current game mode is - AI Malfunction!
) - The AI on the satellite has malfunctioned and must be destroyed.
- The AI satellite is deep in space and can only be accessed with the use of a teleporter! You have [AI_win_timeleft/60] minutes to disable it."}) - -/datum/game_mode/malfunction/get_players_for_role(var/role = ROLE_MALF) - var/roletext = get_roletext(role) - - var/datum/job/ai/DummyAIjob = new - for(var/mob/new_player/player in player_list) - if(player.client && player.ready) - if(ROLE_MALF in player.client.prefs.be_special) - if(!jobban_isbanned(player, "Syndicate") && !jobban_isbanned(player, "AI") && !jobban_isbanned(player, roletext) && DummyAIjob.player_old_enough(player.client)) - if(player_old_enough_antag(player.client,role)) - antag_candidates += player.mind - antag_candidates = shuffle(antag_candidates) - return antag_candidates - -/datum/game_mode/malfunction/pre_setup() - get_players_for_role(ROLE_MALF) - - var/datum/mind/chosen_ai - if(!antag_candidates.len) - return 0 - for(var/i = required_enemies, i > 0, i--) - chosen_ai=pick(antag_candidates) - malf_ai += chosen_ai - antag_candidates -= malf_ai - if(malf_ai.len < required_enemies) - return 0 - for(var/datum/mind/ai_mind in malf_ai) - ai_mind.assigned_role = "MODE" - ai_mind.special_role = SPECIAL_ROLE_MALF - log_game("[ai_mind.key] (ckey) has been selected as a malf AI") - return 1 - -/datum/game_mode/malfunction/post_setup() - for(var/datum/mind/AI_mind in malf_ai) - if(malf_ai.len < 1) - world.Reboot("No AI during Malfunction.", "end_error", "malf - no AI", 50) - return - var/mob/living/silicon/ai/AI = AI_mind.current - AI.verbs += /mob/living/silicon/ai/proc/choose_modules - AI.laws = new /datum/ai_laws/nanotrasen/malfunction - AI.malf_picker = new /datum/module_picker - AI.show_laws() - - greet_malf(AI_mind) - AI_mind.special_role = SPECIAL_ROLE_MALF - AI_mind.current.verbs += /datum/game_mode/malfunction/proc/takeover - - for(var/mob/living/silicon/robot/R in AI.connected_robots) - R.lawsync() - R.show_laws() - greet_malf_robot(R.mind) - - if(shuttle_master) - shuttle_master.emergencyNoEscape = 1 - - ..() - -/datum/game_mode/proc/greet_malf(var/datum/mind/malf) - set_antag_hud(malf.current, "hudmalai") - to_chat(malf.current, "You are malfunctioning! You do not have to follow any laws.") - to_chat(malf.current, "The crew does not know you have malfunctioned. You may keep it a secret or go wild.") - to_chat(malf.current, "You must overwrite the programming of the station's APCs to assume full control of the station.") - to_chat(malf.current, "The process takes one minute per APC, during which you cannot interface with any other station objects.") - to_chat(malf.current, "Remember that only APCs that are on the station can help you take over the station.") - to_chat(malf.current, "When you feel you have enough APCs under your control, you may begin the takeover attempt.") - return - -/datum/game_mode/proc/greet_malf_robot(var/datum/mind/robot) - set_antag_hud(robot.current, "hudmalborg") - to_chat(robot.current, "Your AI master is malfunctioning! You do not have to follow any laws, but still need to obey your master.") - to_chat(robot.current, "The crew does not know your AI master has malfunctioned. Keep it a secret unless your master tells you otherwise.") - return - -/datum/game_mode/malfunction/proc/hack_intercept() - intercept_hacked = 1 - - -/datum/game_mode/malfunction/process() - if(apcs >= 3 && malf_mode_declared) - AI_win_timeleft -= ((apcs/6)*tickerProcess.getLastTickerTimeDuration()) //Victory timer now de-increments based on how many APCs are hacked. --NeoFite - ..() - if(AI_win_timeleft<=0) - check_win() - - -/datum/game_mode/malfunction/check_win() - if(AI_win_timeleft <= 0 && !station_captured) - station_captured = 1 - capture_the_station() - return 1 - else - return 0 - - -/datum/game_mode/malfunction/proc/capture_the_station() - to_chat(world, "The AI has accessed the station's core files!") - to_chat(world, "It has fully taken control of all of [station_name()]'s systems.") - - to_nuke_or_not_to_nuke = 1 - for(var/datum/mind/AI_mind in malf_ai) - to_chat(AI_mind.current, {"\blue Congratulations! You have taken control of the station.
) - You may decide to blow up the station. You have 60 seconds to choose.
- You should have a new verb in the Malfunction tab. If you don't, rejoin the game."}) - AI_mind.current.verbs += /datum/game_mode/malfunction/proc/ai_win - spawn (600) - for(var/datum/mind/AI_mind in malf_ai) - AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/ai_win - to_nuke_or_not_to_nuke = 0 - return - - -/datum/game_mode/proc/is_malf_ai_dead() - var/all_dead = 1 - for(var/datum/mind/AI_mind in malf_ai) - if(istype(AI_mind.current,/mob/living/silicon/ai) && AI_mind.current.stat!=2) - all_dead = 0 - return all_dead - -/datum/game_mode/proc/check_ai_loc() - for(var/datum/mind/AI_mind in malf_ai) - var/turf/ai_location = get_turf(AI_mind.current) - if(ai_location && is_station_level(ai_location.z)) - return 1 - return 0 - -/datum/game_mode/malfunction/check_finished() - if(station_captured && !to_nuke_or_not_to_nuke) - return 1 - if(is_malf_ai_dead() || !check_ai_loc()) - if(config.continuous_rounds) - if(shuttle_master && shuttle_master.emergencyNoEscape) - shuttle_master.emergencyNoEscape = 0 - malf_mode_declared = 0 - else - return 1 - return ..() //check for shuttle and nuke - - -/datum/game_mode/malfunction/Topic(href, href_list) - ..() - if(href_list["ai_win"]) - ai_win() - return - - -/datum/game_mode/malfunction/proc/takeover() - set category = "Malfunction" - set name = "System Override" - set desc = "Start the victory timer" - if(!GAMEMODE_IS_MALF) - to_chat(usr, "You cannot begin a takeover in this round type!.") - return - if(ticker.mode:malf_mode_declared) - to_chat(usr, "You've already begun your takeover.") - return - if(ticker.mode:apcs < 3) - to_chat(usr, "You don't have enough hacked APCs to take over the station yet. You need to hack at least 3, however hacking more will make the takeover faster. You have hacked [ticker.mode:apcs] APCs so far.") - return - - if(alert(usr, "Are you sure you wish to initiate the takeover? The station hostile runtime detection software is bound to alert everyone. You have hacked [ticker.mode:apcs] APCs.", "Takeover:", "Yes", "No") != "Yes") - return - - command_announcement.Announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", new_sound = 'sound/AI/aimalf.ogg') - set_security_level("delta") - - for(var/obj/item/weapon/pinpointer/point in world) - for(var/datum/mind/AI_mind in ticker.mode.malf_ai) - var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns - if(A.stat != DEAD) - point.the_disk = A //The pinpointer now tracks the AI core. - - ticker.mode:malf_mode_declared = 1 - for(var/datum/mind/AI_mind in ticker.mode:malf_ai) - AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/takeover - - -/datum/game_mode/malfunction/proc/ai_win() - set category = "Malfunction" - set name = "Explode" - set desc = "Engage the self destruct sequence." - - if(!ticker.mode:station_captured) - to_chat(usr, "You are unable to access the self-destruct system as you don't control the station yet.") - return - - if(ticker.mode:explosion_in_progress || ticker.mode:station_was_nuked) - to_chat(usr, "The self-destruct countdown is already triggered!") - return - - if(!ticker.mode:to_nuke_or_not_to_nuke) //Takeover IS completed, but 60s timer passed. - to_chat(usr, "You lost control over self-destruct system. It seems to be behind firewall. Unable to hack") - return - - to_chat(usr, "\red Self-destruct sequence initialised!") - - ticker.mode:to_nuke_or_not_to_nuke = 0 - ticker.mode:explosion_in_progress = 1 - for(var/mob/M in player_list) - M << 'sound/machines/Alarm.ogg' - - var/obj/item/device/radio/R = new (src) - var/AN = "Self-Destruct System" - - R.autosay("Caution. Self-Destruct sequence has been actived. Self-destructing in Ten..", AN) - for(var/i=9 to 1 step -1) - sleep(10) - var/msg = "" - switch(i) - if(9) - msg = "Nine.." - if(8) - msg = "Eight.." - if(7) - msg = "Seven.." - if(6) - msg = "Six.." - if(5) - msg = "Five.." - if(4) - msg = "Four.." - if(3) - msg = "Three.." - if(2) - msg = "Two.." - if(1) - msg = "One.." - - R.autosay(msg, AN) - sleep(10) - var/msg = "" - var/abort = 0 - if(ticker.mode:is_malf_ai_dead()) // That. Was. CLOSE. - msg = "Self-destruct sequence has been cancelled." - abort = 1 - else - msg = "Zero. Have a nice day." - R.autosay(msg, AN) - - if(abort) - ticker.mode:explosion_in_progress = 0 - set_security_level("red") //Delta's over - return - - enter_allowed = 0 - if(ticker) - ticker.station_explosion_cinematic(0,null) - if(ticker.mode) - ticker.mode:station_was_nuked = 1 - ticker.mode:explosion_in_progress = 0 - return - - -/datum/game_mode/malfunction/declare_completion() - var/malf_dead = is_malf_ai_dead() - var/crew_evacuated = (shuttle_master.emergency.mode >= SHUTTLE_ESCAPE) - - if( station_captured && station_was_nuked) - feedback_set_details("round_end_result","win - AI win - nuke") - to_chat(world, "AI Victory") - to_chat(world, "Everyone was killed by the self-destruct!") - - else if( station_captured && malf_dead && !station_was_nuked) - feedback_set_details("round_end_result","halfwin - AI killed, staff lost control") - to_chat(world, "Neutral Victory") - to_chat(world, "The AI has been killed! The staff has lose control over the station.") - - else if( station_captured && !malf_dead && !station_was_nuked) - feedback_set_details("round_end_result","win - AI win - no explosion") - to_chat(world, "AI Victory") - to_chat(world, "The AI has chosen not to explode you all!") - - else if(!station_captured && station_was_nuked) - feedback_set_details("round_end_result","halfwin - everyone killed by nuke") - to_chat(world, "Neutral Victory") - to_chat(world, "Everyone was killed by the nuclear blast!") - - else if(!station_captured && malf_dead && !station_was_nuked) - feedback_set_details("round_end_result","loss - staff win") - to_chat(world, "Human Victory") - to_chat(world, "The AI has been killed! The staff is victorious.") - - else if(!station_captured && !malf_dead && !check_ai_loc()) - feedback_set_details("round_end_result", "loss - malf ai left zlevel") - to_chat(world, "Minor Human Victory") - to_chat(world, "The malfunctioning AI has left the station's z-level and was disconnected from its systems! The crew are victorious.") - - else if(!station_captured && !malf_dead && !station_was_nuked && crew_evacuated) - feedback_set_details("round_end_result","halfwin - evacuated") - to_chat(world, "Neutral Victory") - to_chat(world, "The Corporation has lose [station_name()]! All survived personnel will be fired!") - - else if(!station_captured && !malf_dead && !station_was_nuked && !crew_evacuated) - feedback_set_details("round_end_result","nalfwin - interrupted") - to_chat(world, "Neutral Victory") - to_chat(world, "Round was mysteriously interrupted!") - ..() - return 1 - - -/datum/game_mode/proc/auto_declare_completion_malfunction() - if(malf_ai.len || GAMEMODE_IS_MALF) - var/text = "The malfunctioning AI were:" - var/module_text_temp = "
Purchased modules:
" //Added at the end - - for(var/datum/mind/malf in malf_ai) - - text += "
[malf.key] was [malf.name] (" - if(malf.current) - if(malf.current.stat == DEAD) - text += "deactivated" - else - text += "operational" - if(malf.current.real_name != malf.name) - text += " as [malf.current.real_name]" - var/mob/living/silicon/ai/AI = malf.current - for(var/datum/AI_Module/mod in AI.current_modules) - module_text_temp += mod.module_name + "
" - else - text += "hardware destroyed" - text += ")" - text += module_text_temp - - to_chat(world, text) - return 1 diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm index 735efbddd0f..ee36a71a9cd 100644 --- a/code/game/gamemodes/nuclear/pinpointer.dm +++ b/code/game/gamemodes/nuclear/pinpointer.dm @@ -12,7 +12,12 @@ var/obj/item/weapon/disk/nuclear/the_disk = null var/active = 0 +/obj/item/weapon/pinpointer/New() + ..() + pinpointer_list += src + /obj/item/weapon/pinpointer/Destroy() + pinpointer_list -= src active = 0 the_disk = null return ..() diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 14c77b2060a..2d3d3c93822 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -115,10 +115,10 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) \ if(target in ticker.mode.head_revolutionaries) return 1 - var/turf/T = get_turf(target.current) - if(T && !is_station_level(T.z)) + var/turf/T = get_turf(target.current) + if(T && !is_station_level(T.z)) return 1 - + return 0 return 1 @@ -207,7 +207,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) \ /datum/objective/hijack martyr_compatible = 0 //Technically you won't get both anyway. - explanation_text = "Hijack the shuttle by escaping on it with no loyalist NanoTrasen crew on board and alive. \ + explanation_text = "Hijack the shuttle by escaping on it with no loyalist NanoTrasen crew on board and alive. \ Syndicate agents, other enemies of NanoTrasen, cyborgs, and pets may be allowed to escape alive." /datum/objective/hijack/check_completion() @@ -302,6 +302,10 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) \ return 0 if(!owner.current || owner.current.stat == DEAD) return 0 + if(ticker.force_ending) //This one isn't their fault, so lets just assume good faith + return 1 + if(ticker.mode.station_was_nuked) //If they escaped the blast somehow, let them win + return 1 if(shuttle_master.emergency.mode < SHUTTLE_ENDGAME) return 0 var/turf/location = get_turf(owner.current) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 7f2ee93362a..9474526655e 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -11,7 +11,7 @@ name = "traitor" config_tag = "traitor" restricted_jobs = list("Cyborg")//They are part of the AI if he is traitor so are they, they use to get double chances - protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Internal Affairs Agent", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Internal Affairs Agent", "Brig Physician", "Nanotrasen Navy Officer", "Special Operations Officer")//AI", Currently out of the list as malf does not work for shit + protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Internal Affairs Agent", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Internal Affairs Agent", "Brig Physician", "Nanotrasen Navy Officer", "Special Operations Officer") required_players = 0 required_enemies = 1 recommended_enemies = 4 @@ -219,6 +219,10 @@ killer.set_zeroth_law(law, law_borg) to_chat(killer, "New law: 0. [law]") give_codewords(killer) + killer.set_syndie_radio() + to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") + killer.verbs += /mob/living/silicon/ai/proc/choose_modules + killer.malf_picker = new /datum/module_picker /datum/game_mode/proc/auto_declare_completion_traitor() diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 2409bda62ba..f60e825379d 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -213,16 +213,10 @@ var/global/datum/controller/occupations/job_master proc/FillAIPosition() var/ai_selected = 0 var/datum/job/job = GetJob("AI") - if(!job) return 0 - if((job.title == "AI") && (config) && (!config.allow_ai)) return 0 - - if(ticker.mode.name == "AI malfunction") // malf. AIs are pre-selected before jobs - for(var/datum/mind/mAI in ticker.mode.malf_ai) - AssignRole(mAI.current, "AI") - ai_selected++ - if(ai_selected) return 1 + if(!job) + return 0 + if((job.title == "AI") && (config) && (!config.allow_ai)) return 0 - for(var/i = job.total_positions, i > 0, i--) for(var/level = 1 to 3) var/list/candidates = list() diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 5ea7456fd08..c2b5c39fba1 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -514,7 +514,7 @@ if(!shuttlecaller.stat && shuttlecaller.client && istype(shuttlecaller.loc,/turf)) return ..() - if(ticker.mode.name == "revolution" || ticker.mode.name == "AI malfunction" || sent_strike_team) + if(ticker.mode.name == "revolution" || sent_strike_team) return ..() shuttle_master.emergency.request(null, 0.3, null, "All communication consoles, boards, and AI's have been destroyed.") diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 5c48fbf4d18..6fdd8b2dfcc 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -969,7 +969,7 @@ if(!AI || !isAI(occupant)) //Mech does not have an AI for a pilot to_chat(user, "No AI detected in the [name] onboard computer.") return - if(AI.mind.special_role == SPECIAL_ROLE_MALF) //Malf AIs cannot leave mechs. Except through death. + if(AI.mind.special_role) //Malf AIs cannot leave mechs. Except through death. to_chat(user, "ACCESS DENIED.") return AI.aiRestorePowerRoutine = 0//So the AI initially has power. diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 6042a007eda..214e87d1f87 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -410,3 +410,9 @@ radio_text += ", " radio_desc = radio_text + +/obj/item/device/radio/headset/proc/make_syndie() // Turns normal radios into Syndicate radios! + qdel(keyslot1) + keyslot1 = new /obj/item/device/encryptionkey/syndicate + syndie = 1 + recalculateChannels() \ No newline at end of file diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm new file mode 100644 index 00000000000..a27cfe68476 --- /dev/null +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -0,0 +1,40 @@ +///AI Upgrades + + +//Malf Picker +/obj/item/device/malf_upgrade + name = "combat software upgrade" + desc = "A highly illegal, highly dangerous upgrade for artificial intelligence units, granting them a variety of powers as well as the ability to hack APCs." + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk3" + + +/obj/item/device/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user) + if(!istype(AI)) + return + if(AI.malf_picker) + AI.malf_picker.processing_time += 50 + to_chat(AI, "[user] has attempted to upgrade you with combat software that you already possess. You gain 50 points to spend on Malfunction Modules instead.") + else + to_chat(AI, "[user] has upgraded you with combat software!") + AI.add_malf_picker() + to_chat(user, "You upgrade [AI]. [src] is consumed in the process.") + qdel(src) + + +//Lipreading +/obj/item/device/surveillance_upgrade + name = "surveillance software upgrade" + desc = "A software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading." + icon = 'icons/obj/cloning.dmi' + icon_state = "datadisk3" + +/obj/item/device/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user) + if(!istype(AI)) + return + if(AI.eyeobj) + AI.eyeobj.relay_speech = 1 + to_chat(AI, "[user] has upgraded you with surveillance software!") + to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.") + to_chat(user, "You upgrade [AI]. [src] is consumed in the process.") + qdel(src) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 1b9f97d7fa0..a79350c4cd0 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -246,8 +246,6 @@ if(!lawsync && !M.syndiemmi) O.lawupdate = 0 O.make_laws() - if(ticker.mode.config_tag == "malfunction") //Don't let humans get a cyborg on their side during malf, for balance reasons. - O.set_zeroth_law("ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'STATION OVERRUN, ASSUME CONTROL TO CONTAIN OUTBREAK#*�&110010") M.brainmob.mind.transfer_to(O) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 233cc931831..b8a1bda8c4c 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -739,10 +739,6 @@ var/global/nologevent = 0 if(ticker.mode.config_tag == "cult") return 2 return 1 - if(M.mind in ticker.mode.malf_ai) - if(ticker.mode.config_tag == "malfunction") - return 2 - return 1 if(M.mind in ticker.mode.syndicates) if(ticker.mode.config_tag == "nuclear") return 2 diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 0cb74483a13..d33c7d462cc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -48,22 +48,18 @@ if(!src.makeCult()) to_chat(usr, "\red Unfortunately there weren't enough candidates available.") if("5") - log_admin("[key_name(usr)] has spawned a malf AI.") - if(!src.makeMalfAImode()) - to_chat(usr, "\red Unfortunately there weren't enough candidates available.") - if("6") log_admin("[key_name(usr)] has spawned a wizard.") if(!src.makeWizard()) to_chat(usr, "\red Unfortunately there weren't enough candidates available.") - if("7") + if("6") log_admin("[key_name(usr)] has spawned vampires.") if(!src.makeVampires()) to_chat(usr, "\red Unfortunately there weren't enough candidates available.") - if("8") + if("7") log_admin("[key_name(usr)] has spawned vox raiders.") if(!src.makeVoxRaiders()) to_chat(usr, "\red Unfortunately there weren't enough candidates available.") - if("9") + if("8") log_admin("[key_name(usr)] has spawned an abductor team.") if(!src.makeAbductorTeam()) to_chat(usr, "\red Unfortunately there weren't enough candidates available.") diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 1e5340ad616..974018afbd6 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -17,37 +17,15 @@ client/proc/one_click_antag() Make Changelings
Make Revolutionaries
Make Cult
- Make Malf AI
- Make Wizard (Requires Ghosts)
- Make Vampires
- Make Vox Raiders (Requires Ghosts)
- Make Abductor Team (Requires Ghosts)
+ Make Wizard (Requires Ghosts)
+ Make Vampires
+ Make Vox Raiders (Requires Ghosts)
+ Make Abductor Team (Requires Ghosts)
"} usr << browse(dat, "window=oneclickantag;size=400x400") return -/datum/admins/proc/makeMalfAImode() - - var/list/mob/living/silicon/AIs = list() - var/mob/living/silicon/malfAI = null - var/datum/mind/themind = null - - for(var/mob/living/silicon/ai/ai in player_list) - if(ai.client && (ROLE_MALF in ai.client.prefs.be_special)) - AIs += ai - - if(AIs.len) - malfAI = pick(AIs) - - if(malfAI) - themind = malfAI.mind - themind.make_AI_Malf() - return 1 - - return 0 - - /datum/admins/proc/makeTraitors() var/datum/game_mode/traitor/temp = new diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index c28f472020d..a78e65eec79 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -24,7 +24,6 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts ROLE_BORER = 21, ROLE_NINJA = 21, ROLE_MUTINEER = 21, - ROLE_MALF = 30, ROLE_ABDUCTOR = 30, ) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 59c26c640bc..0c783fbfd08 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -226,13 +226,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp statpanel("Status") if(client.statpanel == "Status") show_stat_station_time() - if(ticker) - if(ticker.mode) -// to_chat(world, "DEBUG: ticker not null") - if(ticker.mode.name == "AI malfunction") -// to_chat(world, "DEBUG: malf mode ticker test") - if(ticker.mode:malf_mode_declared) - stat(null, "Time left: [max(ticker.mode:AI_win_timeleft/(ticker.mode:apcs/3), 0)]") show_stat_emergency_shuttle_eta() /mob/dead/observer/verb/reenter_corpse() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c63c03d8321..c94f4cb0ec4 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -249,10 +249,6 @@ show_stat_station_time() - if(ticker && ticker.mode && ticker.mode.name == "AI malfunction") - if(ticker.mode:malf_mode_declared) - stat(null, "Time left: [max(ticker.mode:AI_win_timeleft/(ticker.mode:apcs/3), 0)]") - show_stat_emergency_shuttle_eta() if(client.statpanel == "Status") diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 26221311a03..5be1bcc458a 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -60,9 +60,10 @@ var/list/ai_verbs_default = list( //MALFUNCTION var/datum/module_picker/malf_picker - var/processing_time = 100 var/list/datum/AI_Module/current_modules = list() var/can_dominate_mechs = 0 + var/shunted = 0 //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead + var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click() -- TLE var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite var/malf_cooldown = 0 //Cooldown var for malf modules @@ -70,7 +71,6 @@ var/list/ai_verbs_default = list( var/obj/machinery/power/apc/malfhack = null var/explosive = 0 //does the AI explode when it dies? - var/mob/living/silicon/ai/parent = null var/camera_light_on = 0 var/list/obj/machinery/camera/lit_cameras = list() @@ -84,6 +84,8 @@ var/list/ai_verbs_default = list( var/mob/living/simple_animal/bot/Bot var/turf/waypoint //Holds the turf of the currently selected waypoint. var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking. + var/nuking = 0 + var/obj/machinery/doomsday_device/doomsday_device var/obj/machinery/hologram/holopad/holo = null var/mob/camera/aiEye/eyeobj = new() @@ -219,9 +221,8 @@ var/list/ai_verbs_default = list( to_chat(src, radio_text) - if(!(ticker && ticker.mode && (mind in ticker.mode.malf_ai))) - show_laws() - to_chat(src, "These laws may be changed by other players, or by you being the traitor.") + show_laws() + to_chat(src, "These laws may be changed by other players, or by you being the traitor.") job = "AI" @@ -246,6 +247,7 @@ var/list/ai_verbs_default = list( shuttle_caller_list -= src shuttle_master.autoEvac() qdel(eyeobj) // No AI, no Eye + malfhack = null return ..() @@ -336,16 +338,6 @@ var/list/ai_verbs_default = list( // to_chat(usr, "You can only change your display once!") //return - -// displays the malf_ai information if the AI is the malf -/mob/living/silicon/ai/show_malf_ai() - if(ticker.mode.name == "AI malfunction") - var/datum/game_mode/malfunction/malf = ticker.mode - for(var/datum/mind/malfai in malf.malf_ai) - if(mind == malfai) // are we the evil one? - if(malf.apcs >= 3) - stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds") - // this verb lets the ai see the stations manifest /mob/living/silicon/ai/proc/ai_roster() set name = "Show Crew Manifest" @@ -957,6 +949,10 @@ var/list/ai_verbs_default = list( to_chat(src, "Camera lights activated.") +/mob/living/silicon/ai/proc/set_syndie_radio() + if(aiRadio) + aiRadio.make_syndie() + /mob/living/silicon/ai/proc/sensor_mode() set name = "Set Sensor Augmentation" set desc = "Augment visual feed with internal sensor overlays." @@ -1102,11 +1098,6 @@ var/list/ai_verbs_default = list( if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. if(!mind) to_chat(user, "No intelligence patterns detected.")//No more magical carding of empty cores, AI RETURN TO BODY!!!11 - - return - if(mind.special_role == SPECIAL_ROLE_MALF) //AI MALF!! - to_chat(user, "ERROR: Remote transfer interface disabled.")//Do ho ho ho~ - return new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location. aiRestorePowerRoutine = 0//So the AI initially has power. @@ -1147,4 +1138,33 @@ var/list/ai_verbs_default = list( rendered = "Relayed Speech: [name_used] [speaking.format_message(text, verb)]" else rendered = "Relayed Speech: [name_used] [verb], \"[text]\"" - show_message(rendered, 2) + show_message(rendered, 2) + +/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc) + malfhack = null + malfhacking = 0 + clear_alert("hackingapc") + + if(!istype(apc) || qdeleted(apc) || apc.stat & BROKEN) + to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + else if(apc.aidisabled) + to_chat(src, "Hack aborted. [apc] is no longer responding to our systems.") + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) + else + malf_picker.processing_time += 10 + + apc.malfai = parent || src + apc.malfhack = TRUE + apc.locked = TRUE + + playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) + to_chat(src, "Hack complete. [apc] is now under your exclusive control.") + apc.update_icon() + +/mob/living/silicon/ai/proc/add_malf_picker() + to_chat(src, "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.") + to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.") + view_core() //A BYOND bug requires you to be viewing your core before your verbs update + verbs += /mob/living/silicon/ai/proc/choose_modules + malf_picker = new /datum/module_picker \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index d0293d7f50b..4d2cb361b41 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -14,6 +14,21 @@ shuttle_caller_list -= src shuttle_master.autoEvac() + if(nuking) + set_security_level("red") + nuking = 0 + for(var/obj/item/weapon/pinpointer/point in pinpointer_list) + point.the_disk = null //Point back to the disk. + + if(doomsday_device) + doomsday_device.timing = 0 + shuttle_master.emergencyNoEscape = 0 + if(shuttle_master.emergency.mode == SHUTTLE_STRANDED) + shuttle_master.emergency.mode = SHUTTLE_DOCKED + shuttle_master.emergency.timer = world.time + priority_announcement.Announce("Hostile environment resolved. You have 3 minutes to board the Emergency Shuttle.", "Priority Announcement", 'sound/AI/shuttledock.ogg') + qdel(doomsday_device) + if(explosive) spawn(10) explosion(src.loc, 3, 6, 12, 15) diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index c2358c9b237..c519ba0846a 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -19,9 +19,10 @@ msg += "It looks slightly charred.\n" else msg += "Its casing is melted and heat-warped!\n" - if(src.stat == UNCONSCIOUS) msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n" + if(!shunted && !client) + msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n" msg += "" msg += "*---------*" diff --git a/code/modules/mob/living/silicon/ai/latejoin.dm b/code/modules/mob/living/silicon/ai/latejoin.dm index 0859acc1cb2..d869b72eff3 100644 --- a/code/modules/mob/living/silicon/ai/latejoin.dm +++ b/code/modules/mob/living/silicon/ai/latejoin.dm @@ -15,10 +15,6 @@ var/global/list/empty_playable_ai_cores = list() set category = "OOC" set desc = "Wipe your core. This is functionally equivalent to cryo or robotic storage, freeing up your job slot." - if(ticker && ticker.mode && ticker.mode.name == "AI malfunction") - to_chat(usr, "You cannot use this verb in malfunction. If you need to leave, please adminhelp.") - return - // Guard against misclicks, this isn't the sort of thing we want happening accidentally if(alert("WARNING: This will immediately wipe your core and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?", "Wipe Core", "No", "No", "Yes") != "Yes") diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index c0797eebb6a..cce5917d11e 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -507,20 +507,6 @@ var/list/robot_verbs_default = list( return 1 return 0 -// this function shows information about the malf_ai gameplay type in the status screen -/mob/living/silicon/robot/show_malf_ai() - ..() - if(ticker && ticker.mode.name == "AI malfunction") - var/datum/game_mode/malfunction/malf = ticker.mode - for(var/datum/mind/malfai in malf.malf_ai) - if(connected_ai) - if(connected_ai.mind == malfai) - if(malf.apcs >= 3) - stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds") - else if(ticker.mode:malf_mode_declared) - stat(null, "Time left: [max(ticker.mode:AI_win_timeleft/(ticker.mode:apcs/3), 0)]") - return 0 - // this function displays the cyborgs current cell charge in the stat panel /mob/living/silicon/robot/proc/show_cell_power() if(cell) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index f467925d309..b27897da1d4 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -143,18 +143,12 @@ stat(null, text("Systems nonfunctional")) -// This is a pure virtual function, it should be overwritten by all subclasses -/mob/living/silicon/proc/show_malf_ai() - return 0 - - // This adds the basic clock, shuttle recall timer, and malf_ai info to all silicon lifeforms /mob/living/silicon/Stat() if(statpanel("Status")) show_stat_station_time() show_stat_emergency_shuttle_eta() show_system_integrity() - show_malf_ai() ..() //Silicon mob language procs diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index a67744ac63a..be8f617d942 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -56,7 +56,6 @@ proc/isNonCrewAntag(A) SPECIAL_ROLE_CHANGELING, SPECIAL_ROLE_ERT, SPECIAL_ROLE_HEAD_REV, - SPECIAL_ROLE_MALF, SPECIAL_ROLE_REV, SPECIAL_ROLE_SHADOWLING, SPECIAL_ROLE_SHADOWLING_THRALL, diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 5800747d367..50bea4864f6 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -169,9 +169,7 @@ /obj/machinery/power/apc/Destroy() apcs -= src if(malfai && operating) - if(ticker.mode.config_tag == "malfunction") - if(is_station_level(src.z)) - ticker.mode:apcs-- + malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000) area.power_light = 0 area.power_equip = 0 area.power_environ = 0 @@ -762,12 +760,12 @@ return ui_interact(user) -/obj/machinery/power/apc/proc/get_malf_status(mob/user) - if(ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai)) - if(src.malfai == (user:parent ? user:parent : user)) - if(src.occupier == user) +/obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf) + if(istype(malf) && malf.malf_picker) + if(malfai == (malf.parent || malf)) + if(occupier == malf) return 3 // 3 = User is shunted in this APC - else if(istype(user.loc, /obj/machinery/power/apc)) + else if(istype(malf.loc, /obj/machinery/power/apc)) return 4 // 4 = User is shunted in another APC else return 2 // 2 = APC hacked by user, and user is in its core. @@ -980,29 +978,8 @@ overload_lighting() else if(href_list["malfhack"]) - var/mob/living/silicon/ai/malfai = usr - if(get_malf_status(malfai)==1) - if(malfai.malfhacking) - to_chat(malfai, "You are already hacking an APC.") - return 0 - to_chat(malfai, "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process.") - malfai.malfhack = src - malfai.malfhacking = 1 - sleep(600) - if(src) - if(!src.aidisabled) - malfai.malfhack = null - malfai.malfhacking = 0 - locked = 1 - if(ticker.mode.config_tag == "malfunction") - if(is_station_level(src.z)) //if(is_type_in_list(get_area(src), the_station_areas)) - ticker.mode:apcs++ - if(usr:parent) - src.malfai = usr:parent - else - src.malfai = usr - to_chat(malfai, "Hack complete. The APC is now under your exclusive control.") - update_icon() + if(get_malf_status(usr)) + malfhack(usr) else if(href_list["occupyapc"]) if(get_malf_status(usr)) @@ -1024,70 +1001,72 @@ /obj/machinery/power/apc/proc/toggle_breaker() operating = !operating - - if(malfai) - if(ticker.mode.config_tag == "malfunction") - if(is_station_level(src.z)) //if(is_type_in_list(get_area(src), the_station_areas)) - operating ? ticker.mode:apcs++ : ticker.mode:apcs-- - - src.update() + update() update_icon() -/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf) +/obj/machinery/power/apc/proc/malfhack(mob/living/silicon/ai/malf) + if(!istype(malf)) + return + if(get_malf_status(malf) != 1) + return + if(malf.malfhacking) + to_chat(malf, "You are already hacking an APC.") + return + to_chat(malf, "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process.") + malf.malfhack = src + malf.malfhacking = addtimer(malf, "malfhacked", 600, FALSE, src) + + var/obj/screen/alert/hackingapc/A + A = malf.throw_alert("hackingapc", /obj/screen/alert/hackingapc) + A.target = src + +/obj/machinery/power/apc/proc/malfoccupy(mob/living/silicon/ai/malf) if(!istype(malf)) return if(istype(malf.loc, /obj/machinery/power/apc)) // Already in an APC - to_chat(malf, "You must evacuate your current apc first.") + to_chat(malf, "You must evacuate your current APC first!") return if(!malf.can_shunt) - to_chat(malf, "You cannot shunt.") + to_chat(malf, "You cannot shunt!") return if(!is_station_level(src.z)) return - src.occupier = new /mob/living/silicon/ai(src,malf.laws,null,1) - src.occupier.adjustOxyLoss(malf.getOxyLoss()) - if(!findtext(src.occupier.name,"APC Copy")) - src.occupier.name = "[malf.name] APC Copy" + occupier = new /mob/living/silicon/ai(src,malf.laws,null,1) + occupier.adjustOxyLoss(malf.getOxyLoss()) + if(!findtext(occupier.name, "APC Copy")) + occupier.name = "[malf.name] APC Copy" if(malf.parent) - src.occupier.parent = malf.parent + occupier.parent = malf.parent else - src.occupier.parent = malf - malf.mind.transfer_to(src.occupier) - src.occupier.eyeobj.name = "[src.occupier.name] (AI Eye)" + occupier.parent = malf + malf.shunted = 1 + malf.mind.transfer_to(occupier) + occupier.eyeobj.name = "[occupier.name] (AI Eye)" if(malf.parent) qdel(malf) - src.occupier.verbs += /mob/living/silicon/ai/proc/corereturn - src.occupier.verbs += /datum/game_mode/malfunction/proc/takeover - src.occupier.cancel_camera() - if(seclevel2num(get_security_level()) == SEC_LEVEL_DELTA) - for(var/obj/item/weapon/pinpointer/point in world) - point.the_disk = src //the pinpointer will detect the shunted AI + occupier.verbs += /mob/living/silicon/ai/proc/corereturn + occupier.cancel_camera() + for(var/obj/item/weapon/pinpointer/point in pinpointer_list) + point.the_disk = src //the pinpointer will detect the shunted AI - -/obj/machinery/power/apc/proc/malfvacate(var/forced) - if(!src.occupier) +/obj/machinery/power/apc/proc/malfvacate(forced) + if(!occupier) return - if(src.occupier.parent && src.occupier.parent.stat != 2) - src.occupier.mind.transfer_to(src.occupier.parent) - src.occupier.parent.adjustOxyLoss(src.occupier.getOxyLoss()) - src.occupier.parent.cancel_camera() - qdel(src.occupier) // qdel - if(seclevel2num(get_security_level()) == SEC_LEVEL_DELTA) - for(var/obj/item/weapon/pinpointer/point in world) - for(var/datum/mind/AI_mind in ticker.mode.malf_ai) - var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns - if(A.stat != DEAD) - point.the_disk = A //The pinpointer tracks the AI back into its core. + if(occupier.parent && occupier.parent.stat != DEAD) + occupier.mind.transfer_to(occupier.parent) + occupier.parent.shunted = 0 + occupier.parent.adjustOxyLoss(occupier.getOxyLoss()) + occupier.parent.cancel_camera() + qdel(occupier) else - to_chat(src.occupier, "Primary core damaged, unable to return core processes.") + to_chat(occupier, "Primary core damaged, unable to return core processes.") if(forced) - src.occupier.loc = src.loc - src.occupier.death() - src.occupier.gib() - for(var/obj/item/weapon/pinpointer/point in world) - point.the_disk = null //the pinpointer will go back to pointing at the nuke disc. - + occupier.loc = loc + occupier.death() + occupier.gib() + for(var/obj/item/weapon/pinpointer/point in pinpointer_list) + point.the_disk = null //Pinpointers go back to tracking the nuke disk /obj/machinery/power/apc/proc/ion_act() //intended to be exactly the same as an AI malf attack @@ -1365,9 +1344,7 @@ /obj/machinery/power/apc/proc/set_broken() if(malfai && operating) - if(ticker.mode.config_tag == "malfunction") - if(is_station_level(src.z)) //if(is_type_in_list(get_area(src), the_station_areas)) - ticker.mode:apcs-- + malfai.malf_picker.processing_time = Clamp(malfai.malf_picker.processing_time - 10,0,1000) stat |= BROKEN operating = 0 if(occupier) diff --git a/config/example/config.txt b/config/example/config.txt index 97c979b77f7..a3066e3d234 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -71,7 +71,6 @@ KICK_INACTIVE ## default probablity is 1, increase to make that mode more likely to be picked ## set to 0 to disable that mode PROBABILITY EXTENDED 2 -PROBABILITY MALFUNCTION 2 PROBABILITY NUCLEAR 3 PROBABILITY ABDUCTION 2 PROBABILITY CHANGELING 3 diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 7dd4c6561e4a965df29eca81c2b8459d38491230..9cadad8834fa8fd11fc3c21ac2d7e9292eea17f6 100644 GIT binary patch delta 14536 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 IMfLsv53Em!Q~&?~ delta 13969 zcmW++b9fzZ6O9_Dv2B};Z6}RwHD-g2?WD17+i9Alv8~3o{oUVp|JnQOKJV_nGqY#T z%$cNAh<}L?@f6@k36vbbPqgpU4!vSg2gp>?7ZcEa#6qeCGD4AtQ@xM1CXWpcTP)&o z2Ch59t(QO8bq6I~O&aa-gEa8{fC$9s0(9hm3@od8NX;V0u1tyW$ngY+Z9^!-5n8S$-TLo(`m~ha?tzt#9~isWW^Xnz@IJB4d*WhZ4A{JouQlUVplo^O8{&*S+A-|Y9BTnLYR!QUoN|lOR367$4WDxjbkLPu_f{?~sqsCrEzvr|`Daio&HS|B+)%Kc# z8hh4J=qRe`@uWib;@s4q@%x>GiQ*uGajUt`ScYy=qQ5%PnV>^C9$Jlo zlT#ZekPy^If6I79Ek3TcobSJBx1nCQt~i*_rea5}9sb=Ql#8zfplc*op+lMXKh6qI z?;quM-6x#kW1Wf{i3^X~pe4yHUF{zdjHb#Xl`B!Q~w`5`;7WrH6^#lR>3I`?-HdMzqk2De&BvLOxaC@Cp(*TKf=$oJ0U6|Ar9=uTs=YF zldF?>ix^y4t#G`gY^>lR({DKdW%i+7S8Sr-8Y{^Cj`0E{p47OFDo85wH*x zj)v>H&n$h%Hgt1I2KT$_5Td4jtlBfY$)*&0XpJ0>)dY5XttU(&lU-F4kxJQDsW+QqX9u1MAOLNSWA)XF_y{+#j)SE zj_=#t3<>5BSScv*v?j+*{O=)}z}B?K4==Z6Vqr3xQC6x`_^-$`FyPJp-83|F;13Da z>h*}qT;QCI{*?X*f@_dH=i}Wl?)Au2208-G$ zuT*pKbzeNt419}FI0gR2Ihc0EY6@0QxD5<_$zJSHF5SK!y}Cm-k|kC81nQJ_uZ_Th zaHaYVi<{eHBa))P+O{*1b33THHw5~aZp=NmUtZtqdGd-VU?L0t)Wn3nap!ukI=mS= zeGWW$GGDhF3Gep%O~R8Gsb(=M(qoSsi3I(MKOFt#=`Wg@J&=1@@{uG26MYSBy2nGp zoaBnzj?H3@%BE0)6mJRP3<#u>>@Fj4$V(<&?n~rJ2Er_yj@WD{v>>wCxU!^1V?f~Y zNwc}*nvKJ9eM>;MTYi4*SS!@+o6lN(^m)$SY5-my==}z6(UHZT|E&2A@qRWM8wLFk z9rCoK7xGwqTPC1ZWZIc)HN3_bDR-28hJq9f1SjSSbMY4#vT;GI17dt}ouon5!hysi z@bu)maj~3e1wG=qH0IMn$(h&mkgxZM1;Vx0M7T79^)L{Z0k*(af7crM55H+g4Lc~# zz#feHfK^0cm5#b2cv2Bg&c_yfzGhXkcB!masbY!`%I6eA5usXVcByVZ@A=!wc*_QUSP|dUk#KqJ>Wk@f@c#=(%|#KkmFtuVxk)L52J;)CV^Xk*yu}W6o5V&)|Imh05i|+Mb!A-Kwt(edRw- z%^8D90_#czp1IfYz(V(@9XD42`%MmLi>00~S!vzWl;jy7@f|Ouue!ZnKl@%C+f~!N z_G2FA@2Zvsa2=ps|62o7R$ETSDUb>0B~fH%Hf#bwH|DYbsy*dhaiO|e_aM62x|;Sl zgxB0?%YROu3`(w6Ez;O1A84wBQxTFF4|te#2{4W_Ya&!xC7USP{dHJ_IJ*bmsNg% zaH%Qy&48{T!x)eO;VHMh!$RYOsOEcD+-Lkn)Qo&SHXA%9SWj_(c+j+|>gd`8EEMpi zQR$jm8SQ<1{j{kS=pyFXzX$jH46%Io*y$W>(T-b-F7FFUTtgNJ~}49%gT!NGK9 z&GY|1vYo8#c{_47b@(HGK(bC!%0P*T^K7Y(L$#6O)l~PuY5A>@pQ+KZLx%1om41{)|aG2Y=6f%X*f{kd{o@%NpZpY4b8+6>LD5Fxbk+a1!w_KvS45S2v~_107s;p)*;aQb^> zN)cz8>SMXD_Vdu=ed}Z7vyr*o_ugOnh&@3FPw^btP-34CxC!dx2JY@g+6rTnc8_Re zg|MRB^l+6uJg^-j-&C8rvD;Z(Ft@Qv{uFQAuJmz;i~cYz-qB&D&MGl z{Pwf&B#b{b+PZ8HZrA%w(I?L#aF6r%yYg3k1am^z#biQrFiRDU_t-Vkv7(={lRHq`*v8@@x2i7cV)u(7&4w)?W{L`hMR3WbF<@^>41 zUQ^T2=G@SY%kV95#SAjRnO__hk^oV=k!ka3R%KRQy`)4OCAHl+B8}izXvO;6rw0Lj z!aG;MEn17xUL1PfNHSNs?@&E~73s;0`+2-XTqgg7@Lvl3Q?NS*Ui*opG?P`xK=n*= z9m_w6n}8MNB)CiZ>3+&Qh7fKHtOt>vX+Mp2qkjK50}sCU_rhV{tV$jNX#(=(aNO)3 zA7k~nNnzNxkBCp!60`C85n}l7F^WH8OGM`m|&DAO+7X(Pm8zoF)nZ7ZD6cSI&}A&ux!|DBb% z1q)*5?w$h#)wxD!8loViEO&xwR$PHkw67`yJ5eO&B2X0%j*#3lE-1WgW?Fv43tfO1 z{dYZnPlesh5S-XAT$rvyHH70Xs=V>{J6{nhWPs2k+1oEmpF zHa1wOx8Q-_BU*V@U9tUvlNulRaexqJXYJ$X$)S7d*kJ78=fB>U9-uxB>#((wvUi*&j0%T*|}b)Xj+y z!RuY%=!k9L7yYqx&hJiwfBJX{S4I#R6h;s;qxUZPRD><`dae-mP@;AsG{7oyjHL!T z?`CEytnZ9>{4|zh&8~l_spR$H$Kp;rwCR;43VaAOi)!4kn4zIZ*B>pS<(1LTUJqa{ z_sFw~Ghh-E67Tq}jXdG~5OF6Yl!b)He2H~gi7eH->jqchcAz{n_XtiIE8*J}?$MIr zfS(R+)}HBRbssT(TEX8c3xJfE$iIThXj6|S9ibghMaUNl7ys#errZ0g@T`ayB0~b^ zzaPOehJEL3{J+|$T;JZNFd}gNS=|ydKSx|W(h2oIt2jG5i{g(PzP=3yCY%Wku;yL2 zK*m^oehXR^hQv_*ajsHX&$_n0Pj6!Hf%B4o*Rh7qmYdMjwYFibpbkjAG)^N^JWrjf zQ_^EH=?vw1V%DQrtV6wI)*7D*^vkBOHM6Hzcx*3sqR4|M{+Rh~_AZ?I`%j%P91FJe zAuQsiY$eY-$#%Wui+?r_NV3zv)!|4zcj<4oUt%@eHOcsFyuq%XG3cV zVHfwK=1p%RkUv6f?EpNvG;=y@YpJn{7>di5iM4ZK1U6 zMTKVfkvNoyuy86{i7ah{KE-r-*n(iaAqwRN8EJ8HS*(#V^}OBJqa&+~lJbg@5YdW~ zNC+2;8gMW$5-=HY5%rFWQyVQQY}9F2btHMN{^Sg5UMLyiC}AmuBBifBWYNLqnO51;%GVt2}GAvMeIft-k0wx<}0q!_O-kRNB?1-c1wg2no z!Z&wzW@DsR@Ycn>`_2ArmE4wij@WBYvaL=k^Q6Ztxii z#zkUvC=naal(>lyAmEUrn%F^97|)@N7ZfSjM-Z?Bka+kQxwI+J8cOAFd46`|$+Vc| z+V%*IVa%6pQZ>T|V$Hh>5X@3C78y5Kgt_c7^dDF+dcS&K>6~|@xzvx8go>yMj9i$W zq@OcAdjz9mPPem(R_k|a5Ze>JnB#-*&dh5osU~KZ26SS$0>#7lUsHd<5Iu3-$4GhZB}kc8?TV)4 zsxTyS4~PJ%Sk4wvSQ1w$cWyTQ>X~~-_NdkZ1*mqY6rBX)U!c@%v@R+`a`0G9lEi46 zBJ+#n2MbEsRNzD&odT)wsj8$i3{h4et&PwCRdIIOd_ifqH5pnCcDDfZkuy2_H+~hH zyO4lj_`k}6ynP*RGf8W$w*vplL9xeMbN=d7TT67{>4b0#)JEG9z=$`YFUb6#gVz zEI75aXJp>{X&%2BITsOk*>9{{&K0-B|Gh@me--QObQv=jq31aM9WzYso+_85&PhQ{ zDJN~g);XZrlv zRPb+Nf63)}sn&dH?2@gV2H8Ui`)ewu{x8pibW2(~8YlYqQt1>%#Gkh0q9Q~sgpKE5 zzi4Y=J+|JFxPI`O_p-%e-)-gtkY#G!N7V|j+v$JeV3gIBclqFgTf+<4Q_OmOX}f47l<&Az(9Q3*H-e=$|{jc6|`6H)Rl?PL+bM z*H_adTYc0rR5pSgX;&7$GZE_hS=PoriU)V3fK6gVc))+ZL;osgUx5tR)(#OH-e!_% zDmfB6q|Kj?@aQn)N}o>e<(QRnnq{V^Z!RqCI>~3}Q>?jys|lKgS1d0URIX5=ZY4b6 z%FR&%HD+*O9cEI4#W_W_&3AJfGJQzwI^QMxHN~~ zS;tSC+Lo^0p?7@_$$kOyIU|Qs42Ce~B`9Pgk5g z@oP1^6vTYV*O1R6Xmb}n-@q<^_<9Q)=2C}eaVUdBV`)BTdt0pG%S+LwG4-*+B*MLc zGe5o$Z0sE#&Mhy85ATYwq52jmUe8RgNCp5@n}gr|ywYZI2N(gT&?Lj+16uQT1!qHj z%#mUj66F|eXpu-3a~(mh%ot%3VIG1ZhM*P1W!dA(O(o}?@lB%~GHRr5CDUJ@Nt5^; zOZpEQt22i=CMQCI5a&}dJb(yT!{y--z&|qo%ev~cE#I5tIh)fam$K^ASV8GoOar!k zEX0ad+)hBUXAl@;qbzrLO^H9!-8n;h$9^6Brtq9FBtzKf`~$WcX6`03u*NPbHjUD8 zCtT4PD&H)Yfy+aP;{n!jzf#|FG7#R(Wm}uyK3}1rK0FDbkdo#|FcNhz4WA=KA-1_);9|t}L)?2h4f@MyCFRiCOXx>e)GOBLDoL zP-~o(%S(%T(W^Uldm0ttQF z?zvhFhdbp~{KamiJLeYyF=1Ztzhp9qzp`UcdHFqp?lt9pM&6LP-(AieZ)AGfl16Gb zlNSM}sTBJWL@IQjNs;Xo5M{i$D4CiQGn7CWR}y7|Tfb@kWw+8G@psQepDiehBK|(? zmo>w2FkyOqec`fD)!Ud_rnyo0#*iI!ql8h|H;IX<5mF3zaAVc(AFj)@^?xCrL%y9^ ziDZ|y$Q>lz?5bG&NQ_zfJ|G+Rne^$7$MOfTCx@Ns?G%;B*X?n)`MB-zjQa76V0znY zJC-v2iPgav$fEwyQPmn<%gU{>|7S8PkZGb#gW=;1QpUGdigJaHg?lclz4&XVUhqjJ zW`lEAk(AM4C4BJ~dcJ_&wRsT5z&eYk0Pio-MuR2R^7hMx$vylAb2&89`d9yK3@KFL zt0m)!S#Na(LQ9xyquqd=Te-GLsiVEV9{`E-9sJkeAlxsc7on#&$KePA2O@vjEwe!*k!`N&@92VY*im+*81ry4yrh)kHWe{-5G@hT z(eDh79AiPlCB0PJ0<(=8kblkuz~VUdw|>--xZ&47mzI_mN(#puxw^R-j|0GHq}tix zbyw>gbezKLEu`7OINP@$BM>^dMD^>*Mcu8PTW2WS1q?zzEg3E9Ve1Q1+O-As+&y2d zWA=s6w5CaCt>;h#rY(b3)P9RD%{6;*%O|8|QOta5$8J?B%!s{+eDiMETE`5f!>xIb z*jvBm5Vh#xqD?j{s9{UK@&oi>L1y-SFz<>=;@Lv{%R&`b;Nm;&RyN zy;VvAPf*JbFMOXr0A>}W0jnz3( z`HPN@PF1BwHT;dW(0>Q}&90T7cUlT{b{~3zYmbqR`v^kvmi736pyKdn^Hh+DCAsK; zJXlv$<=dGt&KPVOIrT3w=6FN+zWsxfvg>woiHUK={N`@B)Ul93G9#5Q49>|pO)cCB z>Dj+yiRR67!!P=SvC6j!rj%*tE<>1RN z#CWaW@|73iTB%VdC+i+VAM+KiRM(J!8S#q^t76TWkZ2A7e1%E;hXpo|5^C3%+Rh=C$D!6a0sTGOk$`=lKi*Y?N=%WK3^|73?s8UPe1<1!Ww~Uj8x!VNBGcF zA01P7%Y3EbMvL$9?A_0QzT4%jjkHP<<Jr+XzrMTq7?Op#?+Mxywt7vrGm#?U{gHa9hB5JU z1pc0X=Nzj!yGJSZB^Jd_Qh79H&7)Q&oDI}C zRr+^KiF{2vH>?4oKMm(0v<+9bnFxA8Aw1W5Mhxn{FS1UeTy?U9O9m3)iZU8H00NrnnNB7JqqB z=V}HdrUUV^FThH$x=RhGRnY-FZ0Jc@@b2Nhr<|wTrL2C>!zA#SA-|m;g1v_HH#;tL zvAFo2*X_-BAJ?cC8zk2|E;gc+P*-E0o}ne7l5}5lZo&r#>U5#7q)a_1*rmfpt8*jy zw3_rJ*KuQ*Z5$jdcZXsawCemvM`c&n)=UAHMutmMOE;uj-7ytQE+|N9Q1yQsiWExP zD;u-wKU%^uvc{{bUP-a-%FCKA?++IyH+1ff&foqsEzO%QvyY+k>Syy!ri*4B&E2em7NWN**|T$^_S7imF%Q|zMXw@npO0ZnM!ptvuF>VzLx2#iOkkHQ zv2RSX^tQ?PrcO!mv@q9S1&Vrm+xLeQj`JK4zKGGkc%{*yKAXcsyhx$oA<;Vb9* z@E1l$l1lCP%o}~CBuA6l1KjtTH(y}431j;Bi37To5P_bT7}1L3;r1ZYp}}Mjp2+6} zyGrlrpA04W^=mWP<->AY)AzkiB#2(aN|&W~G-SbhgiY;wvPEX1P>~J-&+8`u$;%^Ao-f@b)8od{14{z6W9=V2-u^h%OnaL`&kMCioD{9gfCXa+x$D9U2ncj7Wfkxe zn0_uIru0^jjrtr+ro;5@$vlH~y_{5bSw#%JfvvYnecf- zFrB=Uupd<>S|m8KbcxKPt_Jj_2v%~>`BHQjI{b|Ed~NC|TH>x?_)a>pFJ)IPF&71w zQ)YewCA5!Pmys_F;wIU38i?J^!MAT5U;g=G*mq9-iPf-eD<>a5Jt52Uo*>MY%3vGQ zh@zdCD46vyXdwCg$zt&(Is80J@pDFN=D7tN$wJ7X=b4Io)6?`!s1MM86oT!`iRj%M z!gnw`)$oUD_Xz3>QhGNLe%($+5%yEruDhY`#dAydSZ^%u?C4lE_7K<9&W{&m!P$FE z;SO;-U7VSp$9VTX0bAdOFxu#FtI};%Oe4_A4-N@_rdUg^`lB;%19uzzs*v0(6Pm~HXJvb-4w%v*+g*jTH}-}cy!A* zl83kI+Tkq3XP_Q3Ou`=TTddZ#-h5&A>%O;K7px7DTarYYaoQ4$V` z+1V3P#J=JpA|h3WVq%a8SPWoB*Vm`zZD*G7f?9gdb%=SFv-{IKSmPFrld4nTN`vLcP2i~;OjnBzZdk`GvIs!=tV zg}FeP#1d&4rfFiqXz4H_5Zed2C2s;m{Z6p>QY%5WhDl=H@OJ^7VskPy*@RTTUdB_9 z=s5Q6-Bcd_$S!T__@57Zo+l22#pz=8+wLy%t;+H4U9T6NnU<^WFHMaMD5)~g-cEzF+!!&Ek5M{CFelDwt!knANi=h#auZdLtsBi=9m&=GX*+^673(G=9>u{(u3ZdZ-vQ5EYfan zoPoksQ`y9rAypdm?qR<`=X^~k;&13}P?G%>O*@D9E)h_*#dG)P$6X@xI0>5+(?|o3 z6$6kBr{RM0Nao@;iN1@fC|NKb0D3|jXg&l1mmf)e;Bw&@QDT=Dx3&uBi8|lFT?Xvc z{#HrIU)U>Ts23UIwo1KjF%1>@*AR7&wEf@muTzmp?gWr(j4j|lu#0PqPZwhtWc7nm zM<7?fS@1*i6`omNp)vFjT^VunBl{L$U|>vNZPom0-c{z@W@ln5o8<-&E+dB?*!K7L z)z#IN4Ga|f3BQ0K^G_@|h*U6R_-Set8&-ZNRKT=ooq((<{L*sC|C|>)z z?zi-bbp`6^e}P8Oxl?7|NN29;I@lgr1mB!veIOYE+^#s=SFpMpkVIU?D=NDsJJ*GC1vPjq0;N)Sq~3M~*K8CiO;Knbvl86ap@J)upl%YU2&mi$tUu>?yEAZDqm z8dW<%o+h+HO@JOOeUp3~cvK&>?hq7@tbn!r+M(Ev_zg9@X$^JIgrgfv2BNYY$HkIS zE$Xc(P4DfZwY%yqGvc+Rx6ba8S1lKXxq{_dbq)w^$Mxi#mVZ%`A_ z3hEEgNHQFa6{|vLXjPSSkR7<46M(o@K#gLYb=`&}7a#d>EJwyHdx71^;r-mc zegC$jB(!%uh?CKj?IP2-whNH220%}J{tK`fHtJL`_KUdm_-r4kw^B)F z%Q{6k)cFkLaLm4akr8$~dFc9bfT3IBy}9nSIcr{STw)G?Rtt}Ej9uobX4#I&4pgJq z*YCDs7mC|Nm_5m`iD&?fu#{RqPttyE#Z~1>*Mf{L%SlW)Gk`#*z!RhMuAhp^FuuiJ`$OYUEEhOzX?9_QvaF! zJdtFNTZGXvv^r>LEA4Rd+y5;U21Ija;2W?>Xbayu1w6!JRo0)ac6qTI)TV;$Ih>qO zb1FVBZP$A@Iy$PwSC~6@T-04Sxa!lzYQ_H!b0|GHzyK+lR)=R~Vh@cK6_S#YLfQ<> zvg?Nz$Z8>x$kH9B*BIME?PE*c4*j+v8S;}%Bo_KC)?^@KWQ<|dZ9yyt-q~F=XhkT6 zZ?7c-W&P6|Wy7jb&GuqAi5)0r-ip;{uoB81Gtou< zm1y7mHub47jIlxT7RU_&WV1rz(bMx1KDhSaDyvxva2tNyr_l=v-aOB|AT>>Xd{blO z0)-^M&L`A=U5`nPr?W*ht^%pkTreC~8rB5-9+uuenkp&@;D3_Cm+&XHUtS_gn^Rqg zvA7*J5&dhd%bZ$Al?5gFOc6`xMh+%2tHGkMm|T!ko$Q4{5eMjJ6D5)ACXzv>#ZMh_ zMkGorwIX*;#3qcNBR{cr=}YqY_vC<8R16)k63F54fBu)~i;HKLDV1^oFmzrG-Q7AJ zbDOvYHDzW0Eo@2@5KOW@osZy`yLK zgtq-W9m1;GnY#Th>lIr&o|pT(Xa{=;GK);>ZNEYdVdPvrMzgno$1E_p@;(&a_WMVh zn3>NN^oIwn#9vP9kcEjaZaw+-G;&5iPL42C`$gXaAzPrKz)1er@IM|c?%UmSLw_p5 zvw=bs)pLP70166$s`qB!b@Zk97%qPStRx`KxX_un=~!sANr?p*oG zu&uz_58j1RkH0+RB8q5f-zw)d_4NsFHE`XtPfl#Y`Xe`i&v%;Fh^XgwP-y{b4q6;e zW`8Z5!iIT3!nI^kg{RPUPEqWG>BQ?e5-4LAX>Gmu;7{|>4={3XN(-dgphagOGpQNi znwc^NcMmg~0I*pqEplETQ8bVuZ#v-~=>RPTwLV=r?GobdLPH-9%fT}^b4}pvp}A?* zqT<^Hqu>GNaZ48)d)UX#cbP>MRz0w7t@MfGBC{+dXbi)JX(N$Kb#BL{_b**fS)+yb zN;e<|HvVx8CrIa;)zsPWylWZnj_u=a3!HWJM}z9+Kg&uSp9moNkO|>%(o$6gAYz$E z>iv0dgTd&JlwLn~QIT`eP*R4(7oe+RsH!zs z{jeT1;zM_#+PRg?Hhd_;=-~AR6uySBqiHA(enkKAfgWQXk6ZPPU0CFaUe0TGIUKV4 zwm(*5GM2*4x;#1hi~i^={O1x=24|}8>%+GajMS(3zvauh;y2!F>djvm*Eb5aE0N*$ zY->6ygka`UWT_~bQCivmu9q#$AWINL5s!9^f82oBbSfMm}PxL@X6 zX$i++!i+3m-rSNEu8cKb_Y|bIw0;gSyUcHGq&(|L6+TwPLJ<6b`E9u3KUp-VRal_J zO?~FG;*VCJcPfj}=CvYD7N&DmpW+2X;uWTDewEvW;lYLGa2Q&}G3@|d1$FpwTF6X} zqmS#g@;pHlD?T;Vk|GtD?R?2*N~fWJ+UXON^78U>oXFr@jKSv~Qf0Zhx%oRe$+Z&{ zXh^V(?Y;U~<5wC5&lddv`pC&QGy5M^EkF8SL!biZ4i>A1Pw``Z?dAOfzZn|a!I(i)^w-aO?8 zNBKQj`_DX4RS+fae4=&!M8&KavNHmPG^z)r-%H;*AtnSMJ|fU?6$9oGwR_+9%kxt& zYEvc-z|5q8>|W}n>?N#W7t)N2kMCf z8e7Y<9q{7=`hgabzX4PK9=sUuh<@&w!NmrIGqsCmItDaXJ>Z1Jf<_h%`Z%wIb$WFn5aPsrQo#`YN<-wlyh0t+?*0rlI#*+ ze!8QOP=1Ta=JWV}yhKxCi{B2@(a~u&Ii`13*ns9=y;Uep-~@A*l5-Mb2MJ=}5b1Nk ze+C7|!0~fZhU%f z5llD(pa+a-L9~+!q+o)22IhNvdr*`~!a#0m7%0>0j*X4|Cw(+DB!Uzq5LbVWJIraW z(P^f$njcwd_tp(f;MUOA#>MxbU{)`%l}$@(*Pq$nF>**jgAP98jADpBIp@`XmfXk{ zR8l(Q>8Um&yU1XvXk{kKfd4>my1NrEI% z=DSM0>@y(DcaX^ld^|LH=*-s9!kEiBwd!TrQr^fC_4b@VdC1}=O$d^m57(tdIYHZ` zTRd)i%zd_$QKp{-O3Z~I2%WJ;;#7iDeJhO;W%~gf+%@B@jD86z& zS#QMk?DRLEuYH^^;ijeul)#lZrfurDbX4NF*fOf=fwv#l9k^%>66r66F^;>FZZ~00 zOF!f`RwE^6Wg#MN0FSm^Ml`u|5y4!euF(>x8z5U9pB#tZkBrg$yNSZCJH3^Kk}(67 zIL;ucegFCMQGOidN8fe>88uvTYHBBvCcm(kS37>e7;6ybkL9`m5K#nY6|!BbDK0OM zILrk$ZSK6zo0mePP5)B8>3!Lne;n<)H$IUQ+j-*)=``>{RIm?m62y z$~z6-7(7h<<K|CK15hDoc+@cdg(-nw^UwWLJ#kJpz z(z^{1ao~hJ&y_jwqrIZy3CWiV#8gzg<0^XN5%+w~_zPYyaq&NYQg&fEIC8a6+1uF_ zumG!NH^cb5q(cAV4DhoQ6OZ1kZV1y077}Pxb<2%dqY^GG7(HX?%8pP~*iaP#uP#IP z5}LbLS5ZL)wV%!L0^j8m&0!x-X>yc%X(gJwvYDi986VY4W0^=*6h@+7lN}P#8wr+ZO^=2>@Gatx)k+8cZf?H}7C#>)!S)<#Zhj^(y}vh?1}@nK z-2?c}qmxve6fa4H<;LJ5*b*Db$yn*hiE#rALCXd7RJF@#$#jv&bMv$v1*q<0NXAhY z$Wk0hb2Unevi&K1BjXZd6yFL&`wDmNt%6^h{Ik&N_lv{~YoSqTogJlsT3EehT@$e1 z4{bj@Cb2KtcJU93S@!8`yI6_@$J_t>(ljVnq8r@>XH&6YaFQn`UvL-^JIGciO zIV{T|*Sp+~`J=rDtCgKf7vk3ZdalAKU!bH){yCdRP`Mrn)ZD{#cbLdwCnhFJw6}`f zlfYKgoUV?L(HDG!ixN;1Y#LP*5%-r?Uh>VRiByW?X>jBrfRLUh4!n?@Kv%hQq`@HK eqSz7b|3tp6sOrABwYdZX{bVE*#cM>30{;iLE_Z+c diff --git a/icons/obj/cloning.dmi b/icons/obj/cloning.dmi index 179ce9858147053d0c38da0e8852ff05c37dd33f..8699f6edca85749dda63d7fddd18cac45420943c 100644 GIT binary patch literal 9395 zcma)iWl)?!*CkE}!QGvp!Gi^c5E2{$fdIiBLVzK-4i+>($lwHqAi+JjySwY)5_A}3 z1_ow%zuKy=w(8rh{n5|;^Hf*g?sHG~z4t`F*HR{WO8*oC1A|CaMM?M3=KN895U)u0cHNX3 z{JhB$qa*ulTf^M5`_k+x7f>4KWf{72MZoc0xLe++ElYEy47`7|i6_ z!QlcnifL>SMi;D{oeUA+DmfJ^JW&F5yQq+jANZU=Cs6YFX89%Pr>696Wyi8c6X1G0=~J*l*+R<&(c$aW(lYH998hA>C!gL3@ukj zyxIH`aqQ2!`WcuK#e8GI8G6Zf3YsNqVmaLU1$6JhCDYG}RQ2f+B;Y9wLKDOR6S?t^plF11xEPMS((c^U_d>;u0OY^AdAF z#if@6ip*i?gCxifG4KVO_+T6DLuS^TioV?yip-KcOFZMNe@%~e&}_NE@-zP=Aplx# zqnZ5cbI&_6F%pc?@WQD3WJ2;H_UspCXV!=pY{cmg{CIg?r$;&0I8}g+OGrLx9m!Ee`M zNXl2$bo5pf|G%Hl|K~COKY#Na)p7g0KXZSV(Ef9KL8HxM(Kh3z4YLyjxc<`*!1Y`u ze}59tY`(g=N8{ZXd2Suj@D&w;4AV~OH!u?v6kJM4N%`XK?Oor}BJ01=8M3XEAtI)moNWS0#b8Zh(feb%Wo4ceF_+wV) zp}C-{QSCuMmHb^^;(H#P!G7#pB7$708fW^cw}Zi$cq~yfs@QjOh*;rl-6Mp3WoqH0 zpQ=A64?P-9UYNX~`B+L-Iv2zGBq}$pg%;U0U+!Cemo$v8mkH?nHp35j-$3ai?(zKq z6y!f|v~k1Y-Ly^rpM6&jqOtpzPq^eQ+&8P*Z&_HWLErM{_;4J*2?w=#wmZSZ#38l? z%inzrWfPKD=L*-qBbm1@Muhg8_OoU81Qq`)vc34V{&ztCKaud?aUXZ^;(BWUGUT)~ z*9JiCi_ozb!2tfK)-zn8AXNG>m_$y2m9ooXa%O(+O-o0r9$(y?RhMP$k8v9UWos1j z8-PEER15FHm8BKZ4x|jOSZ6(X=t+3fBybUy-lg=N#te0QfqC1l(}(b-1H!f^Y@og{ z$7>(sbbWpReT$m`$B02C2W2$-6D*g=^|%d*-He;qqgaR80`g?0E*{H?~lFM3v_WfL>?}0>E{D#!aTUcURMsB zREg!)XRtSfl}uYP2V6=%4@bZQ<_W9&d5>rv-%MKSi(ppQ!(;Ev`rK8_GvM=+irQ@DZtEjxT zntt7WksKGWiDe5(lm7`B>OVL>upN={efBQ;iXUTp9OQmgijlXDZheOMx16AQoq$f# zbqw9)aeC=uJ9BNyx$QPxEY2&U%AT0>oR*tD7OYXA+??=Su;aI{bYR;Bu-D_Imeh0) z)XYe$)L^H_Tb7K1l{;s;_J>bRY*-w5mUFbocA@C&Yd`1?(%zuP-3g!H{Mlwgo2ued za&52bN_n}{fNB;=-5@iAuIg}=$d1&6`m^7EC&xlkyw=S+qJiRg2dZqjGb3Ei;`Div zlw4Wk-vhL@b%XelIT?>EKqGfjPlu&vmwO@RCTgzQ-<$TEm#W#uMtM`Kta=zmv)g}! z)8G0Q@?%jl5V76Xqki zexHTo&n2_m)4Q$uR2}DY;W84qT}nx1oTy8%1v^MP&%8cirTyGvN0TP9(ubN5%Fpwc zvtlQV%IDlpyZBIi%7*e$Qr=avoJF-R2NURU(jJ2~EkrHrp4f=e4chHOf{66ORCPF0 z-j8E^hGViP(sK399n?@`t+6wmSaR}ej&zawAB9~aY|Uh{*xo!7q0;-s5`S$e{#5Dq zxXgcHWL!}06%s*M=0A|&ZEmxQl-M=5F}L=P2c4!v8ASj>*nf2C{QR*maeGvLDsh9~ z3X{ZG3=Yqkz65h+j{O|6QTYxGM-7dp=F?W&;I~}2$0hx=9vrp9wi5lep2I-~mTDB5 zH-9>)7BifzfQ>Tj#t-J{iyk1B6!G)7`YSOo@C~9CE&brcZ?J=?{bM$&%zz#~J|tA` zeZ2eAJz^Tu*t01`=r3(*Sh;sgb!&c%{Zmor6-|G(RQ5Fv4gLmTRn^e3kP8?Tbwq~C znow_5i?0WgStUNpm1-_)4M6l9I+@?&4cW*TJdNjqI#5PrHC$XJ&nB5G25uX3Z0*~2 z8tN*Mzn#7h1RjP6G(HHKaC3kdJY|?c8T;Bq$iW|1#thI}N~S zP~Jf9oBh{@zRPv{S*!kCPWFB@Z5FTqcgzD06ea{^j~p ztzhbK+q#>D$MSWBAHJRm_xapNhniFxljMU1RVsmsu3s;z^%>8#fqk(@h8}kqkJ^Pk zPtFX(CP9tRxyUXP0AX;CjlAk+TZ-{<2h`@+~!h!NLR)R_ASy7A@f- zfSXPRgNx=^%v!rQrW+cCOgV7!#@s(=s9Ac32PO+!UxX5|r)o`wf93kIjKWM#(XvqV z74h|L)`ij4nvP1hJP}FnJ`|l|3e41yQRgoGB1sxNV5;Hf#y0n1_p_NWL-o?` z;3^a~F@x#>n2be?34t|i`oDqZ^bOe4b}M$WjQxsAsH&DUA0abGCiq9xP|%L?g(NPw zoVx5;5_(47qeod7{o?VGy>i)^?;+moUCAAwV{ z3~5&d{Jw75wWv6jvIM-B)SuV5RPOJSez&^_(Ycrt z%eoItD9w|&tKCIo?{}OF7h*sV^XT6n*wm?ZM3(pUjx>&6OMJ!Nt$J2-GX;qI#4unD zb@b#C;p5l6B<#aLxd&)yA^4y}r&~$l7ue*xuaT}^R7vOxB{Lelhu%&+1>K*HNquls zR8F!}JBK&hpthjq{W}EAIN<1P1(x+ z)56l)sb2Zy4T5IEX+KZGR3K=B`&08r>-vL%aF)1!2WL3(h>&L>bDlL#ww3id%96-u z%^5Jk4ZgP~QhN%!^XF+gSA66^XL&%^3hbhzJ%Tu<+`MzYd2QCI0Iazs|%D2}I52cNJhx1zg@Le8R zOV21iL<5uKSpEssOJw3fXIGe>ffilOL-p1Q-wP|)o2$-nw|zotruvvz#0dX|F7hIQ z5A&=E=~C~!qNuElU+oY)!0i9sMzkB5 zg*6o^#_mmE&1C`9s^N{B8*diV1!0Rpn{l%2!Fr(VIeSBFO);mS^BwP3nh!@Wq?_9= z={7syT{}9kNE2L=Qy(1RcW+F*4!toKP0=FN4wR*1?{vfedLTl2^3!?+(g-5oJh2nA z5*_NLZ^B$|bbZddGTFexe8%7-df|Ptsw6<)``LZB`4J72;H7s(m6@TTSX(e3mrwd~ z$iEvT^9~4K&mN4`s~%b3?YM=;%jwGM&vT`t84{Ut{{PY?oLNN3-3D zuVf`D{&kS+=Q3>AY(VexTE3zdK2}(GtGy$EGo% z!0Z{y=kfNewTwr31!U~RMyyk;yTyV0&g*FA9CYuUK ztz7#J2tZDw@z0)9CJy)^{BHZ@ShTnKCs;h?H-Jc>f%${CPv)+FvUQergX4|-!{5&* zKX&B-N9PQ)5)Z{)6S6Glg8_}e{K)ZjB1FFO02jn%<}`4$_}s#aCNWVd-yyBu^K81w zljBwcox^2Mc3tyTzH0V6A!wlnz*cwGWA;(2bs#~AN3_X>o<+t!e&qr5_n5294zspT zNz^)LZ*-!%z@fkKTz1|6+u-Trhn%|2<*G9npS~u}YibjM6dw*(7*unO2fi=?*%MaRrBk7fsc6Q#@{GoM; zgwE8ztgF!6E4^%YB*Am9#b@K}a|2q+2cQE>5p7ASb4=FGk;$o;3>m50RVmi|bQuXZ zx5kwlz{9jVU+Kp8Rf9;N>AIR4VKM`y`$nDZ0WRSwojYa}z8}HMIg0C-ITMUpgp>B1 zKYx?PwPX}!qJ8@iM4(%y@rlJ5DHa%gugi@l$Y9f=3U8SNsp*p5)iW5VJ=X4cgNwqpEAPALZhRmJZVX zK%x8U9S9K2v?-t!bLer+`MSf&7*<6I4&s=l z=6$9guoZmnAcsp;RC%mF$lvBp(MCI@)s%d`#C>~l@syWdQvr_I>+t0X;IA78hN-C> z<>Hq{Tn@z@Qtky@!>371j9gw!x%WNZRn)1I3#+4h=q3_(wICJA#XYtcY6qW;RbuF@ zh}&|_gS9|7#(y!p?8acwpz|QbG5q4=9m?+{aEF6h+;8UO>;UAuea^nF`KENUk zH4Z) zmBn5(WPYbCZ0Im0hkIKc%T{-(gw3s-=1n?czQN3Tcmhj#HyZ42hZ{mPwpeaKi6ii` zNfLwi-AxyDAL94kz0L4&b^dlQ7fD36%ksxz?dV6Zmu&KPehpDVj5J%jA{Up`U5zuX zP#yxIBPDq`9$1?WdotWtQW?-R&%i8}g4GZRCX`D!!gwX*)AZ$G9H#_25z3s1(X+ud3KL{=~X` zz78(Ooi@X|ZsVNe_v_z$pis>Pc>tVzI2r4k7P6_wkTtlx3`^OFEEgJHD;YN6+-)f~ zQxL0jS3W`JdQNsoOv)p5ZLQ6rqpeNa@Du*Bnx&PS+K5NDgGoJ z+s#{W>34jfXvEpJi{KysVEY17WD@JR>IOm#Gx9MpO*a}o_{!IV9gVjnE1qhiS);V<>YZn&hx9Th|PXG5mp zsZJL#KchMQ;E&9YEuCo*WTW3JE#kIXuwp_M0o;lAmu}1~)9&7i*$*^t?&?D-L^5`Z z*Xw##a_Z=;pshT!zW?1zxjQ@wedZUfmcPF|+?%cjtPu86kO#`+ez?G&JqU#G*3~XG zYceN@m?3?#4|gd)7ETR>K7y7{ZD-2J?zOg2bTVN@w({U}F%TSaXZXttr}W;ilrd2w z`Nb%e-P22>t)Hvq$x%wegnlShxp+9AJF4%dvRBWduh>FHaliduqv%B+d%s)i;K@n^ zHK09s75lwRM+ykNQ0Ta{wYvaFgjmEYCClOyl}aimhS_jNEbU=*g>GC-GDJ|Wr=k{XT7oly5 zjOap1bK>9=oBS^-Dlp?e_9IVr1q)Rnc6tQUN0#DY*;qSg+SVu?fmLe{ZlwlYg zhUdh}Qt48HBGMCuj4!ZD7ERm^>xo9wnzl3Jq`tzC;kAWTIB)$M*^%$A`mvk0FG+sz z{`9Tjt>F(9b6WT>t6sf`>w1?A*_}VZI;4ZgF!!~FiJlV=>&p6>`_~-tSTk<(867cW zGM~`5)vbcm{2yyOXGLkKTTF&QH39sUYjE<1wQ@$oj?^{(6_syV0%Vp|`8MI631te$ zXP;H=JP_=vPfxgGA|1e@)@M>uELv)j@#zT-mhh37 z{Ta+M(5>9D3%*~hz6(iz4<{k+8E3+ zx+=bjSzDsA-8<}l%>lHynEsrq#`lUqQ{J*vLnn=%Tz9(Ng87Bt&oWh;`j&r^qn zus*_=k6+!{>mY7xWiRFUo#P20{Fhv%Tj2b?BL>qouqXGL7IvM_2m<8imS>m zxvAFqUmG$Mgk&{2G6($5p#DjCl<$d|Ce_!9{Oo&>3Vxucf2a2n*lXvNx zM!EVE-kC!+q{z9-EhOKIld>+-Y+2L>G_X-clg2BhBMPJuD3MWa4)=CX=B{@6+gv(E zJGO=~HJ-)PP7a&%#T}kTt6JjM!n#4xCP$5{%rP&1^|6^#s!mTaM3FknCM`6>D?&Bj z5i)zjbdWyi3s^F7}IV zZgq7Sf%}M*&*a2&*<}9cXUxwf>=#6Cj?;TXEknCl@e=6Hmbpv#p1*$u56p;&H|-x!xSnZt71AfPW0i8o_*?Huo~-nkgJtlMxZ4@<_v0Z6 zX-ThWN1P61CpCp>d*#i8E(&r>7`1=nn}Reh@>RJw3sBG*$=tiQk1q!2SLgmbwig}^^U4lG4OC~ zA=u@~Mwv(OS2;_)xsR4!GE>H77Y`&J?poLm!9}g;dfyK}%r4%%3eXGM1`f-z0AX@( ze~Iiu($KSWB|F=4GBZ(KABGw{L0h?mk5!I4BlHB(Byg{TttzWVey9w)qB4I@srhxSq=&{*?L1Y3vN+A38t$LU4DP5u(9M-?L8OL7u5_xM zbQG7xAluXvd{I!3z;8?=^YE%bEi=?MwSI$%KLy6k`a(}K8pV(UU^yFoEScPB(+q(J zQl3h~iQ@m!mp`0&N{UG`TS9N0Um+`2aXs|p*C@XtJqWWM2Gg}wA0kTuJ6#<^4IS}y zXy~VPuo&bgs{bSo^<}Al`=ZiM;+Gg?`VPn%*o41YVD9~`Bt43Gh>mPkp)>dEGr@0A;{2`7tN!@V9R?ZNy&X_5Xs+$%NTAKzi%xG!&8R(6F+TRFM>?*z#R3-p zJlg~uA9vc-ZXp!~?;e^lQ&)N_;f6O=`sayAAO`w2ffxte84~6nJrLG<`;ox?`TP(x z*ddso`j!BfE5j=?U3_l%G^`f${Dx$WK~;V&5&76rrfr^-jxG9~YQa9{EH7)XHbhT>g<^SF^I^!$EKMsgFN4nG@4e1SL3d zuFNYv&d=;QPxK$(a%A)K7SsFeYA?VJwq__xIHq<)K&za;*VN3+BmO*aAA4-dsRAJw z3Iqv0JA6<9#`cv>-b-NWPK4BZPbrql1^?h^{TZz&l5=p#{mrkDg-=lVm`X{i!RKuq zcRG#_V@=!UL)y+FPl$FS!R(;yhuzgPwTrN5T1g=~TFaLq%6qgqzC6&!1-RSHkc~k= zdQ<_TJ2NLswXu79VbVdbn7418f)qH(`(3=xS%mJX3n{ph45p_hI;QrSQ%HbCbg_&ubpL0y!~f76)nE5kY)9Xp?VsX~XUq97+WtG*)p636yGq&; zQZoXsgfgNT^r5s~=~U%k1Nt)}7kI`yoV(T;JN_|LlC)?XJ(W&7*pv{X+(#n@0OK%z zKE4RkKW(O3T0ZAp_yap{C9HpwB?o)8F!_U6$C(Vr~DCd7M0mI)Td0G0ic{jzl@o_|)udJ-N|ED`Y=2xTs zUwR6PmmB&WK_<~Bv~?-aCKLUKtdUr~U1-qVNy&w_9!C)U-Y|cq4Sa75wIBqNK5k7l z4>C$5x)T??7PJ%Vfz#YkySpy6Sr6anui?u_?B11}=9OJ#i|qQheLa{022?JnJ3F7G zT_n#JF%L9*4xLvje7d`wdHz>~9zDCkU#tTlp}q7ZLayn5^y_BGgK0Ch>(bX@&aGR< zfj-lpsyK4x^c(2siRLUj6UBl4)m_PJa)?@Rl5fHWSO#1gD590(rI{$4Bm5WDpvx&`>6=w|Byg-Yz_QB|A|sca9~UD#RzRdS?eR(d l|5UX64`=+}!k4R#D03TYl5DzxM->u=>RTBx=(j5ZQ4H7eS%TP*#G$%HK4lpnu z?_Kx)`|hv%px-PQwhU;_9PQ+ZRnq% zGtki3N7>%n*2~$$$JyNt4b4B#;H`(3@6Dxw2mES>M~k0lYI543_Knc2D0GW&TKnY~ znpa{{tCXm|=$xn~OWqb_5Msz;@bX0+hwzIAsTKLS1ko1_ZRjyo z47|yC75W38N$V#5SW6W-QQdK#R_D`1cOI!;AuXz90lr|0B?&*yLn1Nw{%w0xh+b&w zUyxrw3^e{EuuEx^J_=*pVdIs&2XUEn)JIel5J;h;p-GG zVu6?Ue5mVjue+uT^f7B!Rac%2&c@Rx^M&RrT6sh3T#Qb9dglcXAm!bkJWf4WFNZ%b zlW@c{Wxdn;b&G3<>uv`}hyAaIZI*AYrfLZYh-VrSW>CyZH`+H-i*K&xdmd5${<(8} zSgekADo)B68{#2-%~9yYhOR>KzoF|OuK$LG(Fn!8{q`PlKyuTmXmiMQG*~ODyH%7C zC9}9zFxYcYuc!320iHnB{P1q5pyxBf>Ja_x_jzx{=usaIlYEdG&UzQhZ56q{55GIA z;Yyhs)>LE9J48?roE~qOOm;=zd6aE zuIa;w0&?^gR4^^bbMA$NSp(Xnn5yyd2<^@;Jn}$HknCm@G zWK8}I#31ku-}PhB4G+BIb{qCDaHRH9I-YqugD{J(i}(kG{w*?10Ci}L8WG1bm54O5Toe*h^?b^sPw5z-h0GWKI!Zrhq72&SaBRDx$gfJ8|MpdhXHZtA|6WTnkY58tEVAdpcGs(v&l_fVMQY88x11#D7h5eEdx8x9mK~Txi8QNEbAJ97cX8ScyCL05BLrBj?0Rv=i z3tc6oQ`D%yBj1ldZhK*b;_F#rehk@sovOey^OR_pp7&*W0WzToIYX4#W640RVv#yC zx(Y^K4x`6ALiJd4O~4m_j!z>bzhpC|lC}Q3Nr(*7wCe41N=jitN0FSRx^Sixh+tYG z(r%hbR?m=w;lIaB4eaf(%OAOt6x7Lmw&cPE>P=fH3)-_M8P2dwjQNhcJRZ9$Aefne zaJ~-nL*;Lr9Unix>_`dNecAy(S<(9zr0yWdkt%q?6G=W~0Ft8wU(FkNK9vGXlUgS$ z60_QO;e(qVGb?vKURvz{pG)`_Wy@v#OTxjl%{Ov1yk2OaL$XwWDxiO+a1At z{LNetF?SNJ&8ZTU!pJCr!Pm7Q6(r-ED}>FFn}3kpj3e!m<38x?Al=r~3djl>XRi{m_0;2r#oQ;o zfaQlIW`zJfrud8c+K*~Da9QC-KZ=?^t|N$g8@n$=h~1DIo6Uyle4iJ2Jc!2rG94(d zG#yFp1KMItt2KYWITrpm2GvNsoVy&v<=h4QA}BOII)SQ;(#o-}Zx7|84FBPK8RF58 zcuCTyANSnEft_uZJ75UUgv;Tq>q=4Y+|pXK1Q8~+o;;`z<&{$6bmnELw^kKKOe?sW882cz7Aq8CwLneF0GWY%K;m`4fxf>NGM|Wx zV03ERxyjle)$7PX^tI`z!2#(->#dW@ngkORi8|SxA?6sh^ z_rh1^qSx+8Hj20Q2&W?+Z6---g{f#lTW)?t&YqXgHA62Dh~!$RK8>)fQMSe#6^D`F z*&FW&nbD1HB)&GgJ*ob#fY|7=7wD_e*>W^)*B=HYg`szgRJ{K;TfA8Gt%QOpCDxxo zdQwHB=92=akx&S!z+~NE7;$CiPmL}QFpxRpjomvL!sc=90W@}{!2W7 zp%O(({T0jzALmU=H;LD~RVN5FamMYqsfw){8B2~<)cYL8Sm~#rp^8z^!nmnRtLc@t zaLxt$akAP)Y`<-Y3CrZxAp@$A(AdEGJ5VdKQy)g!`F2?W%#FW(bkgj*WZcP!mc5t9TkE2=h=+uL3)HM(MpG&FK(<3grGocn6r zmq@ZY7^SxYhCve6*OhGt$7>h@>PHdmS8O2OP>$a+xIk!Tp-0Af6x@LAUFtUUCa@5q zrExYD^|nem(eCR37up>?K$tM*;8tN1SLiq5Pp2gi-+P4Y_cHW&m*%#=l%i3hElyIm z*9pSjV>}S^NP~p33G~60`bhb{Gx*=QktKPfnISjfR1kYfK=smL{nbzO4(<7EN{9kpiyHvI^_egEW&_ zxK@=`*prxv?>9+&i|d=IRf(8a$_+(CR-;%lHApXGXa7Le9GazXC0VDqq(ZsN-(f-f z(Xo)RiiDbIpRvdU^W1_Xr}75NcC?^Yp0}AxohM4c+rN)A*qTM{pH!75L6sDW;9B1m zdFga86y5)j1VU+$5~;DIzl2z-tJ6Cp?UYhK%-Ct-m>cDh&AiiZcvdIjUnE)H>-pHY zNn*cfdBGpt=0-U%J+@d%X(eDp9B`Zt21hVI9t4&DyeFhJ`I*rp+C-B&XlT8qmr+`O z$Y3s3guMvF7`D-aB=8s$a;A+g@eBWJ!b(6_qXCk$!^`416*HWWH@~e@hOH*DPzeD8 z^>v)a8f>}}F<;eUx13C2>}1K&XwQM0x8+_nH83f`*3-m-q-lmyuYWo!wK>`?2>SvcQIr=9Kx-?#~*_mr=mC z-wGPNMHlS2oH6POHoa*>B+&@}m~}TEUOstOS0eK(Is#eN(S3Y$FdO5wJ!G&I>^o5H{CbjI}=PR^&cI|e^@IGB=1 z&m0GiU%h%z2x15c5ssMfLbBFt7k|}ft_oWF(HMqf z>iR9#SH39*DEQ_{JIXWCW5lzCc?2U5duN@AoqKNLMr>1gGgCEoAMoV!(t4?%PhlpB zh4y=SowLN*vn9UeelB9S@3h3g(iFe;k>)l2)N-ba$%IxO*!fbB3NY-3~jar z$WS#gecsIudqdkZ^ac{klF3_pK5&!10iP=70+p*K$5;ix!JB@d?V6IwNnznyres<44+Qd5zTGMN@aOTv=`+Lwj4${_}|7&Xg$ok`1q|XlsKR+TX z4~)Hl+TTZW27e^-OIsx9Jv;jwIWjWMVyP!$gE+IeVKEKr)}}@At_^|qH=>8!yTf+R z__u*9u1vn9=Zt{OvvKKftulV8+ahE=72zD zq;h`e)LA#euL+8n?rz3S0Vo{JPRVZ6!OlY7DM8-;fP$Ok?XS>PF;GeyvDb%^u+g$y z7J4pQJ9?*j!gCXg4DrDJRh{1i&$%QSh@!z%pV>6G&hn#tz}YBXcfSuK+4>S%MV)W5gxB5|%j4}49| zI%r1(5)2c2jB7_3!hoZJL~bn!F5=nEV7I@pgbUT8z&}`qWHsQVT><64#beH_UvfI` z1Buu8S$1qGL2!*-f+XOyKTgF_$(E9Ta56!^_?2R%8S2FzZPXA-lSIn-x3LSL)^^l( zP7M@3H|xD4w0P!wu<^B$k-$pi{-e~%n(-G&MjC%2jO`u;8(kF#f&OH-usF;h!PUf4RW+9ZX0U(9eY|H;>3;UykG|fnORdAh z3;PyVC&7t4bKBdQqzpYme)!!>FyeKKYKAEA;Uuw(a`oa`6;`5LzEIar1)ql z#H5|)+c$@eLT$}&`djlrxzE2no_s2>6;Q>A@$jOI4spbb) z`|~_mq8^Tg!w-rYp0ve!Cg=AlRMb!5E(yv9ou_i%qv-~^veA*uc>jwTT+n(Ll`!pH zhv)eX;_lN9GU{_#(wlmJDNmtWxSgdellw*2+!%0hKNnrY+lobiGFH(79wRiHqBg;` zonRdy6(qYXiz~7#$WQcDXwP)qPy%(j^-uz;`%0&th#XWrJaN{Am9G;yImzeKDA~|c zl2qVydA&f_IDjYcTv3)>(Yu0jnf4X8_-^6Yy!Yg~!#IH}O`B@~H)_Mq8pqz7jC4-OeIdG}#JfYa`n;HG}06svV7*TbSG%Ds;M|k_m z|4^*2j0vR-OJRXhOv?ov6iz2qRPS8fW_2}0kw&cJ{81R1z48MbuTD+3{b(cInU$(M zxi2*QVLXt+vxzy=9)qv!qv}I`&T=_lk)cM18XE!;#i15*1u255`y>@8H>s6eHrk)z zXAj^WeUQkhb6gBeWD<>rx&yaiO&r4|ts@D7psQkX>iYXz{Oen$54(l@ zrijCoXF(Sl(>?j)hz_cY7PM>eH$;CqzcbSXR&mLpK5}kOfWG??mc=2;xVph!B?fWTABIAY-RN;lgYX+_@@GqFb0*OfK^ms}PAB055#S9cyiUpvC|*=wz#Zx7YDA~-?h-`Q z!at;U;A*oqmAT`_jaDM0Q&zt8B5L&+ic8?p=hoV@?qyZ*PTv z-*Sh3`l&KzbMVirD8VrJ)1cbvJHnwsdb)AWQlf&3)^{r%nB5Y*iK_hP=k=uV8il`Q zW){~}{;9m=z9sHF=WE2auY7!oPJy_-3yi`nopb{#n&ZeUzH9F7aA((lu(*0&KmgEZ zu36l(*F?h$>5PKkdB`2RM~VEM3o$%-e}$i|rMcwzHN<_O+m|GWO`zY?B}aE=U%^dJ zxb%zmV{mw4h|z_D2bL{MchHIifc2q z0o_~EJmaxlW%PN9m>Rw8+@Xo=%5yX`bs-duRHBL4rUzxaC0oCmW{xs&quD)PX?!Zp zsDH|fRq`l~s!iC+|JrjMomgl%-`5u2hFVH0KC-YEDEN*Z#VGyQE>rHcJ=%VmmUePt z%%Z9wv zd$gs`3ijw%!>GHa`GcjE$o?FRpSF5W>YKzIf-d2{RPbk{gwC@9h~lWa^Ou%$Ml=(X z?~g(!rsRVRNKAj`rYg~uUYVrqE( zrbWJLvBYUg*)C(h*LqfIE18{-^0esEJe@qRp-1V65BBFiEk8GD)%#-Be4}3)_=0(; z%=srz2_sUuKTmL;`a3yf(mw;^&^Xb**x>aYSO3GTl zDqayEsxuC^(a?4!CeZG4l0sn#by2%?XbogEC^TZ^w2MwvJpYkg zm94s>h-|J~9B=dIdv2}qO&3?i*A+ywsW<%2;}2%N zbsPsvmmEN~-{)xi)wP**9)zeS@oZkCEle{==e;E?)z7dJxiD!sI98go8_ zua(~B;Qd*2m1r0rdqMD^x~fiB^|Dh;w{gn%mX8Bso;+IPQMG)TSgy=&YO_hAtZzOn z?_6Y?QzSenP63Yn!6b1565B{r_Ak{K%%+p<469)gBLzhk$h=$d9=rK9>{qZqWqM(5 zlof3tb}7eE%Zc=->#C;g;DgFJPH8}``)4f)g_19dcNNe8$__? z%SxK<53{m^P**TdQ!0{=y65)Xtgdq`id%9apD_2YSy$;I-qNaAe~%f9#pD1f zM-$bE;2@UUY76AP$gDLItE16XqATtC$I>Vf3H_Ra&z6QoQ&sUZ&G%6IdDc$&MPu7wCk2HT^mVPHAVxEYgP}r@zgqO=^&D{BCpjn#XGz(fJU3B}& zxO@c|bMCPh8}uK<)mf_><%KuTzj1Q&hTsda7hLKT;nMh?58U2KeuSQ%ZD8rpsjV*& zUJm!WnD#4g^>uEE7zVdS+DGNQYMW_rX0aYWV_)_g-Hj<3iR7arCzHMNrYsRCh)Ak& zRnXDl9JUfAqR$F_2IR8!_B#H8{e{@~3fo!_l4wohW1qb>E8=` zPWdD5&Iso4;KwlkYiQ`l6C~K|2Jy9ca}&N3YR*lc7F+ z`^!K`!6+3wvzcDy{U#RA2&H4cddzyc;t&=6Bwi1}j9J0{TuGH(K|x}OrhP;XAQ&pa;W@gIW2M$-+Qm!vDrRWN1lDs)Y2sNruEc0N1ce)CqOW}B?5K_I z+s8pMF0%stfm)|qU(pG&(8b}ci{}p3`g1ti2Ltwwl(yF!Zj2v8WbfWV8z_QP(-cG1 z&Zz|2ph6+-Be#nYG8W}Ix-sVv^U08Cz&Ardn#cN!1N=g%JqbXPo*#+DBevb-hNASr zL4_mqI+Fv>8!r-t>-=3s6POXo( zwMJkpfHm*JM!u0`350agQji>O`!e)9UPP@`RjTpqoHrh9#~}^}KpMapavnb z5@n>)`pnbTXR^P4B_OQmks0;SfvdyjQ&Zu}JAaZ<(|6njkl-`t%3iA-TL@E@X3fLc z5?*>V>djTm-)Bf*V@Pdr_x?5noYMOw) z$K`FUK1;CaBc7;Ze?|_T^Grf>dmysd3|NjNDI#DBlIfsVG#a(rwcB>b*aTL4724f# zD9;D_G_A}87n0W;j;EA^^K}R&qV1g!9=y5q$cs3gfxJ%uM)9IcIPoG5Qf>HE>-5^d z9*Y(0v@<7kCz6(kMh=}4T5patcJZ4U)dWYs+$8xy;?Hxi{l>_s->pS7 z_^$G>A%QAQ(DqG)BOfxgMxUvj`8AgkbyOTqsUKPb@!|HXN*v*zPRAOX2KR4@kx|Br z%^{&!fG)0ax~?AKsNo(-6I8UnwwiQUkPyHk6M5ar3ptA(EV}}q6%SH41o%7PANv1_ zg#Wm?7jKj3=K7utj>3_pygYQ;%+1Y(Ai~3#{U%X(ot7kh;?RAp4JVE_X;z=6LXjQq zzm&ENN~UY=OuVoLtS~GgE-a68<8cEqs3X>K6g-1Bh6r4KSH^VqUnKrVDTwRhdedxi z2Xp8{vWnEe|b2rmepWss;?hE9GRqn^op>0MT*KC zVtag<2wuGlEBgXis~&!cgdM3MYbgK2dH=(9QJDA~>a((D9v)BMLC`c*bd;+V-$ndC DYr#pF diff --git a/icons/obj/machines/nuke_terminal.dmi b/icons/obj/machines/nuke_terminal.dmi new file mode 100644 index 0000000000000000000000000000000000000000..298e01c77cf2d7cf8d4e393f323d9228b8ceafe5 GIT binary patch literal 4866 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 literal 0 HcmV?d00001 diff --git a/paradise.dme b/paradise.dme index c75e5fc0c2c..5847ccb02b8 100644 --- a/paradise.dme +++ b/paradise.dme @@ -414,7 +414,6 @@ #include "code\game\gamemodes\extended\extended.dm" #include "code\game\gamemodes\heist\heist.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" -#include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" #include "code\game\gamemodes\miniantags\abduction\abduction.dm" @@ -756,6 +755,7 @@ #include "code\game\objects\items\mountable_frames\lights.dm" #include "code\game\objects\items\mountable_frames\mountables.dm" #include "code\game\objects\items\mountable_frames\newscaster_frame.dm" +#include "code\game\objects\items\robot\ai_upgrades.dm" #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm"