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 7dc984584b0..3838552714a 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, "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..c656826dfdb 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -16,6 +16,104 @@
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/announced = 0
+
+/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) && !announced)
+ var/message = "[sec_left] SECONDS UNTIL DOOMSDAY DEVICE ACTIVATION!"
+ minor_announcement.Announce(message, "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4", 'sound/misc/notice1.ogg')
+ announced = 10
+ announced = max(0, announced-1)
+
+/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 +541,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 36bfd528e73..9073f56ceb3 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..7c77ca6099f 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(GAMEMODE_IS_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 c425ec0edef..4f1f12b5597 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 492998e552a..d97fd4f836e 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 2c5fe1e0678..33c33c2ab6d 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 c51cdb8f3d2..3bdd95b648d 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 ddc1d7d70fa..5f2de47752c 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 dffa670d470..ad325c6a674 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 99542ffb526..5dd9ea3b09e 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..b8ee00a9a5d 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,77 @@
/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)
+ occupier.verbs += /mob/living/silicon/ai/proc/corereturn
+ occupier.cancel_camera()
+ if((seclevel2num(get_security_level()) == SEC_LEVEL_DELTA) && malf.nuking)
+ 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(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)
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)
+ 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 tracks the AI back into its core.
-
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 +1349,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 7dd4c6561e4..9cadad8834f 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/obj/cloning.dmi b/icons/obj/cloning.dmi
index 179ce985814..8699f6edca8 100644
Binary files a/icons/obj/cloning.dmi and b/icons/obj/cloning.dmi differ
diff --git a/icons/obj/machines/nuke_terminal.dmi b/icons/obj/machines/nuke_terminal.dmi
new file mode 100644
index 00000000000..298e01c77cf
Binary files /dev/null and b/icons/obj/machines/nuke_terminal.dmi differ
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"