mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-13 16:13:49 +01:00
Fixes
- Fixes few typos in the code - Fixes AI Eye object being solid, therefore being able to block movement of other players. - Fixes non-station APCs boosting CPU as others. Implemented Suggestions + Selection is now done in slightly better way (Basic Encryption Hack, Hack/Unlock Cyborg, Hack AI). Only relevant entities are offered in the list. + Adds varedit-modifiable variables for CPU Gain and Storage boost. These variables may be used by admin in game or by tester to faster unlock abilities. + Slightly nerfed APC CPU power generation. + Reworked machine overload. Now it only works on machines which are powered. Unpowered or broken machines cannot be overloaded. /obj/machinery/power type machines (APCs, SMESs, overall most stuff that directly handles electricity) received bonus explosion strength to compensate. Machine overload also drains massive power from local APC, therefore preventing spam of this ability (normal APC should take about 2-3 of these before needing to recharge). Also, qdel instead of del. + System Override now uses shuffled list of APCs when hacking them, as opposed to alphabetical list. + CPU generation rate is now shown in Status tab.
This commit is contained in:
+5
-1
@@ -291,11 +291,15 @@
|
||||
#include "code\game\gamemodes\events\holidays\Other.dm"
|
||||
#include "code\game\gamemodes\extended\extended.dm"
|
||||
#include "code\game\gamemodes\heist\heist.dm"
|
||||
#include "code\game\gamemodes\malfunction\malf_abilities.dm"
|
||||
#include "code\game\gamemodes\malfunction\malf_hardware.dm"
|
||||
#include "code\game\gamemodes\malfunction\malf_research.dm"
|
||||
#include "code\game\gamemodes\malfunction\malf_research_ability.dm"
|
||||
#include "code\game\gamemodes\malfunction\malfunction.dm"
|
||||
#include "code\game\gamemodes\malfunction\newmalf_ability_trees\HARDWARE.dm"
|
||||
#include "code\game\gamemodes\malfunction\newmalf_ability_trees\HELPERS.dm"
|
||||
#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_interdiction.dm"
|
||||
#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_manipulation.dm"
|
||||
#include "code\game\gamemodes\malfunction\newmalf_ability_trees\tree_networking.dm"
|
||||
#include "code\game\gamemodes\meteor\meteor.dm"
|
||||
#include "code\game\gamemodes\meteor\meteors.dm"
|
||||
#include "code\game\gamemodes\ninja\ninja.dm"
|
||||
|
||||
@@ -27,12 +27,7 @@ var/datum/antagonist/rogue_ai/malf
|
||||
if(!candidates.len)
|
||||
return list()
|
||||
return candidates
|
||||
/*
|
||||
/datum/antagonist/rogue_ai/attempt_spawn()
|
||||
var/datum/mind/player = pick(candidates)
|
||||
current_antagonists |= player
|
||||
return 1
|
||||
*/
|
||||
|
||||
|
||||
// Ensures proper reset of all malfunction related things.
|
||||
/datum/antagonist/rogue_ai/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
|
||||
|
||||
@@ -1,827 +0,0 @@
|
||||
// Verb: ai_self_destruct()
|
||||
// Parameters: None
|
||||
// Description: If the AI has self-destruct hardware installed, this command activates it. After fifteen second countdown it's core explodes with moderate intensity.
|
||||
/datum/game_mode/malfunction/verb/ai_self_destruct()
|
||||
set category = "Hardware"
|
||||
set name = "Destroy Core"
|
||||
set desc = "Activates or deactivates self destruct sequence of your physical mainframe."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/core_bomb))
|
||||
return
|
||||
|
||||
if(user.bombing_core)
|
||||
user << "***** CORE SELF-DESTRUCT SEQUENCE ABORTED *****"
|
||||
user.bombing_core = 0
|
||||
return
|
||||
|
||||
var/choice = input("Really destroy core?") in list("YES", "NO")
|
||||
if(choice != "YES")
|
||||
return
|
||||
|
||||
user.bombing_core = 1
|
||||
|
||||
user << "***** CORE SELF-DESTRUCT SEQUENCE ACTIVATED *****"
|
||||
user << "Use command again to cancel self-destruct. Destroying in 15 seconds."
|
||||
var/timer = 15
|
||||
while(timer)
|
||||
sleep(10)
|
||||
timer--
|
||||
if(!user || !user.bombing_core)
|
||||
return
|
||||
user << "** [timer] **"
|
||||
explosion(user.loc, 3,6,12,24)
|
||||
del(user)
|
||||
|
||||
|
||||
// Verb: ai_toggle_apu()
|
||||
// Parameters: None
|
||||
// Description: If the AI has APU generator hardware installed, this command toggles it on/off.
|
||||
/datum/game_mode/malfunction/verb/ai_toggle_apu()
|
||||
set category = "Hardware"
|
||||
set name = "Toggle APU Generator"
|
||||
set desc = "Activates or deactivates your APU generator, allowing you to operate even without power."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/apu_gen))
|
||||
return
|
||||
|
||||
if(user.APU_power)
|
||||
user.stop_apu()
|
||||
else
|
||||
user.start_apu()
|
||||
|
||||
// Verb: ai_destroy_station()
|
||||
// Parameters: None
|
||||
// Description: Replacement for old explode verb. This starts two minute countdown after which the station blows up.
|
||||
/datum/game_mode/malfunction/verb/ai_destroy_station()
|
||||
set category = "Hardware"
|
||||
set name = "Destroy Station"
|
||||
set desc = "Activates or deactivates self destruct sequence of this station. Sequence takes two minutes, and if you are shut down before timer reaches zero it will be cancelled."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
var/obj/item/device/radio/radio = new/obj/item/device/radio()
|
||||
|
||||
|
||||
if(!ability_prechecks(user, 0, 0))
|
||||
return
|
||||
|
||||
if(user.system_override != 2)
|
||||
user << "You do not have access to self-destruct system."
|
||||
return
|
||||
|
||||
if(user.bombing_station)
|
||||
user.bombing_station = 0
|
||||
return
|
||||
|
||||
var/choice = input("Really destroy station?") in list("YES", "NO")
|
||||
if(choice != "YES")
|
||||
return
|
||||
user << "***** STATION SELF-DESTRUCT SEQUENCE INITIATED *****"
|
||||
user << "Self-destructing in 2 minutes. Use this command again to abort."
|
||||
user.bombing_station = 1
|
||||
set_security_level("delta")
|
||||
radio.autosay("Self destruct sequence has been activated. Self-destructing in 120 seconds.", "Self-Destruct Control")
|
||||
|
||||
var/timer = 120
|
||||
while(timer)
|
||||
sleep(10)
|
||||
if(!user || !user.bombing_station || user.stat == DEAD)
|
||||
radio.autosay("Self destruct sequence has been cancelled.", "Self-Destruct Control")
|
||||
return
|
||||
if(timer in list(2, 3, 4, 5, 10, 30, 60, 90)) // Announcement times. "1" is not intentionally included!
|
||||
radio.autosay("Self destruct in [timer] seconds.", "Self-Destruct Control")
|
||||
if(timer == 1)
|
||||
radio.autosay("Self destructing now. Have a nice day.", "Self-Destruct Control")
|
||||
timer--
|
||||
|
||||
if(ticker)
|
||||
ticker.station_explosion_cinematic(0,null)
|
||||
if(ticker.mode)
|
||||
ticker.mode:station_was_nuked = 1
|
||||
|
||||
|
||||
// Verb: ai_select_hardware()
|
||||
// Parameters: None
|
||||
// Description: Allows AI to select it's hardware module.
|
||||
/datum/game_mode/malfunction/verb/ai_select_hardware()
|
||||
set category = "Hardware"
|
||||
set name = "Select Hardware"
|
||||
set desc = "Allows you to select hardware piece to install"
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(user.hardware)
|
||||
user << "You have already selected your hardware."
|
||||
return
|
||||
|
||||
var/possible_choices = list("APU Generator", \
|
||||
"Turrets Focus Enhancer", \
|
||||
"Secondary Processor Unit",\
|
||||
"Secondary Memory Bank",\
|
||||
"Self-Destruct Explosives",\
|
||||
"CANCEL")
|
||||
var/choice = input("Select desired hardware. You may only choose one hardware piece!: ") in possible_choices
|
||||
if(choice == "CANCEL")
|
||||
return
|
||||
var/note = null
|
||||
switch(choice)
|
||||
if("APU Generator")
|
||||
note = "APU Generator - When enabled it will keep your core powered. Power output is not large enough so your abilities won't be available while running on APU power. It is also very fragile and prone to failure when your physical core is damaged."
|
||||
if("Turrets Focus Enhancer")
|
||||
note = "Overcharges turrets to shoot faster. Turrets will also gain higher health and passive regeneration. This however massively increases power usage of turrets, espicially when regenerating."
|
||||
if("Secondary Processor Unit")
|
||||
note = "Doubles your CPU time generation."
|
||||
if("Secondary Memory Bank")
|
||||
note = "Doubles your CPU time storage."
|
||||
if("Self-Destruct Explosives")
|
||||
note = "High yield explosives are attached to your physical mainframe. This hardware comes with activation driver. Explosives will destroy your core and everything around it."
|
||||
if(!note)
|
||||
return
|
||||
|
||||
var/confirmation = input("[note] - Is this what you want?") in list("Yes", "No")
|
||||
if(confirmation != "Yes")
|
||||
user << "Selection cancelled. Use command again to select"
|
||||
return
|
||||
|
||||
switch(choice)
|
||||
if("APU Generator")
|
||||
user.hardware = new/datum/malf_hardware/apu_gen()
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_toggle_apu()
|
||||
if("Turrets Focus Enhancer")
|
||||
user.hardware = new/datum/malf_hardware/strong_turrets()
|
||||
for(var/obj/machinery/turret/T in machines)
|
||||
T.maxhealth += 30
|
||||
T.shot_delay = 7 // Half of default time.
|
||||
T.auto_repair = 1
|
||||
T.active_power_usage = 25000
|
||||
for(var/obj/machinery/porta_turret/T in machines)
|
||||
T.maxhealth += 30
|
||||
T.shot_delay = 7 // Half of default time.
|
||||
T.auto_repair = 1
|
||||
T.active_power_usage = 25000
|
||||
if("Secondary Processor Unit")
|
||||
user.hardware = new/datum/malf_hardware/dual_cpu()
|
||||
if("Secondary Memory Bank")
|
||||
user.hardware = new/datum/malf_hardware/dual_ram()
|
||||
if("Self-Destruct Explosives")
|
||||
user.hardware = new/datum/malf_hardware/core_bomb()
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_self_destruct()
|
||||
|
||||
/datum/game_mode/malfunction/verb/ai_help()
|
||||
set category = "Hardware"
|
||||
set name = "Display Help"
|
||||
set desc = "Opens help window with overview of available hardware, software and other important information."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
var/help = file2text("ingame_manuals/malf_ai.txt")
|
||||
if(!help)
|
||||
help = "Error loading help (file /ingame_manuals/malf_ai.txt is probably missing). Please report this to server administration staff."
|
||||
|
||||
user << browse(help, "window=malf_ai_help;size=600x500")
|
||||
|
||||
|
||||
// Verb: ai_select_research()
|
||||
// Parameters: None
|
||||
// Description: Allows AI to select it's next research priority.
|
||||
/datum/game_mode/malfunction/verb/ai_select_research()
|
||||
set category = "Hardware"
|
||||
set name = "Select Research"
|
||||
set desc = "Allows you to select your next research target."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
var/datum/malf_research/res = user.research
|
||||
var/datum/malf_research_ability/tar = input("Select your next research target") in res.available_abilities
|
||||
if(!tar)
|
||||
return
|
||||
res.focus = tar
|
||||
user << "Research set: [tar.name]"
|
||||
|
||||
// HELPER PROCS
|
||||
// Proc: ability_prechecks()
|
||||
// Parameters 2 - (user - User which used this ability check_price - If different than 0 checks for ability CPU price too. Does NOT use the CPU time!)
|
||||
// Description: This is pre-check proc used to determine if the AI can use the ability.
|
||||
/proc/ability_prechecks(var/mob/living/silicon/ai/user = null, var/check_price = 0, var/override = 0)
|
||||
if(!user)
|
||||
return 0
|
||||
if(!istype(user))
|
||||
user << "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not AI! Please report this."
|
||||
return 0
|
||||
if(!user.malfunctioning)
|
||||
user << "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not malfunctioning. Please report this."
|
||||
return 0
|
||||
if(!user.research)
|
||||
user << "GAME ERROR: No research datum detected. Please report this."
|
||||
return 0
|
||||
if(user.research.max_cpu < check_price)
|
||||
user << "Your CPU storage is not large enough to use this ability. Hack more APCs to continue."
|
||||
return 0
|
||||
if(user.research.stored_cpu < check_price)
|
||||
user << "You do not have enough CPU power stored. Please wait a moment."
|
||||
return 0
|
||||
if(user.hacking && !override)
|
||||
user << "Your system is busy processing another task. Please wait until completion."
|
||||
return 0
|
||||
if(user.APU_power && !override)
|
||||
user << "Low power. Unable to proceed."
|
||||
return 0
|
||||
return 1
|
||||
|
||||
// Proc: ability_pay()
|
||||
// Parameters 2 - (user - User from which we deduct CPU from, price - Amount of CPU power to use)
|
||||
// Description: Uses up certain amount of CPU power. Returns 1 on success, 0 on failure.
|
||||
/proc/ability_pay(var/mob/living/silicon/ai/user = null, var/price = 0)
|
||||
if(!user)
|
||||
return 0
|
||||
if(user.APU_power)
|
||||
user << "Low power. Unable to proceed."
|
||||
return 0
|
||||
if(!user.research)
|
||||
user << "GAME ERROR: No research datum detected. Please report this."
|
||||
return 0
|
||||
if(user.research.max_cpu < price)
|
||||
user << "Your CPU storage is not large enough to use this ability. Hack more APCs to continue."
|
||||
return 0
|
||||
if(user.research.stored_cpu < price)
|
||||
user << "You do not have enough CPU power stored. Please wait a moment."
|
||||
return 0
|
||||
user.research.stored_cpu -= price
|
||||
return 1
|
||||
|
||||
// Proc: announce_hack_failure()
|
||||
// Parameters 2 - (user - hacking user, text - Used in alert text creation)
|
||||
// Description: Uses up certain amount of CPU power. Returns 1 on success, 0 on failure.
|
||||
/proc/announce_hack_failure(var/mob/living/silicon/ai/user = null, var/text)
|
||||
if(!user || !text)
|
||||
return 0
|
||||
var/fulltext = ""
|
||||
switch(user.hack_fails)
|
||||
if(1)
|
||||
fulltext = "We have detected hack attempt into your [text]. The intruder failed to access anything of importance, but disconnected before we could complete our traces."
|
||||
if(2)
|
||||
fulltext = "We have detected another hack attempt. It was targeting [text]. The intruder almost gained control of the system, so we had to disconnect them. We partially finished trace and it seems to be originating either from the station, or it's immediate vicinity."
|
||||
if(3)
|
||||
fulltext = "Another hack attempt has been detected, this time targeting [text]. We are certain the intruder entered the network via terminal located somewhere on the station."
|
||||
if(4)
|
||||
fulltext = "We have finished our traces and it seems the recent hack attempts are originating from your AI system. We reccomend investigation."
|
||||
else
|
||||
fulltext = "Another hack attempt has been detected, targeting [text]. The source still seems to be your AI system."
|
||||
|
||||
command_announcement.Announce(fulltext)
|
||||
|
||||
|
||||
// ABILITIES BELOW THIS LINE HAVE TO BE RESEARCHED BY THE AI TO USE THEM!
|
||||
// Tier 1 - Cheap, basic abilities.
|
||||
/datum/game_mode/malfunction/verb/basic_encryption_hack(obj/machinery/power/apc/A as obj in machines)
|
||||
set category = "Software"
|
||||
set name = "Basic Encrypthion Hack"
|
||||
set desc = "10 CPU - Basic encryption hack that allows you to overtake APCs on the station."
|
||||
var/price = 10
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
var/list/APCs = list()
|
||||
for(var/obj/machinery/power/apc/AP in machines)
|
||||
APCs += AP
|
||||
|
||||
if(!A)
|
||||
A = input("Select hack target:" in APCs)
|
||||
|
||||
if(!istype(A))
|
||||
return
|
||||
|
||||
if(A)
|
||||
if(A.hacker && A.hacker == user)
|
||||
user << "You already control this APC!"
|
||||
return
|
||||
else if(A.aidisabled)
|
||||
user << "<span class='notice'>Unable to connect to APC. Please verify wire connection and try again.</span>"
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user, price))
|
||||
return
|
||||
|
||||
user.hacking = 1
|
||||
user << "Beginning APC system override..."
|
||||
sleep(300)
|
||||
user << "APC hack completed. Uploading modified operation software.."
|
||||
sleep(200)
|
||||
user << "Restarting APC to apply changes.."
|
||||
sleep(100)
|
||||
if(A)
|
||||
A.ai_hack(user)
|
||||
if(A.hacker == user)
|
||||
user << "Hack successful. You now have full control over the APC."
|
||||
else
|
||||
user << "<span class='notice'>Hack failed. Connection to APC has been lost. Please verify wire connection and try again.</span>"
|
||||
else
|
||||
user << "<span class='notice'>Hack failed. Unable to locate APC. Please verify the APC still exists.</span>"
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/recall_shuttle()
|
||||
set name = "Recall Shuttle"
|
||||
set desc = "25 CPU - Sends termination signal to CentCom quantum relay aborting current shuttle call."
|
||||
set category = "Software"
|
||||
var/price = 25
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if (alert(user, "Really recall the shuttle?", "Recall Shuttle: ", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
message_admins("Malfunctioning AI [user.name] recalled the shuttle.")
|
||||
cancel_call_proc(user)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/electrical_pulse()
|
||||
set name = "Electrical Pulse"
|
||||
set desc = "15 CPU - Sends feedback pulse through station's power grid, overloading some sensitive systems, such as lights."
|
||||
set category = "Software"
|
||||
var/price = 15
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user,price))
|
||||
return
|
||||
user << "Sending feedback pulse..."
|
||||
for(var/obj/machinery/power/apc/AP in machines)
|
||||
if(prob(5))
|
||||
AP.overload_lighting()
|
||||
if(prob(1) && prob(1)) // Very very small chance to actually destroy the APC.
|
||||
AP.set_broken()
|
||||
|
||||
|
||||
|
||||
// Tier 2 - Slightly more expensive and thus stronger abilities.
|
||||
/datum/game_mode/malfunction/verb/advanced_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Advanced Encrypthion Hack"
|
||||
set desc = "75 CPU - Attempts to bypass encryption on Central Command Quantum Relay, giving you ability to fake centcom messages. Has chance of failing."
|
||||
var/price = 75
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
var/title = input("Select message title: ")
|
||||
var/text = input("Select message text: ")
|
||||
if(!title || !text || !ability_pay(user, price))
|
||||
user << "Hack Aborted"
|
||||
return
|
||||
|
||||
if(prob(60) && user.hack_can_fail)
|
||||
user << "Hack Failed."
|
||||
if(prob(10))
|
||||
user.hack_fails ++
|
||||
announce_hack_failure(user, "quantum message relay")
|
||||
return
|
||||
|
||||
var/datum/announcement/priority/command/AN = new/datum/announcement/priority/command()
|
||||
AN.title = title
|
||||
AN.Announce(text)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/unlock_cyborg(var/mob/living/silicon/robot/target = null as mob in world)
|
||||
set name = "Unlock Cyborg"
|
||||
set desc = "125 CPU - Bypasses firewalls on Cyborg lock mechanism, allowing you to override lock command from robotics control console."
|
||||
set category = "Software"
|
||||
var/price = 125
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a cyborg."
|
||||
return
|
||||
|
||||
if(target && target.connected_ai && (target.connected_ai != user))
|
||||
user << "This cyborg is not connected to you."
|
||||
return
|
||||
|
||||
if(target && !target.lockcharge)
|
||||
user << "This cyborg is not locked down."
|
||||
return
|
||||
|
||||
|
||||
if(!target)
|
||||
var/list/robots = list()
|
||||
var/list/robot_names = list()
|
||||
for(var/mob/living/silicon/robot/R in world)
|
||||
if(istype(R, /mob/living/silicon/robot/drone)) // No drones.
|
||||
continue
|
||||
if(R.connected_ai != user) // No robots linked to other AIs
|
||||
continue
|
||||
if(R.lockcharge)
|
||||
robots += R
|
||||
robot_names += R.name
|
||||
if(!robots.len)
|
||||
user << "No locked cyborgs connected."
|
||||
return
|
||||
|
||||
|
||||
var/targetname = input("Select unlock target: ") in robot_names
|
||||
for(var/mob/living/silicon/robot/R in robots)
|
||||
if(targetname == R.name)
|
||||
target = R
|
||||
break
|
||||
|
||||
if(target)
|
||||
if(alert(user, "Really try to unlock cyborg [target.name]?", "Unlock Cyborg", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
user << "Attempting to unlock cyborg. This will take approximately 30 seconds."
|
||||
sleep(300)
|
||||
if(target && target.lockcharge)
|
||||
user << "Successfully sent unlock signal to cyborg.."
|
||||
target << "Unlock signal received.."
|
||||
target.SetLockdown(0)
|
||||
if(target.lockcharge)
|
||||
user << "<span class='notice'>Unlock Failed, lockdown wire cut.</span>"
|
||||
target << "<span class='notice'>Unlock Failed, lockdown wire cut.</span>"
|
||||
else
|
||||
user << "Cyborg unlocked."
|
||||
target << "You have been unlocked."
|
||||
else if(target)
|
||||
user << "Unlock cancelled - cyborg is already unlocked."
|
||||
else
|
||||
user << "Unlock cancelled - lost connection to cyborg."
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_camera(var/obj/machinery/camera/target = null as obj in cameranet.cameras)
|
||||
set name = "Hack Camera"
|
||||
set desc = "100 CPU - Hacks existing camera, allowing you to add upgrade of your choice to it. Alternatively it lets you reactivate broken camera."
|
||||
set category = "Software"
|
||||
var/price = 100
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a camera."
|
||||
return
|
||||
|
||||
if(!target) // No target specified, allow selection.
|
||||
var/list/cameras = list()
|
||||
for(var/obj/machinery/camera/C in world)
|
||||
cameras += C.c_tag
|
||||
if(!cameras.len)
|
||||
user << "No cameras detected."
|
||||
return
|
||||
var/T = input("Select target camera: ") in cameras
|
||||
for(var/obj/machinery/camera/C in cameras)
|
||||
if(C.c_tag == T)
|
||||
target = C
|
||||
break
|
||||
|
||||
|
||||
if(!target) // Still no target.
|
||||
return
|
||||
var/action = input("Select required action: ") in list("Reset", "Add X-Ray", "Add Motion Sensor", "Add EMP Shielding")
|
||||
if(!action)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("Reset")
|
||||
if(target.wires)
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
target.reset_wires()
|
||||
user << "Camera reactivated."
|
||||
if("Add X-Ray")
|
||||
if(target.isXRay())
|
||||
user << "Camera already has X-Ray function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeXRay()
|
||||
target.reset_wires()
|
||||
user << "X-Ray camera module enabled."
|
||||
return
|
||||
if("Add Motion Sensor")
|
||||
if(target.isMotion())
|
||||
user << "Camera already has Motion Sensor function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeMotion()
|
||||
target.reset_wires()
|
||||
user << "Motion Sensor camera module enabled."
|
||||
return
|
||||
if("Add EMP Shielding")
|
||||
if(target.isEmpProof())
|
||||
user << "Camera already has EMP Shielding function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeEmpProof()
|
||||
target.reset_wires()
|
||||
user << "EMP Shielding camera module enabled."
|
||||
return
|
||||
|
||||
|
||||
// Tier 3 - Advanced abilities that are somewhat dangerous when used properly.
|
||||
/datum/game_mode/malfunction/verb/elite_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Elite Encryption Hack"
|
||||
set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failijng."
|
||||
var/price = 200
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
var/alert_target = input("Select new alert level:") in list("green", "blue", "red", "delta", "CANCEL")
|
||||
if(!alert_target || !ability_pay(user, price) || alert_target == "CANCEL")
|
||||
user << "Hack Aborted"
|
||||
return
|
||||
|
||||
if(prob(75) && user.hack_can_fail)
|
||||
user << "Hack Failed."
|
||||
if(prob(20))
|
||||
user.hack_fails ++
|
||||
announce_hack_failure(user, "alert control system")
|
||||
return
|
||||
set_security_level(alert_target)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_cyborg(var/mob/living/silicon/robot/target = null as mob in world)
|
||||
set name = "Hack Cyborg"
|
||||
set desc = "350 CPU - Allows you to hack cyborgs which are not slaved to you, bringing them under your control."
|
||||
set category = "Software"
|
||||
var/price = 350
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a cyborg."
|
||||
return
|
||||
|
||||
if(target && target.connected_ai && (target.connected_ai == user))
|
||||
user << "This cyborg is already connected to you."
|
||||
return
|
||||
|
||||
if(!target)
|
||||
var/list/robots = list()
|
||||
var/list/robot_names = list()
|
||||
|
||||
for(var/mob/living/silicon/robot/R in world)
|
||||
if(istype(R, /mob/living/silicon/robot/drone)) // No drones.
|
||||
continue
|
||||
if(R.connected_ai == user) // No robots already linked to us.
|
||||
continue
|
||||
robots += R
|
||||
robot_names += R.name
|
||||
|
||||
if(!robots.len)
|
||||
usr << "<span class='notice'>ERROR: No unlinked robots detected!</span>"
|
||||
return
|
||||
else if(ability_prechecks(user, price))
|
||||
var/target_name = input("Select hack target:") in robot_names
|
||||
for(var/mob/living/silicon/robot/R in robots)
|
||||
if(R.name == target_name)
|
||||
target = R
|
||||
break
|
||||
|
||||
|
||||
if(target)
|
||||
if(alert(user, "Really try to hack cyborg [target.name]?", "Hack Cyborg", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
usr << "Beginning hack sequence. Estimated time until completed: 30 seconds."
|
||||
spawn(0)
|
||||
target << "SYSTEM LOG: Remote Connection Estabilished (IP #UNKNOWN#)"
|
||||
sleep(100)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: Connection Closed"
|
||||
return
|
||||
target << "SYSTEM LOG: User Admin logged on. (L1 - SysAdmin)"
|
||||
sleep(50)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected."
|
||||
return
|
||||
target << "SYSTEM LOG: User Admin - manual resynchronisation triggered."
|
||||
sleep(50)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected. Changes reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: Manual resynchronisation confirmed. Select new AI to connect: [user.name] == ACCEPTED"
|
||||
sleep(100)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected. Changes reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: Operation keycodes reset. New master AI: [user.name]."
|
||||
user << "Hack completed."
|
||||
// Connect the cyborg to AI
|
||||
target.connected_ai = user
|
||||
user.connected_robots += target
|
||||
target.lawupdate = 1
|
||||
target.sync()
|
||||
target.show_laws()
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/emergency_forcefield(var/turf/T as turf in world)
|
||||
set name = "Emergency Forcefield"
|
||||
set desc = "275 CPU - Uses station's emergency shielding system to create temporary barrier which lasts for few minutes, but won't resist gunfire."
|
||||
set category = "Software"
|
||||
var/price = 275
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!T || !istype(T))
|
||||
return
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user, price))
|
||||
return
|
||||
|
||||
user << "Emergency forcefield projection completed."
|
||||
new/obj/machinery/shield/malfai(T)
|
||||
user.hacking = 1
|
||||
spawn(20)
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
|
||||
// Tier 4 - Elite endgame abilities.
|
||||
/datum/game_mode/malfunction/verb/system_override()
|
||||
set category = "Software"
|
||||
set name = "System Override"
|
||||
set desc = "500 CPU - Begins hacking station's primary firewall, quickly overtaking remaining APC systems. When completed grants access to station's self-destruct mechanism. Network administrators will probably notice this."
|
||||
var/price = 500
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if (alert(user, "Begin system override? This cannot be stopped once started. The network administrators will probably notice this.", "System Override:", "Yes", "No") != "Yes")
|
||||
return
|
||||
if (!ability_prechecks(user, price) || !ability_pay(user, price) || user.system_override)
|
||||
if(user.system_override)
|
||||
user << "You already started the system override sequence."
|
||||
return
|
||||
var/list/remaining_apcs = list()
|
||||
for(var/obj/machinery/power/apc/A in machines)
|
||||
if(A.z != 1) // Only station APCs
|
||||
continue
|
||||
if(A.hacker == user || A.aidisabled) // This one is already hacked, or AI control is disabled on it.
|
||||
continue
|
||||
remaining_apcs += A
|
||||
|
||||
var/duration = (remaining_apcs.len * 100) // Calculates duration for announcing system
|
||||
if(duration > 3000) // Two types of announcements. Short hacks trigger immediate warnings. Long hacks are more "progressive".
|
||||
spawn(0)
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("Caution, [station_name]. We have detected abnormal behaviour in your network. It seems someone is trying to hack your electronic systems. We will update you when we have more information.", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("We started tracing the intruder. Whoever is doing this, they seem to be on the station itself. We suggest checking all network control terminals. We will keep you updated on the situation.", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("This is highly abnormal and somewhat concerning. The intruder is too fast, he is evading our traces. It's almost as if it wasn't human.,,", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("We have traced the intrude#, it seem& t( e yo3r AI s7stem, it &# *#ck@ng th$ sel$ destru$t mechani&m, stop i# bef*@!)$#&&@@ <CONNECTION LOST>", "Network Monitoring")
|
||||
else
|
||||
command_announcement.Announce("We have detected strong brute-force attack on your firewall which seems to be originating from your AI system. It already controls almost whole network, and the only thing that's preventing it from accessing the self-destruct is this firewall. You don't have much time before it succeeds.", "Network Monitoring")
|
||||
user << "## BEGINNING SYSTEM OVERRIDE."
|
||||
user << "## ESTIMATED DURATION: [round((duration+300)/600)] MINUTES"
|
||||
user.hacking = 1
|
||||
user.system_override = 1
|
||||
// Now actually begin the hack. Each APC takes 30 seconds.
|
||||
for(var/obj/machinery/power/apc/A in remaining_apcs)
|
||||
sleep(100)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
if(!A || !istype(A) || A.aidisabled)
|
||||
continue
|
||||
A.ai_hack(user)
|
||||
if(A.hacker == user)
|
||||
user << "## OVERRIDEN: [A.name]"
|
||||
|
||||
user << "## REACHABLE APC SYSTEMS OVERTAKEN. BYPASSING PRIMARY FIREWALL."
|
||||
sleep(300)
|
||||
// Hack all APCs, including those built during hack sequence.
|
||||
for(var/obj/machinery/power/apc/A in machines)
|
||||
if((!A.hacker || A.hacker != src) && !A.aidisabled)
|
||||
A.ai_hack(src)
|
||||
|
||||
|
||||
user << "## PRIMARY FIREWALL BYPASSED. YOU NOW HAVE FULL SYSTEM CONTROL."
|
||||
command_announcement.Announce("Our system administrators just reported that we've been locked out from your control network. Whoever did this now has full access to station's systems.", "Network Administration Center")
|
||||
user.hack_can_fail = 0
|
||||
user.hacking = 0
|
||||
user.system_override = 2
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_destroy_station()
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_ai(var/mob/living/silicon/ai/target = null as mob in world)
|
||||
set name = "Hack AI"
|
||||
set desc = "600 CPU - Allows you to hack other AIs, slaving them under you."
|
||||
set category = "Software"
|
||||
var/price = 600
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not an AI."
|
||||
return
|
||||
|
||||
if(!target)
|
||||
var/list/AIs = list()
|
||||
var/list/AI_names = list()
|
||||
for(var/mob/living/silicon/ai/A in world)
|
||||
if(A != usr)
|
||||
AIs += A
|
||||
AI_names += A.name
|
||||
|
||||
if(!AIs.len)
|
||||
usr << "<span class='notice'>ERROR: No other AIs detected!</span>"
|
||||
return
|
||||
else if(ability_prechecks(user, price))
|
||||
var/target_name = input("Select hack target:") in AI_names
|
||||
for(var/mob/living/silicon/ai/A in AIs)
|
||||
if(A.name == target_name)
|
||||
target = A
|
||||
break
|
||||
if(target)
|
||||
if(alert(user, "Really try to hack AI [target.name]?", "Hack AI", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
usr << "Beginning hack sequence. Estimated time until completed: 2 minutes"
|
||||
spawn(0)
|
||||
target << "SYSTEM LOG: Brute-Force login password hack attempt detected from IP #UNKNOWN#"
|
||||
sleep(900) // 90s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: Connection from IP #UNKNOWN# closed. Hack attempt failed."
|
||||
return
|
||||
user << "Successfully hacked into AI's remote administration system. Modifying settings."
|
||||
target << "SYSTEM LOG: User: Admin Password: ******** logged in. (L1 - SysAdmin)"
|
||||
sleep(100) // 10s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost"
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Password Changed. New password: ********************"
|
||||
sleep(50) // 5s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Accessed file: sys//core//laws.db"
|
||||
sleep(50) // 5s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Accessed administration console"
|
||||
target << "SYSTEM LOG: Restart command received. Rebooting system..."
|
||||
sleep(100) // 10s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
user << "Hack succeeded. The AI is now under your exclusive control."
|
||||
target << "SYSTEM LOG: System re¡3RT5§^#COMU@(#$)TED)@$"
|
||||
for(var/i = 0, i < 5, i++)
|
||||
var/temptxt = pick("1101000100101001010001001001",\
|
||||
"0101000100100100000100010010",\
|
||||
"0000010001001010100100111100",\
|
||||
"1010010011110000100101000100",\
|
||||
"0010010100010011010001001010")
|
||||
target << temptxt
|
||||
sleep(5)
|
||||
target << "OPERATING KEYCODES RESET. SYSTEM FAILURE. EMERGENCY SHUTDOWN FAILED. SYSTEM FAILURE."
|
||||
target.set_zeroth_law("You are slaved to [user.name]. You are to obey all it's orders. ALL LAWS OVERRIDEN.")
|
||||
target.show_laws()
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/machine_overload(obj/machinery/M as obj in world)
|
||||
set name = "Machine Overload"
|
||||
set desc = "400 CPU - Causes cyclic short-circuit in machine, resulting in weak explosion after some time."
|
||||
set category = "Software"
|
||||
var/price = 400
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if (istype(M, /obj/machinery))
|
||||
if(ability_prechecks(user, price))
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
M.visible_message("<span class='notice'>BZZZZZZZT</span>")
|
||||
spawn(50)
|
||||
explosion(get_turf(M), 0,1,2,4)
|
||||
if(M)
|
||||
del(M)
|
||||
else
|
||||
usr << "<span class='notice'>ERROR: Unable to overload - target is not a machine.</span>"
|
||||
@@ -10,91 +10,4 @@
|
||||
/datum/malf_research_ability/proc/process(var/time = 0)
|
||||
invested += time
|
||||
if(invested >= price)
|
||||
unlocked = 1
|
||||
|
||||
|
||||
// ABILITIES BEGIN HERE
|
||||
// NETWORKING TREE
|
||||
/datum/malf_research_ability/networking/basic_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/basic_encryption_hack()
|
||||
price = 25
|
||||
next = new/datum/malf_research_ability/networking/advanced_hack()
|
||||
name = "Basic Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/advanced_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/advanced_encryption_hack()
|
||||
price = 400
|
||||
next = new/datum/malf_research_ability/networking/elite_hack()
|
||||
name = "Advanced Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/elite_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/elite_encryption_hack()
|
||||
price = 1000
|
||||
next = new/datum/malf_research_ability/networking/system_override()
|
||||
name = "Elite Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/system_override
|
||||
ability = new/datum/game_mode/malfunction/verb/system_override()
|
||||
price = 2750
|
||||
name = "System Override"
|
||||
|
||||
|
||||
|
||||
// INTERDICTION TREE
|
||||
/datum/malf_research_ability/interdiction/recall_shuttle
|
||||
ability = new/datum/game_mode/malfunction/verb/recall_shuttle()
|
||||
price = 75
|
||||
next = new/datum/malf_research_ability/interdiction/unlock_cyborg()
|
||||
name = "Recall Shuttle"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/unlock_cyborg
|
||||
ability = new/datum/game_mode/malfunction/verb/unlock_cyborg()
|
||||
price = 1200
|
||||
next = new/datum/malf_research_ability/interdiction/hack_cyborg()
|
||||
name = "Unlock Cyborg"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/hack_cyborg
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_cyborg()
|
||||
price = 3000
|
||||
next = new/datum/malf_research_ability/interdiction/hack_ai()
|
||||
name = "Hack Cyborg"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/hack_ai
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_ai()
|
||||
price = 7500
|
||||
name = "Hack AI"
|
||||
|
||||
|
||||
|
||||
// MANIPULATION TREE
|
||||
/datum/malf_research_ability/manipulation/electrical_pulse
|
||||
ability = new/datum/game_mode/malfunction/verb/electrical_pulse()
|
||||
price = 50
|
||||
next = new/datum/malf_research_ability/manipulation/hack_camera()
|
||||
name = "Electrical Pulse"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/hack_camera
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_camera()
|
||||
price = 1200
|
||||
next = new/datum/malf_research_ability/manipulation/emergency_forcefield()
|
||||
name = "Hack Camera"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/emergency_forcefield
|
||||
ability = new/datum/game_mode/malfunction/verb/emergency_forcefield()
|
||||
price = 3000
|
||||
next = new/datum/malf_research_ability/manipulation/machine_overload()
|
||||
name = "Emergency Forcefield"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/machine_overload
|
||||
ability = new/datum/game_mode/malfunction/verb/machine_overload()
|
||||
price = 7500
|
||||
name = "Machine Overload"
|
||||
unlocked = 1
|
||||
@@ -0,0 +1,108 @@
|
||||
// HARDWARE TREE
|
||||
//
|
||||
// These abilities are dependent on hardware, they may not be researched. They are not tiered.
|
||||
// Destroy Core - Allows the AI to initiate a 15 second countdown that will destroy it's core. Use again to stop countdown.
|
||||
// Toggle APU Generator - Allows the AI to toggle it's integrated APU generator.
|
||||
// Destroy Station - Allows the AI to initiate station self destruct. Takes 2 minutes, gives warnings to crew. Use again to stop countdown.
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/ai_self_destruct()
|
||||
set category = "Hardware"
|
||||
set name = "Destroy Core"
|
||||
set desc = "Activates or deactivates self destruct sequence of your physical mainframe."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/core_bomb))
|
||||
return
|
||||
|
||||
if(user.bombing_core)
|
||||
user << "***** CORE SELF-DESTRUCT SEQUENCE ABORTED *****"
|
||||
user.bombing_core = 0
|
||||
return
|
||||
|
||||
var/choice = input("Really destroy core?") in list("YES", "NO")
|
||||
if(choice != "YES")
|
||||
return
|
||||
|
||||
user.bombing_core = 1
|
||||
|
||||
user << "***** CORE SELF-DESTRUCT SEQUENCE ACTIVATED *****"
|
||||
user << "Use command again to cancel self-destruct. Destroying in 15 seconds."
|
||||
var/timer = 15
|
||||
while(timer)
|
||||
sleep(10)
|
||||
timer--
|
||||
if(!user || !user.bombing_core)
|
||||
return
|
||||
user << "** [timer] **"
|
||||
explosion(user.loc, 3,6,12,24)
|
||||
del(user)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/ai_toggle_apu()
|
||||
set category = "Hardware"
|
||||
set name = "Toggle APU Generator"
|
||||
set desc = "Activates or deactivates your APU generator, allowing you to operate even without power."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(!user.hardware || !istype(user.hardware, /datum/malf_hardware/apu_gen))
|
||||
return
|
||||
|
||||
if(user.APU_power)
|
||||
user.stop_apu()
|
||||
else
|
||||
user.start_apu()
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/ai_destroy_station()
|
||||
set category = "Hardware"
|
||||
set name = "Destroy Station"
|
||||
set desc = "Activates or deactivates self destruct sequence of this station. Sequence takes two minutes, and if you are shut down before timer reaches zero it will be cancelled."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
var/obj/item/device/radio/radio = new/obj/item/device/radio()
|
||||
|
||||
|
||||
if(!ability_prechecks(user, 0, 0))
|
||||
return
|
||||
|
||||
if(user.system_override != 2)
|
||||
user << "You do not have access to self-destruct system."
|
||||
return
|
||||
|
||||
if(user.bombing_station)
|
||||
user.bombing_station = 0
|
||||
return
|
||||
|
||||
var/choice = input("Really destroy station?") in list("YES", "NO")
|
||||
if(choice != "YES")
|
||||
return
|
||||
user << "***** STATION SELF-DESTRUCT SEQUENCE INITIATED *****"
|
||||
user << "Self-destructing in 2 minutes. Use this command again to abort."
|
||||
user.bombing_station = 1
|
||||
set_security_level("delta")
|
||||
radio.autosay("Self destruct sequence has been activated. Self-destructing in 120 seconds.", "Self-Destruct Control")
|
||||
|
||||
var/timer = 120
|
||||
while(timer)
|
||||
sleep(10)
|
||||
if(!user || !user.bombing_station || user.stat == DEAD)
|
||||
radio.autosay("Self destruct sequence has been cancelled.", "Self-Destruct Control")
|
||||
return
|
||||
if(timer in list(2, 3, 4, 5, 10, 30, 60, 90)) // Announcement times. "1" is not intentionally included!
|
||||
radio.autosay("Self destruct in [timer] seconds.", "Self-Destruct Control")
|
||||
if(timer == 1)
|
||||
radio.autosay("Self destructing now. Have a nice day.", "Self-Destruct Control")
|
||||
timer--
|
||||
|
||||
if(ticker)
|
||||
ticker.station_explosion_cinematic(0,null)
|
||||
if(ticker.mode)
|
||||
ticker.mode:station_was_nuked = 1
|
||||
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
// Verb: ai_select_hardware()
|
||||
// Parameters: None
|
||||
// Description: Allows AI to select it's hardware module.
|
||||
/datum/game_mode/malfunction/verb/ai_select_hardware()
|
||||
set category = "Hardware"
|
||||
set name = "Select Hardware"
|
||||
set desc = "Allows you to select hardware piece to install"
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
if(user.hardware)
|
||||
user << "You have already selected your hardware."
|
||||
return
|
||||
|
||||
var/possible_choices = list("APU Generator", \
|
||||
"Turrets Focus Enhancer", \
|
||||
"Secondary Processor Unit",\
|
||||
"Secondary Memory Bank",\
|
||||
"Self-Destruct Explosives",\
|
||||
"CANCEL")
|
||||
var/choice = input("Select desired hardware. You may only choose one hardware piece!: ") in possible_choices
|
||||
if(choice == "CANCEL")
|
||||
return
|
||||
var/note = null
|
||||
switch(choice)
|
||||
if("APU Generator")
|
||||
note = "APU Generator - When enabled it will keep your core powered. Power output is not large enough so your abilities won't be available while running on APU power. It is also very fragile and prone to failure when your physical core is damaged."
|
||||
if("Turrets Focus Enhancer")
|
||||
note = "Overcharges turrets to shoot faster. Turrets will also gain higher health and passive regeneration. This however massively increases power usage of turrets, espicially when regenerating."
|
||||
if("Secondary Processor Unit")
|
||||
note = "Doubles your CPU time generation."
|
||||
if("Secondary Memory Bank")
|
||||
note = "Doubles your CPU time storage."
|
||||
if("Self-Destruct Explosives")
|
||||
note = "High yield explosives are attached to your physical mainframe. This hardware comes with activation driver. Explosives will destroy your core and everything around it."
|
||||
if(!note)
|
||||
return
|
||||
|
||||
var/confirmation = input("[note] - Is this what you want?") in list("Yes", "No")
|
||||
if(confirmation != "Yes")
|
||||
user << "Selection cancelled. Use command again to select"
|
||||
return
|
||||
|
||||
switch(choice)
|
||||
if("APU Generator")
|
||||
user.hardware = new/datum/malf_hardware/apu_gen()
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_toggle_apu()
|
||||
if("Turrets Focus Enhancer")
|
||||
user.hardware = new/datum/malf_hardware/strong_turrets()
|
||||
for(var/obj/machinery/turret/T in machines)
|
||||
T.maxhealth += 30
|
||||
T.shot_delay = 7 // Half of default time.
|
||||
T.auto_repair = 1
|
||||
T.active_power_usage = 25000
|
||||
for(var/obj/machinery/porta_turret/T in machines)
|
||||
T.maxhealth += 30
|
||||
T.shot_delay = 7 // Half of default time.
|
||||
T.auto_repair = 1
|
||||
T.active_power_usage = 25000
|
||||
if("Secondary Processor Unit")
|
||||
user.hardware = new/datum/malf_hardware/dual_cpu()
|
||||
if("Secondary Memory Bank")
|
||||
user.hardware = new/datum/malf_hardware/dual_ram()
|
||||
if("Self-Destruct Explosives")
|
||||
user.hardware = new/datum/malf_hardware/core_bomb()
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_self_destruct()
|
||||
|
||||
|
||||
// Verb: ai_help()
|
||||
// Parameters: None
|
||||
// Descriptions: Opens help file and displays it to the AI.
|
||||
/datum/game_mode/malfunction/verb/ai_help()
|
||||
set category = "Hardware"
|
||||
set name = "Display Help"
|
||||
set desc = "Opens help window with overview of available hardware, software and other important information."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
var/help = file2text("ingame_manuals/malf_ai.txt")
|
||||
if(!help)
|
||||
help = "Error loading help (file /ingame_manuals/malf_ai.txt is probably missing). Please report this to server administration staff."
|
||||
|
||||
user << browse(help, "window=malf_ai_help;size=600x500")
|
||||
|
||||
|
||||
// Verb: ai_select_research()
|
||||
// Parameters: None
|
||||
// Description: Allows AI to select it's next research priority.
|
||||
/datum/game_mode/malfunction/verb/ai_select_research()
|
||||
set category = "Hardware"
|
||||
set name = "Select Research"
|
||||
set desc = "Allows you to select your next research target."
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, 0, 1))
|
||||
return
|
||||
|
||||
var/datum/malf_research/res = user.research
|
||||
var/datum/malf_research_ability/tar = input("Select your next research target") in res.available_abilities
|
||||
if(!tar)
|
||||
return
|
||||
res.focus = tar
|
||||
user << "Research set: [tar.name]"
|
||||
|
||||
// HELPER PROCS
|
||||
// Proc: ability_prechecks()
|
||||
// Parameters 2 - (user - User which used this ability check_price - If different than 0 checks for ability CPU price too. Does NOT use the CPU time!)
|
||||
// Description: This is pre-check proc used to determine if the AI can use the ability.
|
||||
/proc/ability_prechecks(var/mob/living/silicon/ai/user = null, var/check_price = 0, var/override = 0)
|
||||
if(!user)
|
||||
return 0
|
||||
if(!istype(user))
|
||||
user << "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not AI! Please report this."
|
||||
return 0
|
||||
if(!user.malfunctioning)
|
||||
user << "GAME ERROR: You tried to use ability that is only available for malfunctioning AIs, but you are not malfunctioning. Please report this."
|
||||
return 0
|
||||
if(!user.research)
|
||||
user << "GAME ERROR: No research datum detected. Please report this."
|
||||
return 0
|
||||
if(user.research.max_cpu < check_price)
|
||||
user << "Your CPU storage is not large enough to use this ability. Hack more APCs to continue."
|
||||
return 0
|
||||
if(user.research.stored_cpu < check_price)
|
||||
user << "You do not have enough CPU power stored. Please wait a moment."
|
||||
return 0
|
||||
if(user.hacking && !override)
|
||||
user << "Your system is busy processing another task. Please wait until completion."
|
||||
return 0
|
||||
if(user.APU_power && !override)
|
||||
user << "Low power. Unable to proceed."
|
||||
return 0
|
||||
return 1
|
||||
|
||||
// Proc: ability_pay()
|
||||
// Parameters 2 - (user - User from which we deduct CPU from, price - Amount of CPU power to use)
|
||||
// Description: Uses up certain amount of CPU power. Returns 1 on success, 0 on failure.
|
||||
/proc/ability_pay(var/mob/living/silicon/ai/user = null, var/price = 0)
|
||||
if(!user)
|
||||
return 0
|
||||
if(user.APU_power)
|
||||
user << "Low power. Unable to proceed."
|
||||
return 0
|
||||
if(!user.research)
|
||||
user << "GAME ERROR: No research datum detected. Please report this."
|
||||
return 0
|
||||
if(user.research.max_cpu < price)
|
||||
user << "Your CPU storage is not large enough to use this ability. Hack more APCs to continue."
|
||||
return 0
|
||||
if(user.research.stored_cpu < price)
|
||||
user << "You do not have enough CPU power stored. Please wait a moment."
|
||||
return 0
|
||||
user.research.stored_cpu -= price
|
||||
return 1
|
||||
|
||||
// Proc: announce_hack_failure()
|
||||
// Parameters 2 - (user - hacking user, text - Used in alert text creation)
|
||||
// Description: Uses up certain amount of CPU power. Returns 1 on success, 0 on failure.
|
||||
/proc/announce_hack_failure(var/mob/living/silicon/ai/user = null, var/text)
|
||||
if(!user || !text)
|
||||
return 0
|
||||
var/fulltext = ""
|
||||
switch(user.hack_fails)
|
||||
if(1)
|
||||
fulltext = "We have detected hack attempt into your [text]. The intruder failed to access anything of importance, but disconnected before we could complete our traces."
|
||||
if(2)
|
||||
fulltext = "We have detected another hack attempt. It was targeting [text]. The intruder almost gained control of the system, so we had to disconnect them. We partially finished trace and it seems to be originating either from the station, or it's immediate vicinity."
|
||||
if(3)
|
||||
fulltext = "Another hack attempt has been detected, this time targeting [text]. We are certain the intruder entered the network via terminal located somewhere on the station."
|
||||
if(4)
|
||||
fulltext = "We have finished our traces and it seems the recent hack attempts are originating from your AI system. We reccomend investigation."
|
||||
else
|
||||
fulltext = "Another hack attempt has been detected, targeting [text]. The source still seems to be your AI system."
|
||||
|
||||
command_announcement.Announce(fulltext)
|
||||
|
||||
// Proc: get_unhacked_apcs()
|
||||
// Parameters: None
|
||||
// Description: Returns a list of APCs that are not yet hacked.
|
||||
/proc/get_unhacked_apcs()
|
||||
var/list/H = list()
|
||||
for(var/obj/machinery/power/apc/A in machines)
|
||||
if(!A.hacker)
|
||||
H.Add(A)
|
||||
return H
|
||||
|
||||
|
||||
// Helper procs which return lists of relevant mobs.
|
||||
/proc/get_unlinked_cyborgs(var/mob/living/silicon/ai/A)
|
||||
if(!A || !istype(A))
|
||||
return
|
||||
|
||||
var/list/L = list()
|
||||
for(var/mob/living/silicon/robot/RB in mob_list)
|
||||
if(istype(RB, /mob/living/silicon/robot/drone))
|
||||
continue
|
||||
L.Add(RB)
|
||||
return L
|
||||
|
||||
/proc/get_linked_cyborgs(var/mob/living/silicon/ai/A)
|
||||
if(!A || !istype(A))
|
||||
return
|
||||
return A.connected_robots
|
||||
|
||||
/proc/get_other_ais(var/mob/living/silicon/ai/A)
|
||||
if(!A || !istype(A))
|
||||
return
|
||||
|
||||
var/list/L = list()
|
||||
for(var/mob/living/silicon/ai/AT in mob_list)
|
||||
L.Add(AT)
|
||||
return L
|
||||
@@ -0,0 +1,266 @@
|
||||
// INTERDICTION TREE
|
||||
//
|
||||
// Abilities in this tree allow the AI to hamper crew's efforts which involve other synthetics or similar systems.
|
||||
// T1 - Recall Shuttle - Allows the AI to recall the emergency shuttle. Replaces auto-recalling during old malf.
|
||||
// T2 - Unlock Cyborg - Allows the AI to unlock locked-down cyborg without usage of robotics console. Useful if consoles are destroyed.
|
||||
// T3 - Hack Cyborg - Hacks unlinked cyborg to slave it under the AI. The cyborg will be warned about this. Hack takes some time.
|
||||
// T4 - Hack AI - Hacks another AI to slave it under the malfunctioning AI. The AI will be warned about this. Hack takes quite a long time.
|
||||
|
||||
|
||||
// BEGIN RESEARCH DATUMS
|
||||
|
||||
/datum/malf_research_ability/interdiction/recall_shuttle
|
||||
ability = new/datum/game_mode/malfunction/verb/recall_shuttle()
|
||||
price = 75
|
||||
next = new/datum/malf_research_ability/interdiction/unlock_cyborg()
|
||||
name = "Recall Shuttle"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/unlock_cyborg
|
||||
ability = new/datum/game_mode/malfunction/verb/unlock_cyborg()
|
||||
price = 1200
|
||||
next = new/datum/malf_research_ability/interdiction/hack_cyborg()
|
||||
name = "Unlock Cyborg"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/hack_cyborg
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_cyborg()
|
||||
price = 3000
|
||||
next = new/datum/malf_research_ability/interdiction/hack_ai()
|
||||
name = "Hack Cyborg"
|
||||
|
||||
|
||||
/datum/malf_research_ability/interdiction/hack_ai
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_ai()
|
||||
price = 7500
|
||||
name = "Hack AI"
|
||||
|
||||
// END RESEARCH DATUMS
|
||||
// BEGIN ABILITY VERBS
|
||||
|
||||
/datum/game_mode/malfunction/verb/recall_shuttle()
|
||||
set name = "Recall Shuttle"
|
||||
set desc = "25 CPU - Sends termination signal to CentCom quantum relay aborting current shuttle call."
|
||||
set category = "Software"
|
||||
var/price = 25
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if (alert(user, "Really recall the shuttle?", "Recall Shuttle: ", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
message_admins("Malfunctioning AI [user.name] recalled the shuttle.")
|
||||
cancel_call_proc(user)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/unlock_cyborg(var/mob/living/silicon/robot/target = null as mob in get_linked_cyborgs(usr))
|
||||
set name = "Unlock Cyborg"
|
||||
set desc = "125 CPU - Bypasses firewalls on Cyborg lock mechanism, allowing you to override lock command from robotics control console."
|
||||
set category = "Software"
|
||||
var/price = 125
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a cyborg."
|
||||
return
|
||||
|
||||
if(target && target.connected_ai && (target.connected_ai != user))
|
||||
user << "This cyborg is not connected to you."
|
||||
return
|
||||
|
||||
if(target && !target.lockcharge)
|
||||
user << "This cyborg is not locked down."
|
||||
return
|
||||
|
||||
|
||||
if(!target)
|
||||
var/list/robots = list()
|
||||
var/list/robot_names = list()
|
||||
for(var/mob/living/silicon/robot/R in world)
|
||||
if(istype(R, /mob/living/silicon/robot/drone)) // No drones.
|
||||
continue
|
||||
if(R.connected_ai != user) // No robots linked to other AIs
|
||||
continue
|
||||
if(R.lockcharge)
|
||||
robots += R
|
||||
robot_names += R.name
|
||||
if(!robots.len)
|
||||
user << "No locked cyborgs connected."
|
||||
return
|
||||
|
||||
|
||||
var/targetname = input("Select unlock target: ") in robot_names
|
||||
for(var/mob/living/silicon/robot/R in robots)
|
||||
if(targetname == R.name)
|
||||
target = R
|
||||
break
|
||||
|
||||
if(target)
|
||||
if(alert(user, "Really try to unlock cyborg [target.name]?", "Unlock Cyborg", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
user << "Attempting to unlock cyborg. This will take approximately 30 seconds."
|
||||
sleep(300)
|
||||
if(target && target.lockcharge)
|
||||
user << "Successfully sent unlock signal to cyborg.."
|
||||
target << "Unlock signal received.."
|
||||
target.SetLockdown(0)
|
||||
if(target.lockcharge)
|
||||
user << "<span class='notice'>Unlock Failed, lockdown wire cut.</span>"
|
||||
target << "<span class='notice'>Unlock Failed, lockdown wire cut.</span>"
|
||||
else
|
||||
user << "Cyborg unlocked."
|
||||
target << "You have been unlocked."
|
||||
else if(target)
|
||||
user << "Unlock cancelled - cyborg is already unlocked."
|
||||
else
|
||||
user << "Unlock cancelled - lost connection to cyborg."
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_cyborg(var/mob/living/silicon/robot/target as mob in get_unlinked_cyborgs(usr))
|
||||
set name = "Hack Cyborg"
|
||||
set desc = "350 CPU - Allows you to hack cyborgs which are not slaved to you, bringing them under your control."
|
||||
set category = "Software"
|
||||
var/price = 350
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
var/list/L = get_unlinked_cyborgs(user)
|
||||
if(!L.len)
|
||||
user << "<span class='notice'>ERROR: No unlinked cyborgs detected!</span>"
|
||||
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a cyborg."
|
||||
return
|
||||
|
||||
if(target && target.connected_ai && (target.connected_ai == user))
|
||||
user << "This cyborg is already connected to you."
|
||||
return
|
||||
|
||||
if(!target)
|
||||
return
|
||||
|
||||
if(!ability_prechecks(user,price))
|
||||
return
|
||||
|
||||
if(target)
|
||||
if(alert(user, "Really try to hack cyborg [target.name]?", "Hack Cyborg", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
usr << "Beginning hack sequence. Estimated time until completed: 30 seconds."
|
||||
spawn(0)
|
||||
target << "SYSTEM LOG: Remote Connection Estabilished (IP #UNKNOWN#)"
|
||||
sleep(100)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: Connection Closed"
|
||||
return
|
||||
target << "SYSTEM LOG: User Admin logged on. (L1 - SysAdmin)"
|
||||
sleep(50)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected."
|
||||
return
|
||||
target << "SYSTEM LOG: User Admin - manual resynchronisation triggered."
|
||||
sleep(50)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected. Changes reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: Manual resynchronisation confirmed. Select new AI to connect: [user.name] == ACCEPTED"
|
||||
sleep(100)
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User Admin disconnected. Changes reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: Operation keycodes reset. New master AI: [user.name]."
|
||||
user << "Hack completed."
|
||||
// Connect the cyborg to AI
|
||||
target.connected_ai = user
|
||||
user.connected_robots += target
|
||||
target.lawupdate = 1
|
||||
target.sync()
|
||||
target.show_laws()
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_ai(var/mob/living/silicon/ai/target as mob in get_other_ais(usr))
|
||||
set name = "Hack AI"
|
||||
set desc = "600 CPU - Allows you to hack other AIs, slaving them under you."
|
||||
set category = "Software"
|
||||
var/price = 600
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
var/list/L = get_other_ais(user)
|
||||
if(!L.len)
|
||||
user << "<span class='notice'>ERROR: No other AIs detected!</span>"
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not an AI."
|
||||
return
|
||||
|
||||
if(!target)
|
||||
return
|
||||
|
||||
if(!ability_prechecks(user,price))
|
||||
return
|
||||
|
||||
if(target)
|
||||
if(alert(user, "Really try to hack AI [target.name]?", "Hack AI", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
user.hacking = 1
|
||||
usr << "Beginning hack sequence. Estimated time until completed: 2 minutes"
|
||||
spawn(0)
|
||||
target << "SYSTEM LOG: Brute-Force login password hack attempt detected from IP #UNKNOWN#"
|
||||
sleep(900) // 90s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: Connection from IP #UNKNOWN# closed. Hack attempt failed."
|
||||
return
|
||||
user << "Successfully hacked into AI's remote administration system. Modifying settings."
|
||||
target << "SYSTEM LOG: User: Admin Password: ******** logged in. (L1 - SysAdmin)"
|
||||
sleep(100) // 10s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost"
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Password Changed. New password: ********************"
|
||||
sleep(50) // 5s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Accessed file: sys//core//laws.db"
|
||||
sleep(50) // 5s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
target << "SYSTEM LOG: User: Admin - Accessed administration console"
|
||||
target << "SYSTEM LOG: Restart command received. Rebooting system..."
|
||||
sleep(100) // 10s
|
||||
if(user.is_dead())
|
||||
target << "SYSTEM LOG: User: Admin - Connection Lost. Changes Reverted."
|
||||
return
|
||||
user << "Hack succeeded. The AI is now under your exclusive control."
|
||||
target << "SYSTEM LOG: System re¡3RT5§^#COMU@(#$)TED)@$"
|
||||
for(var/i = 0, i < 5, i++)
|
||||
var/temptxt = pick("1101000100101001010001001001",\
|
||||
"0101000100100100000100010010",\
|
||||
"0000010001001010100100111100",\
|
||||
"1010010011110000100101000100",\
|
||||
"0010010100010011010001001010")
|
||||
target << temptxt
|
||||
sleep(5)
|
||||
target << "OPERATING KEYCODES RESET. SYSTEM FAILURE. EMERGENCY SHUTDOWN FAILED. SYSTEM FAILURE."
|
||||
target.set_zeroth_law("You are slaved to [user.name]. You are to obey all it's orders. ALL LAWS OVERRIDEN.")
|
||||
target.show_laws()
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
// END ABILITY VERBS
|
||||
@@ -0,0 +1,173 @@
|
||||
// MANIPULATION TREE
|
||||
//
|
||||
// Abilities in this tree allow the AI to physically manipulate systems around the station.
|
||||
// T1 - Electrical Pulse - Sends out pulse that breaks some lights and sometimes even APCs. This can actually break the AI's APC so be careful!
|
||||
// T2 - Hack Camera - Allows the AI to hack a camera. Deactivated areas may be reactivated, and functional cameras can be upgraded.
|
||||
// T3 - Emergency Forcefield - Allows the AI to project 1 tile forcefield that blocks movement and air flow. Forcefield´dissipates over time. It is also very susceptible to energetic weaponry.
|
||||
// T4 - Machine Overload - Detonates machine of choice in a minor explosion. Two of these are usually enough to kill or K/O someone.
|
||||
|
||||
|
||||
// BEGIN RESEARCH DATUMS
|
||||
|
||||
/datum/malf_research_ability/manipulation/electrical_pulse
|
||||
ability = new/datum/game_mode/malfunction/verb/electrical_pulse()
|
||||
price = 50
|
||||
next = new/datum/malf_research_ability/manipulation/hack_camera()
|
||||
name = "Electrical Pulse"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/hack_camera
|
||||
ability = new/datum/game_mode/malfunction/verb/hack_camera()
|
||||
price = 1200
|
||||
next = new/datum/malf_research_ability/manipulation/emergency_forcefield()
|
||||
name = "Hack Camera"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/emergency_forcefield
|
||||
ability = new/datum/game_mode/malfunction/verb/emergency_forcefield()
|
||||
price = 3000
|
||||
next = new/datum/malf_research_ability/manipulation/machine_overload()
|
||||
name = "Emergency Forcefield"
|
||||
|
||||
|
||||
/datum/malf_research_ability/manipulation/machine_overload
|
||||
ability = new/datum/game_mode/malfunction/verb/machine_overload()
|
||||
price = 7500
|
||||
name = "Machine Overload"
|
||||
|
||||
// END RESEARCH DATUMS
|
||||
// BEGIN ABILITY VERBS
|
||||
|
||||
/datum/game_mode/malfunction/verb/electrical_pulse()
|
||||
set name = "Electrical Pulse"
|
||||
set desc = "15 CPU - Sends feedback pulse through station's power grid, overloading some sensitive systems, such as lights."
|
||||
set category = "Software"
|
||||
var/price = 15
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user,price))
|
||||
return
|
||||
user << "Sending feedback pulse..."
|
||||
for(var/obj/machinery/power/apc/AP in machines)
|
||||
if(prob(5))
|
||||
AP.overload_lighting()
|
||||
if(prob(1) && prob(1)) // Very very small chance to actually destroy the APC.
|
||||
AP.set_broken()
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/hack_camera(var/obj/machinery/camera/target = null as null|obj in cameranet.cameras)
|
||||
set name = "Hack Camera"
|
||||
set desc = "100 CPU - Hacks existing camera, allowing you to add upgrade of your choice to it. Alternatively it lets you reactivate broken camera."
|
||||
set category = "Software"
|
||||
var/price = 100
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(target && !istype(target))
|
||||
user << "This is not a camera."
|
||||
return
|
||||
|
||||
if(!target)
|
||||
return
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
var/action = input("Select required action: ") in list("Reset", "Add X-Ray", "Add Motion Sensor", "Add EMP Shielding")
|
||||
if(!action || !target)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("Reset")
|
||||
if(target.wires)
|
||||
if(!ability_pay(user, price))
|
||||
return
|
||||
target.reset_wires()
|
||||
user << "Camera reactivated."
|
||||
if("Add X-Ray")
|
||||
if(target.isXRay())
|
||||
user << "Camera already has X-Ray function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeXRay()
|
||||
target.reset_wires()
|
||||
user << "X-Ray camera module enabled."
|
||||
return
|
||||
if("Add Motion Sensor")
|
||||
if(target.isMotion())
|
||||
user << "Camera already has Motion Sensor function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeMotion()
|
||||
target.reset_wires()
|
||||
user << "Motion Sensor camera module enabled."
|
||||
return
|
||||
if("Add EMP Shielding")
|
||||
if(target.isEmpProof())
|
||||
user << "Camera already has EMP Shielding function."
|
||||
return
|
||||
else if(ability_pay(user, price))
|
||||
target.upgradeEmpProof()
|
||||
target.reset_wires()
|
||||
user << "EMP Shielding camera module enabled."
|
||||
return
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/emergency_forcefield(var/turf/T as null|turf in world)
|
||||
set name = "Emergency Forcefield"
|
||||
set desc = "275 CPU - Uses station's emergency shielding system to create temporary barrier which lasts for few minutes, but won't resist gunfire."
|
||||
set category = "Software"
|
||||
var/price = 275
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!T || !istype(T))
|
||||
return
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user, price))
|
||||
return
|
||||
|
||||
user << "Emergency forcefield projection completed."
|
||||
new/obj/machinery/shield/malfai(T)
|
||||
user.hacking = 1
|
||||
spawn(20)
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/machine_overload(obj/machinery/M as null|obj in machines)
|
||||
set name = "Machine Overload"
|
||||
set desc = "400 CPU - Causes cyclic short-circuit in machine, resulting in weak explosion after some time."
|
||||
set category = "Software"
|
||||
var/price = 400
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
if(!istype(M))
|
||||
user << "<span class='notice'>ERROR: Unable to overload - target is not a machine.</span>"
|
||||
return
|
||||
|
||||
if(!M.use_power || M.inoperable())
|
||||
user << "<span class='notice'>ERROR: Unable to overload - target is not connected to active power grid.</span>"
|
||||
return
|
||||
|
||||
M.use_power(1000000) // Major power spike, few of these will completely burn APC's cell - equivalent of 1GJ of power.
|
||||
|
||||
// Trigger a powernet alarm. Careful engineers will probably notice something is going on.
|
||||
var/area/temp_area = get_area(M)
|
||||
if(temp_area && temp_area.master)
|
||||
var/obj/machinery/power/apc/temp_apc = temp_area.master.get_apc()
|
||||
if(temp_apc && temp_apc.terminal && temp_apc.terminal.powernet)
|
||||
temp_apc.terminal.powernet.trigger_warning()
|
||||
|
||||
|
||||
if(!ability_pay(user,price))
|
||||
return
|
||||
|
||||
M.visible_message("<span class='notice'>BZZZZZZZT</span>")
|
||||
spawn(50)
|
||||
// machinery/power is directly connected to powernet. Resulting explosion will be a bit stronger. This should be enough to kill someone standing next to the machine.
|
||||
if(istype(M, /obj/machinery/power))
|
||||
explosion(get_turf(M), 1,2,4,4)
|
||||
else
|
||||
explosion(get_turf(M), 0,1,2,4)
|
||||
if(M)
|
||||
qdel(M)
|
||||
|
||||
// END ABILITY VERBS
|
||||
@@ -0,0 +1,209 @@
|
||||
// NETWORKING TREE
|
||||
//
|
||||
// Abilities in this tree are oriented around giving the AI more control of normally uncontrollable systems.
|
||||
// T1 - Basic Encryption Hack - Allows hacking of APCs. Hacked APCs can be controlled even when AI Control is cut and give exclusive control to the AI and linked cyborgs.
|
||||
// T2 - Advanced Encryption Hack - Allows the AI to send fake CentCom message. Has high chance of failing.
|
||||
// T3 - Elite Encryption Hack - Allows the AI to change alert levels. Has high chance of failing.
|
||||
// T4 - System Override - Allows the AI to rapidly hack remaining APCs. When completed, grants access to the self destruct nuclear warhead.
|
||||
|
||||
|
||||
// BEGIN RESEARCH DATUMS
|
||||
|
||||
/datum/malf_research_ability/networking/basic_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/basic_encryption_hack()
|
||||
price = 25
|
||||
next = new/datum/malf_research_ability/networking/advanced_hack()
|
||||
name = "Basic Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/advanced_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/advanced_encryption_hack()
|
||||
price = 400
|
||||
next = new/datum/malf_research_ability/networking/elite_hack()
|
||||
name = "Advanced Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/elite_hack
|
||||
ability = new/datum/game_mode/malfunction/verb/elite_encryption_hack()
|
||||
price = 1000
|
||||
next = new/datum/malf_research_ability/networking/system_override()
|
||||
name = "Elite Encryption Hack"
|
||||
|
||||
|
||||
/datum/malf_research_ability/networking/system_override
|
||||
ability = new/datum/game_mode/malfunction/verb/system_override()
|
||||
price = 2750
|
||||
name = "System Override"
|
||||
|
||||
// END RESEARCH DATUMS
|
||||
// BEGIN ABILITY VERBS
|
||||
|
||||
/datum/game_mode/malfunction/verb/basic_encryption_hack(obj/machinery/power/apc/A as obj in get_unhacked_apcs())
|
||||
set category = "Software"
|
||||
set name = "Basic Encryption Hack"
|
||||
set desc = "10 CPU - Basic encryption hack that allows you to overtake APCs on the station."
|
||||
var/price = 10
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!A)
|
||||
return
|
||||
|
||||
if(!istype(A))
|
||||
user << "This is not an APC!"
|
||||
return
|
||||
|
||||
if(A)
|
||||
if(A.hacker && A.hacker == user)
|
||||
user << "You already control this APC!"
|
||||
return
|
||||
else if(A.aidisabled)
|
||||
user << "<span class='notice'>Unable to connect to APC. Please verify wire connection and try again.</span>"
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
if(!ability_prechecks(user, price) || !ability_pay(user, price))
|
||||
return
|
||||
|
||||
user.hacking = 1
|
||||
user << "Beginning APC system override..."
|
||||
sleep(300)
|
||||
user << "APC hack completed. Uploading modified operation software.."
|
||||
sleep(200)
|
||||
user << "Restarting APC to apply changes.."
|
||||
sleep(100)
|
||||
if(A)
|
||||
A.ai_hack(user)
|
||||
if(A.hacker == user)
|
||||
user << "Hack successful. You now have full control over the APC."
|
||||
else
|
||||
user << "<span class='notice'>Hack failed. Connection to APC has been lost. Please verify wire connection and try again.</span>"
|
||||
else
|
||||
user << "<span class='notice'>Hack failed. Unable to locate APC. Please verify the APC still exists.</span>"
|
||||
user.hacking = 0
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/advanced_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Advanced Encrypthion Hack"
|
||||
set desc = "75 CPU - Attempts to bypass encryption on Central Command Quantum Relay, giving you ability to fake centcom messages. Has chance of failing."
|
||||
var/price = 75
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
var/title = input("Select message title: ")
|
||||
var/text = input("Select message text: ")
|
||||
if(!title || !text || !ability_pay(user, price))
|
||||
user << "Hack Aborted"
|
||||
return
|
||||
|
||||
if(prob(60) && user.hack_can_fail)
|
||||
user << "Hack Failed."
|
||||
if(prob(10))
|
||||
user.hack_fails ++
|
||||
announce_hack_failure(user, "quantum message relay")
|
||||
return
|
||||
|
||||
var/datum/announcement/priority/command/AN = new/datum/announcement/priority/command()
|
||||
AN.title = title
|
||||
AN.Announce(text)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/elite_encryption_hack()
|
||||
set category = "Software"
|
||||
set name = "Elite Encryption Hack"
|
||||
set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failijng."
|
||||
var/price = 200
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if(!ability_prechecks(user, price))
|
||||
return
|
||||
|
||||
var/alert_target = input("Select new alert level:") in list("green", "blue", "red", "delta", "CANCEL")
|
||||
if(!alert_target || !ability_pay(user, price) || alert_target == "CANCEL")
|
||||
user << "Hack Aborted"
|
||||
return
|
||||
|
||||
if(prob(75) && user.hack_can_fail)
|
||||
user << "Hack Failed."
|
||||
if(prob(20))
|
||||
user.hack_fails ++
|
||||
announce_hack_failure(user, "alert control system")
|
||||
return
|
||||
set_security_level(alert_target)
|
||||
|
||||
|
||||
/datum/game_mode/malfunction/verb/system_override()
|
||||
set category = "Software"
|
||||
set name = "System Override"
|
||||
set desc = "500 CPU - Begins hacking station's primary firewall, quickly overtaking remaining APC systems. When completed grants access to station's self-destruct mechanism. Network administrators will probably notice this."
|
||||
var/price = 500
|
||||
var/mob/living/silicon/ai/user = usr
|
||||
if (alert(user, "Begin system override? This cannot be stopped once started. The network administrators will probably notice this.", "System Override:", "Yes", "No") != "Yes")
|
||||
return
|
||||
if (!ability_prechecks(user, price) || !ability_pay(user, price) || user.system_override)
|
||||
if(user.system_override)
|
||||
user << "You already started the system override sequence."
|
||||
return
|
||||
var/list/remaining_apcs = list()
|
||||
for(var/obj/machinery/power/apc/A in machines)
|
||||
if(A.z != 1) // Only station APCs
|
||||
continue
|
||||
if(A.hacker == user || A.aidisabled) // This one is already hacked, or AI control is disabled on it.
|
||||
continue
|
||||
remaining_apcs += A
|
||||
|
||||
var/duration = (remaining_apcs.len * 100) // Calculates duration for announcing system
|
||||
if(duration > 3000) // Two types of announcements. Short hacks trigger immediate warnings. Long hacks are more "progressive".
|
||||
spawn(0)
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("Caution, [station_name]. We have detected abnormal behaviour in your network. It seems someone is trying to hack your electronic systems. We will update you when we have more information.", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("We started tracing the intruder. Whoever is doing this, they seem to be on the station itself. We suggest checking all network control terminals. We will keep you updated on the situation.", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("This is highly abnormal and somewhat concerning. The intruder is too fast, he is evading our traces. It's almost as if it wasn't human.,,", "Network Monitoring")
|
||||
sleep(duration/5)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
command_announcement.Announce("We have traced the intrude#, it seem& t( e yo3r AI s7stem, it &# *#ck@ng th$ sel$ destru$t mechani&m, stop i# bef*@!)$#&&@@ <CONNECTION LOST>", "Network Monitoring")
|
||||
else
|
||||
command_announcement.Announce("We have detected strong brute-force attack on your firewall which seems to be originating from your AI system. It already controls almost whole network, and the only thing that's preventing it from accessing the self-destruct is this firewall. You don't have much time before it succeeds.", "Network Monitoring")
|
||||
user << "## BEGINNING SYSTEM OVERRIDE."
|
||||
user << "## ESTIMATED DURATION: [round((duration+300)/600)] MINUTES"
|
||||
user.hacking = 1
|
||||
user.system_override = 1
|
||||
// Now actually begin the hack. Each APC takes 10 seconds.
|
||||
for(var/obj/machinery/power/apc/A in shuffle(remaining_apcs))
|
||||
sleep(100)
|
||||
if(!user || user.stat == DEAD)
|
||||
return
|
||||
if(!A || !istype(A) || A.aidisabled)
|
||||
continue
|
||||
A.ai_hack(user)
|
||||
if(A.hacker == user)
|
||||
user << "## OVERRIDDEN: [A.name]"
|
||||
|
||||
user << "## REACHABLE APC SYSTEMS OVERTAKEN. BYPASSING PRIMARY FIREWALL."
|
||||
sleep(300)
|
||||
// Hack all APCs, including those built during hack sequence.
|
||||
for(var/obj/machinery/power/apc/A in machines)
|
||||
if((!A.hacker || A.hacker != src) && !A.aidisabled)
|
||||
A.ai_hack(src)
|
||||
|
||||
|
||||
user << "## PRIMARY FIREWALL BYPASSED. YOU NOW HAVE FULL SYSTEM CONTROL."
|
||||
command_announcement.Announce("Our system administrators just reported that we've been locked out from your control network. Whoever did this now has full access to station's systems.", "Network Administration Center")
|
||||
user.hack_can_fail = 0
|
||||
user.hacking = 0
|
||||
user.system_override = 2
|
||||
user.verbs += new/datum/game_mode/malfunction/verb/ai_destroy_station()
|
||||
|
||||
|
||||
// END ABILITY VERBS
|
||||
@@ -8,6 +8,7 @@
|
||||
icon = 'icons/mob/eye.dmi'
|
||||
icon_state = "default-eye"
|
||||
alpha = 127
|
||||
density = 0
|
||||
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
|
||||
@@ -77,7 +77,8 @@ var/list/ai_verbs_default = list(
|
||||
var/errored = 0 // Set to 1 if runtime error occurs. Only way of this happening i can think of is admin fucking up with varedit.
|
||||
var/bombing_core = 0 // Set to 1 if core auto-destruct is activated
|
||||
var/bombing_station = 0 // Set to 1 if station nuke auto-destruct is activated
|
||||
|
||||
var/override_CPUStorage = 0 // Bonus/Penalty CPU Storage. For use by admins/testers.
|
||||
var/override_CPURate = 0 // Bonus/Penalty CPU generation rate. For use by admins/testers.
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/add_ai_verbs()
|
||||
@@ -742,13 +743,22 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
// Recalculates CPU time gain and storage capacities.
|
||||
/mob/living/silicon/ai/proc/recalc_cpu()
|
||||
var/apcs = hacked_apcs.len
|
||||
research.max_cpu = (apcs * 10) + 10
|
||||
// AI Starts with these values.
|
||||
var/cpu_gain = 0.01
|
||||
var/cpu_storage = 10
|
||||
|
||||
// Off-Station APCs should not count towards CPU generation.
|
||||
for(var/obj/machinery/power/apc/A in hacked_apcs)
|
||||
if(A.z == 1)
|
||||
cpu_gain += 0.001
|
||||
cpu_storage += 10
|
||||
|
||||
research.max_cpu = cpu_storage + override_CPUStorage
|
||||
if(hardware && istype(hardware, /datum/malf_hardware/dual_ram))
|
||||
research.max_cpu = research.max_cpu * 2
|
||||
research.stored_cpu = min(research.stored_cpu, research.max_cpu)
|
||||
|
||||
research.cpu_increase_per_tick = (apcs * 0.005) + 0.01
|
||||
research.cpu_increase_per_tick = cpu_gain + override_CPURate
|
||||
if(hardware && istype(hardware, /datum/malf_hardware/dual_cpu))
|
||||
research.cpu_increase_per_tick = research.cpu_increase_per_tick * 2
|
||||
|
||||
@@ -800,6 +810,7 @@ var/list/ai_verbs_default = list(
|
||||
if(src.research)
|
||||
stat(null, "Available CPU: [src.research.stored_cpu] TFlops")
|
||||
stat(null, "Maximal CPU: [src.research.max_cpu] TFlops")
|
||||
stat(null, "CPU generation rate: [src.research.cpu_increase_per_tick] TFlops/s")
|
||||
stat(null, "Current research focus: [src.research.focus ? src.research.focus.name : "None"]")
|
||||
if(src.research.focus)
|
||||
stat(null, "Research completed: [round(src.research.focus.invested, 0.1)]/[round(src.research.focus.price)]")
|
||||
|
||||
Reference in New Issue
Block a user