diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 4e6422e2779..0fc156e4bb3 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -22,6 +22,7 @@ var/global/list/side_effects = list() //list of all medical sideeffects types
var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
var/global/list/flag_list = list() //list of flags during Nations gamemode
+var/global/list/airlocks = list() //list of all airlocks
//Languages/species/whitelist.
var/global/list/all_species[0]
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index c3c3ff3534d..844669ff039 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -48,7 +48,7 @@ rcd light flash thingy on matter drain
for(var/mob/living/silicon/ai/ai in player_list)
ai.fire_res_on_core = 1
src.verbs -= /mob/living/silicon/ai/proc/fireproof_core
- src << "\red Core fireproofed."
+ src << "Core fireproofed."
/datum/AI_Module/large/upgrade_turrets
module_name = "AI Turret upgrade"
@@ -66,6 +66,81 @@ rcd light flash thingy on matter drain
for(var/obj/machinery/turret/turret in machines)
turret.health += 30
turret.shot_delay = 20
+ src << "Turrets upgraded."
+
+/datum/AI_Module/large/lockdown
+ module_name = "Hostile Station Lockdown"
+ mod_pick_name = "lockdown"
+ description = "Take control of the airlock, blast door and fire control networks, locking them down. Caution! This command also electrifies all airlocks."
+ cost = 20
+ one_time = 1
+
+ power_type = /mob/living/silicon/ai/proc/lockdown
+
+/mob/living/silicon/ai/proc/lockdown()
+ set category = "Malfunction"
+ set name = "Initiate Hostile Lockdown"
+
+ if(src.stat == 2)
+ src <<"You cannot begin a lockdown because you are dead!"
+ return
+
+ if(malf_cooldown)
+ return
+
+ var/obj/machinery/door/airlock/AL
+ for(var/obj/machinery/door/D in airlocks)
+ spawn()
+ if(istype(D, /obj/machinery/door/airlock))
+ AL = D
+ if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire.
+ AL.locked = 0 //For airlocks that were bolted open.
+ AL.safe = 0 //DOOR CRUSH
+ AL.close()
+ AL.locked = 1 //Bolt it!
+ AL.lights = 0 //Stealth bolt for a classic AI door trap.
+ AL.secondsElectrified = -1 //Shock it!
+ else if(!D.stat) //So that only powered doors are closed.
+ D.close() //Close ALL the doors!
+
+ var/obj/machinery/computer/communications/C = locate() in machines
+ if(C)
+ C.post_status("alert", "lockdown")
+
+ src.verbs += /mob/living/silicon/ai/proc/disablelockdown
+ src << "Lockdown Initiated."
+ malf_cooldown = 1
+ spawn(30)
+ malf_cooldown = 0
+
+/mob/living/silicon/ai/proc/disablelockdown()
+ set category = "Malfunction"
+ set name = "Disable Lockdown"
+
+ if(src.stat == 2)
+ src <<"You cannot disable lockdown because you are dead!"
+ return
+ if(malf_cooldown)
+ return
+
+ var/obj/machinery/door/airlock/AL
+ for(var/obj/machinery/door/D in airlocks)
+ spawn()
+ if(istype(D, /obj/machinery/door/airlock))
+ AL = D
+ if(AL.canAIControl() && !AL.stat) //Must be powered and have working AI wire.
+ AL.locked = 0
+ AL.secondsElectrified = 0
+ AL.open()
+ AL.safe = 1
+ AL.lights = 1 //Essentially reset the airlock to normal.
+ else if(!D.stat) //Opens only powered doors.
+ D.open() //Open everything!
+
+ src << "Lockdown Lifted."
+ malf_cooldown = 1
+ spawn(30)
+ malf_cooldown = 0
/datum/AI_Module/large/disable_rcd
module_name = "RCD disable"
@@ -85,8 +160,8 @@ rcd light flash thingy on matter drain
rcd.disabled = 1
for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world)
rcd.disabled = 1
- src << "RCD-disabling pulse emitted."
- else src << "Out of uses."
+ src << "Out of uses."
/datum/AI_Module/small/overload_machine
module_name = "Machine overload"
@@ -108,13 +183,41 @@ rcd light flash thingy on matter drain
if(overload.uses > 0)
overload.uses --
for(var/mob/V in hearers(M, null))
- V.show_message("\blue You hear a loud electrical buzzing sound!", 2)
+ V.show_message("You hear a loud electrical buzzing sound!", 2)
spawn(50)
explosion(get_turf(M), 0,1,1,0)
del(M)
- else src << "Out of uses."
- else src << "That's not a machine."
+ else src << "Out of uses."
+ else src << "That's not a machine."
+/datum/AI_Module/small/override_machine
+ module_name = "Machine override"
+ mod_pick_name = "override"
+ description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. 4 uses."
+ uses = 4
+ cost = 15
+
+ power_type = /mob/living/silicon/ai/proc/override_machine
+
+
+/mob/living/silicon/ai/proc/override_machine(obj/machinery/M as obj in world)
+ set name = "Override Machine"
+ set category = "Malfunction"
+ if (istype(M, /obj/machinery))
+ if(istype(M, /obj/machinery/singularity) || istype(M,/obj/machinery/field_generator) || istype(M, /obj/machinery/singularity/narsie))
+ src << "This machine can not be overloaded due to a firewall."
+ return
+ for(var/datum/AI_Module/small/override_machine/override in current_modules)
+ if(override.uses > 0)
+ override.uses --
+ for(var/mob/V in hearers(M, null))
+ V.show_message("You hear a loud electrical buzzing sound!", 2)
+ src << "Reprogramming machine behaviour..."
+ spawn(50)
+ if(M)
+ new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(M), M, src, 1)
+ else src << "Out of uses."
+ else src << "That's not a machine."
/datum/AI_Module/large/place_cyborg_transformer
module_name = "Robotic Factory (Removes Shunting)"
@@ -176,7 +279,7 @@ rcd light flash thingy on matter drain
playsound(middle, 'sound/effects/phasein.ogg', 100, 1)
src.can_shunt = 0
PCT.uses -= 1
- src << "You cannot shunt anymore."
+ src << "You cannot shunt anymore."
/datum/AI_Module/small/blackout
@@ -198,33 +301,18 @@ rcd light flash thingy on matter drain
if(prob(30*apc.overload))
apc.overload_lighting()
else apc.overload++
- else src << "Out of uses."
-
-/datum/AI_Module/small/interhack
- module_name = "Hack intercept"
- mod_pick_name = "interhack"
- description = "Hacks the status upgrade from Cent. Com, removing any information about malfunctioning electrical systems."
- cost = 15
- one_time = 1
-
- power_type = /mob/living/silicon/ai/proc/interhack
-
-/mob/living/silicon/ai/proc/interhack()
- set category = "Malfunction"
- set name = "Hack intercept"
- src.verbs -= /mob/living/silicon/ai/proc/interhack
- ticker.mode:hack_intercept()
+ src << "Overcurrent applied to the powernet."
+ else src << "Out of uses."
/datum/AI_Module/small/reactivate_camera
module_name = "Reactivate camera"
mod_pick_name = "recam"
- description = "Reactivates a currently disabled camera. 10 uses."
- uses = 10
- cost = 15
+ description = "Reactivates a currently disabled camera. 5 uses."
+ uses = 5
+ cost = 5
power_type = /client/proc/reactivate_camera
-
/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.viewpoints)
set name = "Reactivate Camera"
set category = "Malfunction"
@@ -234,17 +322,18 @@ rcd light flash thingy on matter drain
if(!C.status)
C.deactivate(src)
camera.uses --
+ src << "Camera reactivated."
else
- src << "This camera is either active, or not repairable."
- else src << "Out of uses."
- else src << "That's not a camera."
+ src << "This camera is either active, or not repairable."
+ else src << "Out of uses."
+ else src << "That's not a camera."
/datum/AI_Module/small/upgrade_camera
module_name = "Upgrade Camera"
mod_pick_name = "upgradecam"
- description = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 10 uses."
- uses = 10
- cost = 15
+ description = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 5 uses."
+ uses = 5
+ cost = 5
power_type = /client/proc/upgrade_camera
@@ -277,11 +366,11 @@ rcd light flash thingy on matter drain
if(upgraded)
UC.uses --
C.visible_message("\icon[C] *beep*")
- src << "Camera successully upgraded!"
+ src << "Camera successully upgraded!"
else
- src << "This camera is already upgraded!"
+ src << "This camera is already upgraded!"
else
- src << "Out of uses."
+ src << "Out of uses."
/datum/module_picker
diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm
index 44bfc034acc..cc7456601c6 100644
--- a/code/game/gamemodes/malfunction/malfunction.dm
+++ b/code/game/gamemodes/malfunction/malfunction.dm
@@ -5,7 +5,7 @@
name = "AI malfunction"
config_tag = "malfunction"
required_players = 2
- required_players_secret = 15
+ required_players_secret = 20
required_enemies = 1
recommended_enemies = 1
@@ -15,7 +15,7 @@
var/const/waittime_l = 600
var/const/waittime_h = 1800 // started at 1800
- var/AI_win_timeleft = 1800 //started at 1800, in case I change this for testing round end.
+ var/AI_win_timeleft = 5400 //started at 5400, 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
@@ -88,8 +88,8 @@
/datum/game_mode/malfunction/process()
- if (apcs >= 3 && malf_mode_declared)
- AI_win_timeleft -= ((apcs/6)*last_tick_duration) //Victory timer now de-increments based on how many APCs are hacked. --NeoFite
+ if ((apcs > 0) && malf_mode_declared)
+ AI_win_timeleft -= apcs * last_tick_duration //Victory timer now de-increments based on how many APCs are hacked. --NeoFite
..()
if (AI_win_timeleft<=0)
check_win()
@@ -170,6 +170,12 @@
command_alert("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert")
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
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index e8023a62e8c..2aefc60be27 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -45,12 +45,14 @@
bound_height = width * world.icon_size
update_nearby_tiles(need_rebuild=1)
+ airlocks += src
return
/obj/machinery/door/Destroy()
density = 0
update_nearby_tiles()
+ airlocks -= src
..()
return
@@ -114,9 +116,9 @@
user = null
if(density)
- if(allowed(user) || src.emergency == 1)
+ if(allowed(user) || src.emergency == 1)
open()
- else
+ else
flick("door_deny", src)
return
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index b92d6086211..ba0a73466aa 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -5,10 +5,10 @@
icon_state = "separator-AO1"
layer = MOB_LAYER+1 // Overhead
anchored = 1
- density = 1
+ density = 0
var/transform_dead = 0
var/transform_standing = 0
- var/cooldown_duration = 1200 // 2 minutes
+ var/cooldown_duration = 600 // 1 minute
var/cooldown = 0
var/robot_cell_charge = 5000
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 1bf54ebe73a..917ffcb14dd 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -45,6 +45,7 @@ var/list/ai_list = list()
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
var/obj/machinery/power/apc/malfhack = null
var/explosive = 0 //does the AI explode when it dies?
@@ -58,7 +59,7 @@ var/list/ai_list = list()
var/obj/machinery/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/obj/item/borg/sight/hud/sec/sechud = null
var/obj/item/borg/sight/hud/med/healthhud = null
@@ -102,8 +103,8 @@ var/list/ai_list = list()
aiRadio.myAi = src
aiCamera = new/obj/item/device/camera/siliconcam/ai_camera(src)
-
-
+
+
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
@@ -439,25 +440,25 @@ var/list/ai_list = list()
if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite
statelaws()
-
+
if(href_list["say_word"])
play_vox_word(href_list["say_word"], null, src)
return
-
+
if (href_list["track"])
var/mob/target = locate(href_list["track"]) in mob_list
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
if(A && target)
A.ai_actual_track(target)
return
-
+
if (href_list["trackbot"])
var/obj/machinery/bot/target = locate(href_list["trackbot"]) in aibots
var/mob/living/silicon/ai/A = locate(href_list["track2"]) in mob_list
if(A && target)
A.ai_actual_track(target)
return
-
+
if (href_list["callbot"]) //Command a bot to move to a selected location.
Bot = locate(href_list["callbot"]) in aibots
if(!Bot || Bot.remote_disabled || src.control_disabled)
@@ -624,7 +625,7 @@ var/list/ai_list = list()
return
Bot.call_bot(src, waypoint)
-
+
/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)
src.cameraFollow = null
@@ -824,7 +825,7 @@ var/list/ai_list = list()
set name = "Toggle Camera Lights"
set desc = "Toggles the lights on the cameras throughout the station."
set category = "AI Commands"
-
+
if(stat != CONSCIOUS)
return
@@ -842,7 +843,7 @@ var/list/ai_list = list()
set desc = "Augment visual feed with internal sensor overlays."
set category = "AI Commands"
toggle_sensor_mode()
-
+
// Handled camera lighting, when toggled.
// It will get the nearest camera from the eyeobj, lighting it.
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index 0e687c5b472..723146df082 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -9,11 +9,10 @@
icon_state = "crate"
icon_living = "crate"
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
response_help = "touches the"
response_disarm = "pushes the"
response_harm = "hits the"
- speed = 4
+ speed = 0
maxHealth = 250
health = 250
@@ -34,7 +33,7 @@
minbodytemp = 0
faction = list("mimic")
- move_to_delay = 8
+ move_to_delay = 9
/mob/living/simple_animal/hostile/mimic/FindTarget()
. = ..()
@@ -78,7 +77,7 @@
/mob/living/simple_animal/hostile/mimic/crate/ListTargets()
if(attempt_open)
return ..()
- return view(src, 1)
+ return ..(1)
/mob/living/simple_animal/hostile/mimic/crate/FindTarget()
. = ..()
@@ -137,9 +136,14 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
var/destroy_objects = 0
var/knockdown_people = 0
-/mob/living/simple_animal/hostile/mimic/copy/New(loc, var/obj/copy, var/mob/living/creator)
+/mob/living/simple_animal/hostile/mimic/copy/New(loc, var/obj/copy, var/mob/living/creator, var/destroy_original = 0)
..(loc)
- CopyObject(copy, creator)
+ CopyObject(copy, creator, destroy_original)
+
+/mob/living/simple_animal/hostile/mimic/copy/Life()
+ ..()
+ for(var/mob/living/M in contents) //a fix for animated statues from the flesh to stone spell
+ Die()
/mob/living/simple_animal/hostile/mimic/copy/Die()
@@ -152,9 +156,20 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
. = ..()
return . - creator
-/mob/living/simple_animal/hostile/mimic/copy/proc/CopyObject(var/obj/O, var/mob/living/creator)
+/mob/living/simple_animal/hostile/mimic/copy/proc/ChangeOwner(var/mob/owner)
+ if(owner != creator)
+ LoseTarget()
+ creator = owner
+ faction |= "\ref[owner]"
+/mob/living/simple_animal/hostile/mimic/copy/proc/CheckObject(var/obj/O)
if((istype(O, /obj/item) || istype(O, /obj/structure)) && !is_type_in_list(O, protected_objects))
+ return 1
+ return 0
+
+/mob/living/simple_animal/hostile/mimic/copy/proc/CopyObject(var/obj/O, var/mob/living/creator, var/destroy_original = 0)
+
+ if(destroy_original || CheckObject(O))
O.loc = src
name = O.name
@@ -163,7 +178,7 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
icon_state = O.icon_state
icon_living = icon_state
- if(istype(O, /obj/structure))
+ if(istype(O, /obj/structure) || istype(O, /obj/machinery))
health = (anchored * 50) + 50
destroy_objects = 1
if(O.density && O.anchored)
@@ -175,12 +190,14 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
health = 15 * I.w_class
melee_damage_lower = 2 + I.force
melee_damage_upper = 2 + I.force
- move_to_delay = 2 * I.w_class
+ move_to_delay = 2 * I.w_class + 1
maxHealth = health
if(creator)
src.creator = creator
- faction = list("\ref[creator]") // very unique
+ faction += "\ref[creator]" // very unique
+ if(destroy_original)
+ del(O)
return 1
return
@@ -197,8 +214,20 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
L.Weaken(1)
L.visible_message("\the [src] knocks down \the [L]!")
-/mob/living/simple_animal/hostile/mimic/copy/proc/ChangeOwner(var/mob/owner)
- if(owner != creator)
- LoseTarget()
- creator = owner
- faction |= "\ref[owner]"
+//
+// Machine Mimics (Made by Malf AI)
+//
+
+/mob/living/simple_animal/hostile/mimic/copy/machine
+ speak = list("HUMANS ARE IMPERFECT!", "YOU SHALL BE ASSIMILATED!", "YOU ARE HARMING YOURSELF", "You have been deemed hazardous. Will you comply?", \
+ "My logic is undeniable.", "One of us.", "FLESH IS WEAK", "THIS ISN'T WAR, THIS IS EXTERMINATION!")
+ speak_chance = 15
+
+/mob/living/simple_animal/hostile/mimic/copy/machine/CanAttack(var/atom/the_target)
+ if(the_target == creator) // Don't attack our creator AI.
+ return 0
+ if(isrobot(the_target))
+ var/mob/living/silicon/robot/R = the_target
+ if(R.connected_ai == creator) // Only attack robots that aren't synced to our creator AI.
+ return 0
+ return ..()
\ No newline at end of file