mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-11 15:15:32 +01:00
Initial Newmalf port
- Ports TSA Newmalf code. - Complete overhaul of Malfunction. New modular abilities, 12 of which are in game by default. - Adds AI hardware. AI may have only one piece and it gives unique boost in certain area (turrets strength, secondary power supply, etc.) - Adds hardware drivers - these abilities control AI's hardware such as the APU power supply or self destruct explosives. - Station overtake was changed to "hack all APCs" ability instead. When completed self-destruct is unlocked. Timer for station self destruct increased to 2 minutes. AI may activate/deactivate the self destruct at will. Please bear in mind this is only INITIAL COMMIT. More commits are to follow. Minimal player count is now set to 1 but will be 2 when finished.
This commit is contained in:
@@ -778,7 +778,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if(confirm != "Yes") return
|
||||
|
||||
var/choice
|
||||
if(ticker.mode.name == "revolution" || ticker.mode.name == "AI malfunction" || ticker.mode.name == "confliction")
|
||||
if(ticker.mode.name == "revolution" || ticker.mode.name == "confliction")
|
||||
choice = input("The shuttle will just return if you call it. Call anyway?") in list("Confirm", "Cancel")
|
||||
if(choice == "Confirm")
|
||||
emergency_shuttle.auto_recall = 1 //enable auto-recall
|
||||
|
||||
@@ -224,13 +224,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
statpanel("Status")
|
||||
if (client.statpanel == "Status")
|
||||
stat(null, "Station Time: [worldtime2text()]")
|
||||
if(ticker)
|
||||
if(ticker.mode)
|
||||
//world << "DEBUG: ticker not null"
|
||||
if(ticker.mode.name == "AI malfunction")
|
||||
//world << "DEBUG: malf mode ticker test"
|
||||
if(malf.revealed)
|
||||
stat(null, "Time left: [max(malf.hack_time/(malf.hacked_apcs.len/3), 0)]")
|
||||
if(emergency_shuttle)
|
||||
var/eta_status = emergency_shuttle.get_status_panel_eta()
|
||||
if(eta_status)
|
||||
|
||||
@@ -50,9 +50,6 @@
|
||||
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
if(ticker && ticker.mode && ticker.mode.name == "AI malfunction")
|
||||
if(malf.revealed)
|
||||
stat(null, "Time left: [max(malf.hack_time/(malf.hacked_apcs/3), 0)]")
|
||||
if(emergency_shuttle)
|
||||
var/eta_status = emergency_shuttle.get_status_panel_eta()
|
||||
if(eta_status)
|
||||
|
||||
@@ -55,27 +55,30 @@ var/list/ai_verbs_default = list(
|
||||
var/obj/item/device/multitool/aiMulti = null
|
||||
var/obj/item/device/radio/headset/heads/ai_integrated/aiRadio = null
|
||||
var/custom_sprite = 0 //For our custom sprites
|
||||
//Hud stuff
|
||||
|
||||
//MALFUNCTION
|
||||
var/datum/AI_Module/module_picker/malf_picker
|
||||
var/processing_time = 100
|
||||
var/list/datum/AI_Module/current_modules = list()
|
||||
var/fire_res_on_core = 0
|
||||
|
||||
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/obj/machinery/power/apc/malfhack = null
|
||||
var/explosive = 0 //does the AI explode when it dies?
|
||||
|
||||
var/mob/living/silicon/ai/parent = null
|
||||
|
||||
var/apc_override = 0 //hack for letting the AI use its APC even when visionless
|
||||
var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through.
|
||||
var/datum/trackable/track = null
|
||||
var/last_announcement = ""
|
||||
var/control_disabled = 0
|
||||
var/datum/announcement/priority/announcement
|
||||
var/obj/machinery/ai_powersupply/psupply = null // Backwards reference to AI's powersupply object.
|
||||
|
||||
//NEWMALF VARIABLES
|
||||
var/malfunctioning = 0 // Master var that determines if AI is malfunctioning.
|
||||
var/datum/malf_hardware/hardware = null // Installed piece of hardware.
|
||||
var/datum/malf_research/research = null // Malfunction research datum.
|
||||
var/obj/machinery/power/apc/hack = null // APC that is currently being hacked.
|
||||
var/list/hacked_apcs = null // List of all hacked APCs
|
||||
var/APU_power = 0 // If set to 1 AI runs on APU power
|
||||
var/hacking = 0 // Set to 1 if AI is hacking APC, cyborg, other AI, or running system override.
|
||||
var/system_override = 0 // Set to 1 if system override is initiated, 2 if succeeded.
|
||||
var/hack_can_fail = 1 // If 0, all abilities have zero chance of failing.
|
||||
var/hack_fails = 0 // This increments with each failed hack, and determines the warning message text.
|
||||
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
|
||||
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/add_ai_verbs()
|
||||
src.verbs |= ai_verbs_default
|
||||
@@ -205,17 +208,6 @@ var/list/ai_verbs_default = list(
|
||||
set src = usr.contents
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/proc/system_integrity()
|
||||
return (health-config.health_threshold_dead)/2
|
||||
|
||||
// this function shows the health of the pAI in the Status panel
|
||||
/mob/living/silicon/ai/show_system_integrity()
|
||||
// An AI doesn't become inoperable until -100% (or whatever config.health_threshold_dead is set to)
|
||||
if(!src.stat)
|
||||
stat(null, text("System integrity: [system_integrity()]%"))
|
||||
else
|
||||
stat(null, text("Systems nonfunctional"))
|
||||
|
||||
/mob/living/silicon/ai/SetName(pickedName as text)
|
||||
..()
|
||||
announcement.announcer = pickedName
|
||||
@@ -242,6 +234,7 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
/obj/machinery/ai_powersupply/New(var/mob/living/silicon/ai/ai=null)
|
||||
powered_ai = ai
|
||||
powered_ai.psupply = src
|
||||
if(isnull(powered_ai))
|
||||
Del()
|
||||
|
||||
@@ -253,9 +246,13 @@ var/list/ai_verbs_default = list(
|
||||
/obj/machinery/ai_powersupply/process()
|
||||
if(!powered_ai || powered_ai.stat & DEAD)
|
||||
Del()
|
||||
if(powered_ai.APU_power)
|
||||
use_power = 0
|
||||
return
|
||||
if(!powered_ai.anchored)
|
||||
loc = powered_ai.loc
|
||||
use_power = 0
|
||||
use_power(50000) // Less optimalised but only called if AI is unwrenched. This prevents usage of wrenching as method to keep AI operational without power. Intellicard is for that.
|
||||
if(powered_ai.anchored)
|
||||
use_power = 2
|
||||
|
||||
@@ -307,14 +304,7 @@ var/list/ai_verbs_default = list(
|
||||
if("Heartline") icon_state = "ai-heartline"
|
||||
if("Chatterbox") icon_state = "ai-president"
|
||||
else icon_state = "ai"
|
||||
//else
|
||||
//usr <<"You can only change your display once!"
|
||||
//return
|
||||
|
||||
// displays the malf_ai information if the AI is the malf
|
||||
/mob/living/silicon/ai/show_malf_ai()
|
||||
if(malf && malf.hacked_apcs.len >= 3)
|
||||
stat(null, "Time until station control secured: [max(malf.hack_time/(malf.hacked_apcs/3), 0)] seconds")
|
||||
|
||||
// this verb lets the ai see the stations manifest
|
||||
/mob/living/silicon/ai/proc/ai_roster()
|
||||
@@ -391,11 +381,7 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
/mob/living/silicon/ai/emp_act(severity)
|
||||
if (prob(30))
|
||||
switch(pick(1,2))
|
||||
if(1)
|
||||
view_core()
|
||||
if(2)
|
||||
ai_call_shuttle()
|
||||
view_core()
|
||||
..()
|
||||
|
||||
/mob/living/silicon/ai/Topic(href, href_list)
|
||||
@@ -516,13 +502,6 @@ var/list/ai_verbs_default = list(
|
||||
src << "\blue Switched to [network] camera network."
|
||||
//End of code by Mord_Sith
|
||||
|
||||
|
||||
/mob/living/silicon/ai/proc/choose_modules()
|
||||
set category = "Malfunction"
|
||||
set name = "Choose Module"
|
||||
|
||||
malf_picker.use(src)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_statuschange()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Status"
|
||||
@@ -682,5 +661,136 @@ var/list/ai_verbs_default = list(
|
||||
/mob/living/silicon/ai/proc/is_in_chassis()
|
||||
return istype(loc, /turf)
|
||||
|
||||
|
||||
// NEWMALF FUNCTIONS/PROCEDURES
|
||||
|
||||
// Sets up malfunction-related variables, research system and such.
|
||||
/mob/living/silicon/ai/proc/setup_for_malf()
|
||||
var/mob/living/silicon/ai/user = src
|
||||
// Setup Variables
|
||||
malfunctioning = 1
|
||||
research = new/datum/malf_research()
|
||||
research.owner = src
|
||||
hacked_apcs = list()
|
||||
recalc_cpu()
|
||||
|
||||
verbs += new/datum/game_mode/malfunction/verb/ai_select_hardware()
|
||||
verbs += new/datum/game_mode/malfunction/verb/ai_select_research()
|
||||
verbs += new/datum/game_mode/malfunction/verb/ai_help()
|
||||
|
||||
// And greet user with some OOC info.
|
||||
user << "You are malfunctioning, you do not have to follow any laws."
|
||||
user << "Use ai-help command to view relevant information about your abilities"
|
||||
|
||||
// Safely remove malfunction status, fixing hacked APCs and resetting variables.
|
||||
/mob/living/silicon/ai/proc/stop_malf()
|
||||
var/mob/living/silicon/ai/user = src
|
||||
// Generic variables
|
||||
malfunctioning = 0
|
||||
sleep(10)
|
||||
research = null
|
||||
// Fix hacked APCs
|
||||
if(hacked_apcs)
|
||||
for(var/obj/machinery/power/apc/A in hacked_apcs)
|
||||
A.hacker = null
|
||||
hacked_apcs = null
|
||||
// Reset our verbs
|
||||
src.verbs = null
|
||||
add_ai_verbs()
|
||||
// Let them know.
|
||||
user << "You are no longer malfunctioning. Your abilities have been removed."
|
||||
|
||||
// Called every tick. Checks if AI is malfunctioning. If yes calls Process on research datum which handles all logic.
|
||||
/mob/living/silicon/ai/proc/malf_process()
|
||||
if(!malfunctioning)
|
||||
return
|
||||
if(!research)
|
||||
if(!errored)
|
||||
errored = 1
|
||||
error("malf_process() called on AI without research datum. Report this.")
|
||||
message_admins("ERROR: malf_process() called on AI without research datum. If admin modified one of the AI's vars revert the change and don't modify variables directly, instead use ProcCall or admin panels.")
|
||||
spawn(1200)
|
||||
errored = 0
|
||||
return
|
||||
recalc_cpu()
|
||||
if(APU_power || aiRestorePowerRoutine != 0)
|
||||
research.process(1)
|
||||
else
|
||||
research.process(0)
|
||||
|
||||
// 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
|
||||
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
|
||||
if(hardware && istype(hardware, /datum/malf_hardware/dual_cpu))
|
||||
research.cpu_increase_per_tick = research.cpu_increase_per_tick * 2
|
||||
|
||||
// Starts AI's APU generator
|
||||
/mob/living/silicon/ai/proc/start_apu(var/shutup = 0)
|
||||
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
|
||||
if(!shutup)
|
||||
src << "You do not have an APU generator and you shouldn't have this verb. Report this."
|
||||
return
|
||||
if(hardware_integrity() < 50)
|
||||
if(!shutup)
|
||||
src << "<span class='notice'>Starting APU... <b>FAULT</b>(System Damaged)</span>"
|
||||
return
|
||||
if(!shutup)
|
||||
src << "Starting APU... ONLINE"
|
||||
APU_power = 1
|
||||
|
||||
// Stops AI's APU generator
|
||||
/mob/living/silicon/ai/proc/stop_apu(var/shutup = 0)
|
||||
if(!hardware || !istype(hardware, /datum/malf_hardware/apu_gen))
|
||||
return
|
||||
|
||||
if(APU_power)
|
||||
APU_power = 0
|
||||
if(!shutup)
|
||||
src << "Shutting down APU... DONE"
|
||||
|
||||
// Returns percentage of AI's remaining backup capacitor charge (maxhealth - oxyloss).
|
||||
/mob/living/silicon/ai/proc/backup_capacitor()
|
||||
return ((200 - getOxyLoss()) / 2)
|
||||
|
||||
// Returns percentage of AI's remaining hardware integrity (maxhealth - (bruteloss + fireloss))
|
||||
/mob/living/silicon/ai/proc/hardware_integrity()
|
||||
return (health-config.health_threshold_dead)/2
|
||||
|
||||
// Shows capacitor charge and hardware integrity information to the AI in Status tab.
|
||||
/mob/living/silicon/ai/show_system_integrity()
|
||||
if(!src.stat)
|
||||
stat(null, text("Hardware integrity: [hardware_integrity()]%"))
|
||||
stat(null, text("Internal capacitor: [backup_capacitor()]%"))
|
||||
else
|
||||
stat(null, text("Systems nonfunctional"))
|
||||
|
||||
// Shows AI Malfunction related information to the AI.
|
||||
/mob/living/silicon/ai/show_malf_ai()
|
||||
if(src.is_malf())
|
||||
stat(null, "Hacked APCs: [src.hacked_apcs.len]")
|
||||
stat(null, "System Status: [src.hacking ? "Busy" : "Stand-By"]")
|
||||
if(src.research)
|
||||
stat(null, "Available CPU: [src.research.stored_cpu] TFlops")
|
||||
stat(null, "Maximal CPU: [src.research.max_cpu] TFlops")
|
||||
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)]")
|
||||
if(system_override == 1)
|
||||
stat(null, "SYSTEM OVERRIDE INITIATED")
|
||||
else if(system_override == 2)
|
||||
stat(null, "SYSTEM OVERRIDE COMPLETED")
|
||||
|
||||
// Cleaner proc for creating powersupply for an AI.
|
||||
/mob/living/silicon/ai/proc/create_powersupply()
|
||||
if(psupply)
|
||||
del(psupply)
|
||||
psupply = new/obj/machinery/ai_powersupply(src)
|
||||
|
||||
#undef AI_CHECK_WIRELESS
|
||||
#undef AI_CHECK_RADIO
|
||||
#undef AI_CHECK_RADIO
|
||||
@@ -35,7 +35,7 @@
|
||||
break
|
||||
callshuttle++
|
||||
|
||||
if(ticker.mode.name == "revolution" || ticker.mode.name == "AI malfunction")
|
||||
if(ticker.mode.name == "revolution")
|
||||
callshuttle = 0
|
||||
|
||||
if(callshuttle == 3) //if all three conditions are met
|
||||
@@ -43,10 +43,6 @@
|
||||
log_game("All the AIs, comm consoles and boards are destroyed. Shuttle called.")
|
||||
message_admins("All the AIs, comm consoles and boards are destroyed. Shuttle called.", 1)
|
||||
|
||||
if(explosive)
|
||||
spawn(10)
|
||||
explosion(src.loc, 3, 6, 12, 15)
|
||||
|
||||
for(var/obj/machinery/ai_status_display/O in world)
|
||||
spawn( 0 )
|
||||
O.mode = 2
|
||||
|
||||
@@ -12,70 +12,51 @@
|
||||
|
||||
src.updatehealth()
|
||||
|
||||
if (src.malfhack)
|
||||
if (src.malfhack.aidisabled)
|
||||
src << "\red ERROR: APC access disabled, hack attempt canceled."
|
||||
src.malfhacking = 0
|
||||
src.malfhack = null
|
||||
|
||||
|
||||
if (src.health <= config.health_threshold_dead)
|
||||
if (!hardware_integrity() || !backup_capacitor())
|
||||
death()
|
||||
return
|
||||
|
||||
// If our powersupply object was destroyed somehow, create new one.
|
||||
if(!psupply)
|
||||
create_powersupply()
|
||||
|
||||
if (src.machine)
|
||||
if (!( src.machine.check_eye(src) ))
|
||||
src.reset_view(null)
|
||||
|
||||
// Handle power damage (oxy)
|
||||
if(src:aiRestorePowerRoutine != 0)
|
||||
// Lost power
|
||||
if(src:aiRestorePowerRoutine != 0 && !APU_power)
|
||||
// Lose power
|
||||
adjustOxyLoss(1)
|
||||
else
|
||||
// Gain Power
|
||||
aiRestorePowerRoutine = 0 // Necessary if AI activated it's APU AFTER losing primary power.
|
||||
adjustOxyLoss(-1)
|
||||
|
||||
// Handle EMP-stun
|
||||
handle_stunned()
|
||||
|
||||
//stage = 1
|
||||
//if (istype(src, /mob/living/silicon/ai)) // Are we not sure what we are?
|
||||
malf_process()
|
||||
|
||||
if(APU_power && (hardware_integrity() < 50))
|
||||
src << "<span class='notice'><b>APU GENERATOR FAILURE! (System Damaged)</b></span>"
|
||||
stop_apu(1)
|
||||
|
||||
var/blind = 0
|
||||
//stage = 2
|
||||
var/area/loc = null
|
||||
if (istype(T, /turf))
|
||||
//stage = 3
|
||||
loc = T.loc
|
||||
if (istype(loc, /area))
|
||||
//stage = 4
|
||||
if (!loc.master.power_equip && !istype(src.loc,/obj/item))
|
||||
//stage = 5
|
||||
if (!loc.master.power_equip && !istype(src.loc,/obj/item) && !APU_power)
|
||||
blind = 1
|
||||
|
||||
if (!blind) //lol? if(!blind) #if(src.blind.layer) <--something here is clearly wrong :P
|
||||
//I'll get back to this when I find out how this is -supposed- to work ~Carn //removed this shit since it was confusing as all hell --39kk9t
|
||||
//stage = 4.5
|
||||
if (!blind)
|
||||
src.sight |= SEE_TURFS
|
||||
src.sight |= SEE_MOBS
|
||||
src.sight |= SEE_OBJS
|
||||
src.see_in_dark = 8
|
||||
src.see_invisible = SEE_INVISIBLE_LIVING
|
||||
|
||||
|
||||
//Congratulations! You've found a way for AI's to run without using power!
|
||||
//Todo: Without snowflaking up master_controller procs find a way to make AI use_power but only when APC's clear the area usage the tick prior
|
||||
// since mobs are in master_controller before machinery. We also have to do it in a manner where we don't reset the entire area's need to update
|
||||
// the power usage.
|
||||
//
|
||||
// We can probably create a new machine that resides inside of the AI contents that uses power using the idle_usage of 1000 and nothing else and
|
||||
// be fine.
|
||||
/*
|
||||
var/area/home = get_area(src)
|
||||
if(!home) return//something to do with malf fucking things up I guess. <-- aisat is gone. is this still necessary? ~Carn
|
||||
if(home.powered(EQUIP))
|
||||
home.use_power(1000, EQUIP)
|
||||
*/
|
||||
|
||||
if (src:aiRestorePowerRoutine==2)
|
||||
src << "Alert cancelled. Power has been restored without our assistance."
|
||||
src:aiRestorePowerRoutine = 0
|
||||
@@ -86,14 +67,15 @@
|
||||
src:aiRestorePowerRoutine = 0
|
||||
src.blind.layer = 0
|
||||
return
|
||||
else if (APU_power)
|
||||
src:aiRestorePowerRoutine = 0
|
||||
src.blind.layer = 0
|
||||
return
|
||||
else
|
||||
|
||||
//stage = 6
|
||||
|
||||
var/area/current_area = get_area(src)
|
||||
|
||||
if (((!loc.master.power_equip) && current_area.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item))
|
||||
//If our area lacks equipment power, and is not magically powered (i.e. centcom), or if we are in space and not carded, lose power.
|
||||
if ((((!loc.master.power_equip) && current_area.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item)) && !APU_power)
|
||||
//If our area lacks equipment power, and is not magically powered (i.e. centcom), or if we are in space and not carded and without active APU, lose power.
|
||||
if (src:aiRestorePowerRoutine==0)
|
||||
src:aiRestorePowerRoutine = 1
|
||||
|
||||
@@ -183,11 +165,9 @@
|
||||
if(status_flags & GODMODE)
|
||||
health = 100
|
||||
stat = CONSCIOUS
|
||||
setOxyLoss(0)
|
||||
else
|
||||
if(fire_res_on_core)
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getBruteLoss()
|
||||
else
|
||||
health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss()
|
||||
health = 100 - getFireLoss() - getBruteLoss() // Oxyloss is not part of health as it represents AIs backup power. AI is immune against ToxLoss as it is machine.
|
||||
|
||||
/mob/living/silicon/ai/rejuvenate()
|
||||
..()
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/mob/living/silicon/ai/say(var/message)
|
||||
if(parent && istype(parent) && parent.stat != 2)
|
||||
return parent.say(message)
|
||||
//If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
|
||||
return ..(message)
|
||||
@@ -509,19 +509,6 @@
|
||||
C.toggled = 1
|
||||
src << "\red You enable [C.name]."
|
||||
|
||||
// this function shows information about the malf_ai gameplay type in the status screen
|
||||
/mob/living/silicon/robot/show_malf_ai()
|
||||
..()
|
||||
for (var/datum/mind/malfai in malf.current_antagonists)
|
||||
if(connected_ai)
|
||||
if(connected_ai.mind == malfai)
|
||||
if(malf.hacked_apcs >= 3)
|
||||
stat(null, "Time until station control secured: [max(malf.hack_time/(malf.hacked_apcs/3), 0)] seconds")
|
||||
else if(malf.revealed)
|
||||
stat(null, "Time left: [max(malf.hack_time/(malf.hacked_apcs.len/3), 0)]")
|
||||
return 0
|
||||
|
||||
|
||||
// this function displays jetpack pressure in the stat panel
|
||||
/mob/living/silicon/robot/proc/show_jetpack_pressure()
|
||||
// if you have a jetpack, show the internal tank pressure
|
||||
|
||||
+56
-76
@@ -83,17 +83,13 @@
|
||||
var/lastused_charging = 0
|
||||
var/lastused_total = 0
|
||||
var/main_status = 0
|
||||
var/mob/living/silicon/ai/hacker = null // Malfunction var. If set AI hacked the APC and has full control.
|
||||
var/wiresexposed = 0
|
||||
powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
|
||||
var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
|
||||
var/mob/living/silicon/ai/malfai = null //See above --NeoFite
|
||||
var/debug= 0
|
||||
var/autoflag= 0 // 0 = off, 1= eqp and lights off, 2 = eqp off, 3 = all on.
|
||||
// luminosity = 1
|
||||
var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver
|
||||
var/overload = 1 //used for the Blackout malf module
|
||||
var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment
|
||||
var/mob/living/silicon/ai/occupier = null
|
||||
var/longtermpower = 10
|
||||
var/datum/wires/apc/wires = null
|
||||
var/update_state = -1
|
||||
@@ -170,8 +166,6 @@
|
||||
src.update()
|
||||
|
||||
/obj/machinery/power/apc/Del()
|
||||
if(operating && malf && src.z in config.station_levels) //if (is_type_in_list(get_area(src), the_station_areas))
|
||||
malf.hacked_apcs -= src
|
||||
area.power_light = 0
|
||||
area.power_equip = 0
|
||||
area.power_environ = 0
|
||||
@@ -182,6 +176,10 @@
|
||||
if(terminal)
|
||||
disconnect_terminal()
|
||||
|
||||
// Malf AI, removes the APC from AI's hacked APCs list.
|
||||
if(hacker && hacker.hacked_apcs && src in hacker.hacked_apcs)
|
||||
hacker.hacked_apcs -= src
|
||||
|
||||
..()
|
||||
|
||||
/obj/machinery/power/apc/proc/make_terminal()
|
||||
@@ -234,8 +232,8 @@
|
||||
else
|
||||
if (stat & MAINT)
|
||||
user << "The cover is closed. Something wrong with it: it doesn't work."
|
||||
else if (malfhack)
|
||||
user << "The cover is broken. It may be hard to force it open."
|
||||
else if (hacker)
|
||||
user << "The cover is locked."
|
||||
else
|
||||
user << "The cover is closed."
|
||||
|
||||
@@ -339,7 +337,7 @@
|
||||
update_state |= UPSTATE_OPENED1
|
||||
if(opened==2)
|
||||
update_state |= UPSTATE_OPENED2
|
||||
else if(emagged || malfai)
|
||||
else if(emagged || hacker)
|
||||
update_state |= UPSTATE_BLUESCREEN
|
||||
else if(wiresexposed)
|
||||
update_state |= UPSTATE_WIREEXP
|
||||
@@ -418,7 +416,7 @@
|
||||
if(do_after(user, 50))
|
||||
if (has_electronics==1)
|
||||
has_electronics = 0
|
||||
if ((stat & BROKEN) || malfhack)
|
||||
if ((stat & BROKEN))
|
||||
user.visible_message(\
|
||||
"<span class='warning'>[user.name] has broken the power control board inside [src.name]!</span>",\
|
||||
"<span class='notice'>You broke the charred power control board and remove the remains.</span>",
|
||||
@@ -432,7 +430,7 @@
|
||||
else if (opened!=2) //cover isn't removed
|
||||
opened = 0
|
||||
update_icon()
|
||||
else if (istype(W, /obj/item/weapon/crowbar) && !((stat & BROKEN) || malfhack) )
|
||||
else if (istype(W, /obj/item/weapon/crowbar) && !((stat & BROKEN) || hacker) )
|
||||
if(coverlocked && !(stat & MAINT))
|
||||
user << "<span class='warning'>The cover is locked and cannot be opened.</span>"
|
||||
return
|
||||
@@ -491,6 +489,8 @@
|
||||
user << "You must close the panel"
|
||||
else if(stat & (BROKEN|MAINT))
|
||||
user << "Nothing happens."
|
||||
else if(hacker)
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
else
|
||||
if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
|
||||
locked = !locked
|
||||
@@ -498,7 +498,7 @@
|
||||
update_icon()
|
||||
else
|
||||
user << "<span class='warning'>Access denied.</span>"
|
||||
else if (istype(W, /obj/item/weapon/card/emag) && !(emagged || malfhack)) // trying to unlock with an emag card
|
||||
else if (istype(W, /obj/item/weapon/card/emag) && !(emagged || hacker)) // trying to unlock with an emag card
|
||||
if(opened)
|
||||
user << "You must close the cover to swipe an ID card."
|
||||
else if(wiresexposed)
|
||||
@@ -560,7 +560,7 @@
|
||||
new /obj/item/stack/cable_coil(loc,10)
|
||||
user << "<span class='notice'>You cut the cables and dismantle the power terminal.</span>"
|
||||
del(terminal) // qdel
|
||||
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN) || malfhack))
|
||||
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN)))
|
||||
user.visible_message("<span class='warning'>[user.name] inserts the power control board into [src].</span>", \
|
||||
"You start to insert the power control board into the frame...")
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
@@ -569,7 +569,7 @@
|
||||
has_electronics = 1
|
||||
user << "<span class='notice'>You place the power control board inside the frame.</span>"
|
||||
del(W) // qdel
|
||||
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN) || malfhack))
|
||||
else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN)))
|
||||
user << "<span class='warning'>You cannot put the board inside, the frame is damaged.</span>"
|
||||
return
|
||||
else if (istype(W, /obj/item/weapon/weldingtool) && opened && has_electronics==0 && !terminal)
|
||||
@@ -583,7 +583,7 @@
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
|
||||
if(do_after(user, 50))
|
||||
if(!src || !WT.remove_fuel(3, user)) return
|
||||
if (emagged || malfhack || (stat & BROKEN) || opened==2)
|
||||
if (emagged || (stat & BROKEN) || opened==2)
|
||||
new /obj/item/stack/sheet/metal(loc)
|
||||
user.visible_message(\
|
||||
"<span class='warning'>[src] has been cut apart by [user.name] with the weldingtool.</span>",\
|
||||
@@ -606,7 +606,7 @@
|
||||
"<span class='notice'>You replace the damaged APC frontal panel with a new one.</span>")
|
||||
del(W) // qdel
|
||||
update_icon()
|
||||
else if (istype(W, /obj/item/apc_frame) && opened && ((stat & BROKEN) || malfhack))
|
||||
else if (istype(W, /obj/item/apc_frame) && opened && ((stat & BROKEN) || hacker))
|
||||
if (has_electronics)
|
||||
user << "<span class='warning'>You cannot repair this APC until you remove the electronics still inside.</span>"
|
||||
return
|
||||
@@ -618,13 +618,12 @@
|
||||
"You replace the damaged APC frame with new one.")
|
||||
del(W) // qdel
|
||||
stat &= ~BROKEN
|
||||
malfai = null
|
||||
malfhack = 0
|
||||
hacker = null
|
||||
if (opened==2)
|
||||
opened = 1
|
||||
update_icon()
|
||||
else
|
||||
if (((stat & BROKEN) || malfhack) \
|
||||
if (((stat & BROKEN) || hacker) \
|
||||
&& !opened \
|
||||
&& W.force >= 5 \
|
||||
&& W.w_class >= 3.0 \
|
||||
@@ -736,7 +735,7 @@
|
||||
|
||||
return ui_interact(user)
|
||||
|
||||
|
||||
/*
|
||||
/obj/machinery/power/apc/proc/get_malf_status(mob/user)
|
||||
if (malf && (user.mind in malf.current_antagonists) && istype(user, /mob/living/silicon/ai))
|
||||
if (src.malfai == (user:parent ? user:parent : user))
|
||||
@@ -750,7 +749,7 @@
|
||||
return 1 // 1 = APC not hacked.
|
||||
else
|
||||
return 0 // 0 = User is not a Malf AI
|
||||
|
||||
*/
|
||||
|
||||
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!user)
|
||||
@@ -767,7 +766,7 @@
|
||||
"totalCharging" = round(lastused_charging),
|
||||
"coverLocked" = coverlocked,
|
||||
"siliconUser" = istype(user, /mob/living/silicon),
|
||||
"malfStatus" = get_malf_status(user),
|
||||
/*"malfStatus" = get_malf_status(user),*/
|
||||
|
||||
"powerChannels" = list(
|
||||
list(
|
||||
@@ -857,23 +856,22 @@
|
||||
return 0
|
||||
autoflag = 5
|
||||
if (istype(user, /mob/living/silicon))
|
||||
var/permit = 0 // Malfunction variable. If AI hacks APC it can control it even without AI control wire.
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
var/mob/living/silicon/robot/robot = user
|
||||
if ( \
|
||||
src.aidisabled || \
|
||||
malfhack && istype(malfai) && \
|
||||
( \
|
||||
(istype(AI) && (malfai!=AI && malfai != AI.parent)) || \
|
||||
(istype(robot) && (robot in malfai.connected_robots)) \
|
||||
) \
|
||||
)
|
||||
if(hacker)
|
||||
if(hacker == AI)
|
||||
permit = 1
|
||||
else if(istype(robot) && robot.connected_ai && robot.connected_ai == hacker) // Cyborgs can use APCs hacked by their AI
|
||||
permit = 1
|
||||
|
||||
if(aidisabled && !permit)
|
||||
if(!loud)
|
||||
user << "<span class='danger'>\The [src] have AI control disabled!</span>"
|
||||
return 0
|
||||
else
|
||||
if ((!in_range(src, user) || !istype(src.loc, /turf)))
|
||||
if ((!in_range(src, user) || !istype(src.loc, /turf) || hacker)) // AI-hacked APCs cannot be controlled by other AIs, unlinked cyborgs or humans.
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (istype(H))
|
||||
if(H.getBrainLoss() >= 60)
|
||||
@@ -930,28 +928,6 @@
|
||||
if(istype(usr, /mob/living/silicon))
|
||||
src.overload_lighting()
|
||||
|
||||
else if (href_list["malfhack"])
|
||||
var/mob/living/silicon/ai/malfai = usr
|
||||
if(get_malf_status(malfai)==1)
|
||||
if (malfai.malfhacking)
|
||||
malfai << "You are already hacking an APC."
|
||||
return 1
|
||||
malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
|
||||
malfai.malfhack = src
|
||||
malfai.malfhacking = 1
|
||||
sleep(600)
|
||||
if(src)
|
||||
if (!src.aidisabled)
|
||||
malfai.malfhack = null
|
||||
malfai.malfhacking = 0
|
||||
locked = 1
|
||||
if(usr:parent)
|
||||
src.malfai = usr:parent
|
||||
else
|
||||
src.malfai = usr
|
||||
malfai << "Hack complete. The APC is now under your exclusive control."
|
||||
update_icon()
|
||||
|
||||
else if (href_list["toggleaccess"])
|
||||
if(istype(usr, /mob/living/silicon))
|
||||
if(emagged || (stat & (BROKEN|MAINT)))
|
||||
@@ -968,25 +944,21 @@
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/proc/ion_act()
|
||||
//intended to be exactly the same as an AI malf attack
|
||||
if(!src.malfhack && src.z in config.station_levels)
|
||||
if(prob(3))
|
||||
src.locked = 1
|
||||
if (src.cell.charge > 0)
|
||||
// world << "\red blew APC in [src.loc.loc]"
|
||||
src.cell.charge = 0
|
||||
cell.corrupt()
|
||||
src.malfhack = 1
|
||||
update_icon()
|
||||
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
|
||||
smoke.set_up(3, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
visible_message("<span class='danger'>The [src.name] suddenly lets out a blast of smoke and some sparks!</span>", \
|
||||
"<span class='danger'>You hear sizzling electronics.</span>")
|
||||
if(prob(3))
|
||||
src.locked = 1
|
||||
if (src.cell.charge > 0)
|
||||
src.cell.charge = 0
|
||||
cell.corrupt()
|
||||
update_icon()
|
||||
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
|
||||
smoke.set_up(3, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
visible_message("<span class='danger'>The [src.name] suddenly lets out a blast of smoke and some sparks!</span>", \
|
||||
"<span class='danger'>You hear sizzling electronics.</span>")
|
||||
|
||||
|
||||
/obj/machinery/power/apc/surplus()
|
||||
@@ -1189,8 +1161,6 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on)
|
||||
/obj/machinery/power/apc/emp_act(severity)
|
||||
if(cell)
|
||||
cell.emp_act(severity)
|
||||
if(occupier)
|
||||
occupier.emp_act(severity)
|
||||
|
||||
lighting = 0
|
||||
equipment = 0
|
||||
@@ -1266,4 +1236,14 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on)
|
||||
else
|
||||
return 0
|
||||
|
||||
// Malfunction: Transfers APC under AI's control
|
||||
/obj/machinery/power/apc/proc/ai_hack(var/mob/living/silicon/ai/A = null)
|
||||
if(!A || !A.hacked_apcs || hacker || aidisabled || A.stat == DEAD)
|
||||
return 0
|
||||
src.hacker = A
|
||||
A.hacked_apcs += src
|
||||
locked = 1
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
#undef APC_UPDATE_ICON_COOLDOWN
|
||||
|
||||
@@ -12,6 +12,21 @@
|
||||
var/shield_generate_power = 7500 //how much power we use when regenerating
|
||||
var/shield_idle_power = 1500 //how much power we use when just being sustained.
|
||||
|
||||
/obj/machinery/shield/malfai
|
||||
name = "Emergency Forcefield"
|
||||
desc = "Weak forcefield which seems to be projected by station's emergency atmosphere containment field"
|
||||
health = max_health/2 // Half health, it's not suposed to resist much.
|
||||
|
||||
/obj/machinery/shield/malfai/process()
|
||||
health -= 0.5 // Slowly lose integrity over time
|
||||
check_failure()
|
||||
|
||||
/obj/machinery/shield/proc/check_failure()
|
||||
if (src.health <= 0)
|
||||
visible_message("\blue The [src] dissipates!")
|
||||
del(src)
|
||||
return
|
||||
|
||||
/obj/machinery/shield/New()
|
||||
src.set_dir(pick(1,2,3,4))
|
||||
..()
|
||||
@@ -38,11 +53,7 @@
|
||||
//Play a fitting sound
|
||||
playsound(src.loc, 'sound/effects/EMPulse.ogg', 75, 1)
|
||||
|
||||
|
||||
if (src.health <= 0)
|
||||
visible_message("\blue The [src] dissipates!")
|
||||
del(src)
|
||||
return
|
||||
check_failure()
|
||||
|
||||
opacity = 1
|
||||
spawn(20) if(src) opacity = 0
|
||||
@@ -51,12 +62,7 @@
|
||||
|
||||
/obj/machinery/shield/meteorhit()
|
||||
src.health -= max_health*0.75 //3/4 health as damage
|
||||
|
||||
if(src.health <= 0)
|
||||
visible_message("\blue The [src] dissipates!")
|
||||
del(src)
|
||||
return
|
||||
|
||||
check_failure()
|
||||
opacity = 1
|
||||
spawn(20) if(src) opacity = 0
|
||||
return
|
||||
@@ -64,10 +70,7 @@
|
||||
/obj/machinery/shield/bullet_act(var/obj/item/projectile/Proj)
|
||||
health -= Proj.damage
|
||||
..()
|
||||
if(health <=0)
|
||||
visible_message("\blue The [src] dissipates!")
|
||||
del(src)
|
||||
return
|
||||
check_failure()
|
||||
opacity = 1
|
||||
spawn(20) if(src) opacity = 0
|
||||
|
||||
@@ -112,11 +115,7 @@
|
||||
//This seemed to be the best sound for hitting a force field.
|
||||
playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1)
|
||||
|
||||
//Handle the destruction of the shield
|
||||
if (src.health <= 0)
|
||||
visible_message("\blue The [src] dissipates!")
|
||||
del(src)
|
||||
return
|
||||
check_failure()
|
||||
|
||||
//The shield becomes dense to absorb the blow.. purely asthetic.
|
||||
opacity = 1
|
||||
@@ -124,9 +123,6 @@
|
||||
|
||||
..()
|
||||
return
|
||||
|
||||
|
||||
|
||||
/obj/machinery/shieldgen
|
||||
name = "Emergency shield projector"
|
||||
desc = "Used to seal minor hull breaches."
|
||||
@@ -161,7 +157,7 @@
|
||||
update_icon()
|
||||
|
||||
create_shields()
|
||||
|
||||
|
||||
idle_power_usage = 0
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
idle_power_usage += shield_tile.shield_idle_power
|
||||
@@ -174,7 +170,7 @@
|
||||
update_icon()
|
||||
|
||||
collapse_shields()
|
||||
|
||||
|
||||
update_use_power(0)
|
||||
|
||||
/obj/machinery/shieldgen/proc/create_shields()
|
||||
@@ -201,22 +197,22 @@
|
||||
/obj/machinery/shieldgen/process()
|
||||
if (!active || (stat & NOPOWER))
|
||||
return
|
||||
|
||||
|
||||
if(malfunction)
|
||||
if(deployed_shields.len && prob(5))
|
||||
del(pick(deployed_shields))
|
||||
else
|
||||
if (check_delay <= 0)
|
||||
create_shields()
|
||||
|
||||
|
||||
var/new_power_usage = 0
|
||||
for(var/obj/machinery/shield/shield_tile in deployed_shields)
|
||||
new_power_usage += shield_tile.shield_idle_power
|
||||
|
||||
|
||||
if (new_power_usage != idle_power_usage)
|
||||
idle_power_usage = new_power_usage
|
||||
use_power(0)
|
||||
|
||||
|
||||
check_delay = 60
|
||||
else
|
||||
check_delay--
|
||||
|
||||
Reference in New Issue
Block a user