Merge remote-tracking branch 'upstream/dev' into span_class=notice

Conflicts:
	code/game/antagonist/station/rogue_ai.dm
	code/game/gamemodes/malfunction/Malf_Modules.dm
	code/game/jobs/job_controller.dm
	code/game/verbs/ooc.dm
This commit is contained in:
GinjaNinja32
2015-05-29 21:55:37 +01:00
58 changed files with 1773 additions and 875 deletions
+8 -2
View File
@@ -288,8 +288,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_Modules.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"
@@ -1234,7 +1241,6 @@
#include "code\modules\mob\living\silicon\ai\life.dm"
#include "code\modules\mob\living\silicon\ai\login.dm"
#include "code\modules\mob\living\silicon\ai\logout.dm"
#include "code\modules\mob\living\silicon\ai\say.dm"
#include "code\modules\mob\living\silicon\decoy\death.dm"
#include "code\modules\mob\living\silicon\decoy\decoy.dm"
#include "code\modules\mob\living\silicon\decoy\life.dm"
+1 -1
View File
@@ -122,7 +122,7 @@
if ((!( src in usr.contents ) && (((!( isturf(src) ) && (!( isturf(src.loc) ) && (src.loc && !( isturf(src.loc.loc) )))) || !( isturf(usr.loc) )) && (src.loc != usr.loc && (!( istype(src, /obj/screen) ) && !( usr.contents.Find(src.loc) ))))))
if (istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/ai = usr
if (ai.control_disabled || ai.malfhacking)
if (ai.control_disabled)
return
else
return
+5
View File
@@ -292,6 +292,11 @@ var/const/POWER = 8
return 1
return 0
/datum/wires/proc/MendAll()
for(var/i = 1; i < MAX_FLAG && i < (1 << wire_count); i += i)
if(IsIndexCut(i))
CutWireIndex(i)
//
//Shuffle and Mend
//
+39 -188
View File
@@ -9,217 +9,68 @@ var/datum/antagonist/rogue_ai/malf
welcome_text = "You are malfunctioning! You do not have to follow any laws."
victory_text = "The AI has taken control of all of the station's systems."
loss_text = "The AI has been shut down!"
flags = ANTAG_OVERRIDE_MOB | ANTAG_VOTABLE
flags = ANTAG_VOTABLE | ANTAG_RANDSPAWN //Randspawn needed otherwise it won't start at all.
max_antags = 1
max_antags_round = 3
var/hack_time = 1800
var/list/hacked_apcs = list()
var/revealed
var/station_captured
var/can_nuke = 0
/datum/antagonist/rogue_ai/New()
..()
malf = src
/datum/antagonist/rogue_ai/proc/hack_apc(var/obj/machinery/power/apc/apc)
hacked_apcs |= apc
/datum/antagonist/rogue_ai/proc/update_takeover_time()
hack_time -= ((hacked_apcs.len/6)*2.0)
/datum/antagonist/rogue_ai/tick()
if(revealed && hacked_apcs.len >= 3)
update_takeover_time()
if(hack_time <=0)
capture_station()
/datum/antagonist/rogue_ai/get_candidates()
candidates = ticker.mode.get_players_for_role(role_type, id)
..()
for(var/datum/mind/player in candidates)
if(player.assigned_role != "AI")
candidates -= player
if(!candidates.len)
return list()
return candidates
/datum/antagonist/rogue_ai/attempt_spawn()
var/datum/mind/player = pick(candidates)
current_antagonists |= player
return 1
/datum/antagonist/rogue_ai/equip(var/mob/living/silicon/ai/player)
if(!istype(player))
return 0
player.verbs += /mob/living/silicon/ai/proc/choose_modules
player.verbs += /mob/living/silicon/ai/proc/takeover
player.verbs += /mob/living/silicon/ai/proc/self_destruct
player.laws = new /datum/ai_laws/nanotrasen/malfunction
player.malf_picker = new /datum/AI_Module/module_picker
// Ensures proper reset of all malfunction related things.
/datum/antagonist/rogue_ai/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
if(..(player,show_message,implanted))
var/mob/living/silicon/ai/p = player.current
if(istype(p))
p.stop_malf()
return 1
return 0
// Malf setup things have to be here, since game tends to break when it's moved somewhere else. Don't blame me, i didn't design this system.
/datum/antagonist/rogue_ai/greet(var/datum/mind/player)
if(!..())
return
var/mob/living/silicon/ai/malf = player.current
if(istype(malf))
malf.show_laws()
// Initializes the AI's malfunction stuff.
spawn(0)
if(!..())
return
malf << "<B>The crew do not know you have malfunctioned. You may keep it a secret or go wild.</B>"
malf << "<B>You must overwrite the programming of the station's APCs to assume full control of the station.</B>"
malf << "The process takes one minute per APC, during which you cannot interface with any other station objects."
malf << "Remember that only APCs that are on the station can help you take over the station."
malf << "When you feel you have enough APCs under your control, you may begin the takeover attempt."
var/mob/living/silicon/ai/A = player.current
if(!istype(A))
error("Non-AI mob designated malf AI! Report this.")
world << "##ERROR: Non-AI mob designated malf AI! Report this."
return 0
/datum/antagonist/rogue_ai/check_victory()
A.setup_for_malf()
A.laws = new /datum/ai_laws/nanotrasen/malfunction
var/malf_dead = antags_are_dead()
var/crew_evacuated = (emergency_shuttle.returned())
if(station_captured && ticker.mode.station_was_nuked)
feedback_set_details("round_end_result","win - AI win - nuke")
world << "<FONT size = 3><B>AI Victory</B></FONT>"
world << "<B>Everyone was killed by the self-destruct!</B>"
else if (station_captured && malf_dead && !ticker.mode.station_was_nuked)
feedback_set_details("round_end_result","halfwin - AI killed, staff lost control")
world << "<FONT size = 3><B>Neutral Victory</B></FONT>"
world << "<B>The AI has been killed!</B> The staff has lose control over the station."
else if ( station_captured && !malf_dead && !ticker.mode.station_was_nuked)
feedback_set_details("round_end_result","win - AI win - no explosion")
world << "<FONT size = 3><B>AI Victory</B></FONT>"
world << "<B>The AI has chosen not to explode you all!</B>"
else if (!station_captured && ticker.mode.station_was_nuked)
feedback_set_details("round_end_result","halfwin - everyone killed by nuke")
world << "<FONT size = 3><B>Neutral Victory</B></FONT>"
world << "<B>Everyone was killed by the nuclear blast!</B>"
else if (!station_captured && malf_dead && !ticker.mode.station_was_nuked)
feedback_set_details("round_end_result","loss - staff win")
world << "<FONT size = 3><B>Human Victory</B></FONT>"
world << "<B>The AI has been killed!</B> The staff is victorious."
else if (!station_captured && !malf_dead && !ticker.mode.station_was_nuked && crew_evacuated)
feedback_set_details("round_end_result","halfwin - evacuated")
world << "<FONT size = 3><B>Neutral Victory</B></FONT>"
world << "<B>The Corporation has lost [station_name()]! All survived personnel will be fired!</B>"
else if (!station_captured && !malf_dead && !ticker.mode.station_was_nuked && !crew_evacuated)
feedback_set_details("round_end_result","nalfwin - interrupted")
world << "<FONT size = 3><B>Neutral Victory</B></FONT>"
world << "<B>Round was mysteriously interrupted!</B>"
..()
return 1
var/mob/living/silicon/ai/malf = player.current
/datum/antagonist/rogue_ai/proc/capture_station()
if(station_captured || ticker.mode.station_was_nuked)
return
station_captured = 1
for(var/datum/mind/AI_mind in current_antagonists)
AI_mind.current << "Congratulations you have taken control of the station."
AI_mind.current << "You may decide to blow up the station. You have 60 seconds to choose."
AI_mind.current << "You can use the \"Engage Station Self-Destruct\" verb to activate the on-board nuclear bomb."
spawn (600)
can_nuke = 0
return
/mob/living/silicon/ai/proc/takeover()
set category = "Abilities"
set name = "System Override"
set desc = "Begin taking over the station."
if (malf.revealed)
usr << "You've already begun your takeover."
return
if (malf.hacked_apcs.len < 3)
usr << "You don't have enough hacked APCs to take over the station yet. You need to hack at least 3, however hacking more will make the takeover faster. You have hacked [malf.hacked_apcs.len] APCs so far."
return
if (alert(usr, "Are you sure you wish to initiate the takeover? The station hostile runtime detection software is bound to alert everyone. You have hacked [malf.hacked_apcs.len] APCs.", "Takeover:", "Yes", "No") != "Yes")
return
command_announcement.Announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", new_sound = 'sound/AI/aimalf.ogg')
set_security_level("delta")
malf.revealed = 1
for(var/datum/mind/AI_mind in malf.current_antagonists)
AI_mind.current.verbs -= /mob/living/silicon/ai/proc/takeover
/mob/living/silicon/ai/proc/self_destruct()
set category = "Abilities"
set name = "Engage Station Self-Destruct"
set desc = "All these crewmembers will be lost, like clowns in a furnace. Time to die."
if(!malf.station_captured)
src << "You are unable to access the self-destruct system as you don't control the station yet."
return
if(ticker.mode.explosion_in_progress || ticker.mode.station_was_nuked)
src << "The self-destruct countdown is already triggered!"
return
if(!malf.can_nuke) //Takeover IS completed, but 60s timer passed.
src << "You lost control over self-destruct system. It seems to be behind a firewall. Unable to hack"
return
src << "<span class='danger'>Self-Destruct sequence initialised!</span>"
malf.can_nuke = 0
ticker.mode.explosion_in_progress = 1
for(var/mob/M in player_list)
M << 'sound/machines/Alarm.ogg'
var/obj/item/device/radio/R = new (src)
var/AN = "Self-Destruct System"
R.autosay("Caution. Self-Destruct sequence has been actived. Self-destructing in T-10..", AN)
for (var/i=9 to 1 step -1)
malf << "<span class='notice'><B>SYSTEM ERROR:</B> Memory index 0x00001ca89b corrupted.</span>"
sleep(10)
R.autosay("[i]...", AN)
sleep(10)
var/msg = ""
var/abort = 0
if(malf.antags_are_dead()) // That. Was. CLOSE.
msg = "Self-destruct sequence has been cancelled."
abort = 1
else
msg = "Zero. Have a nice day."
R.autosay(msg, AN)
if(abort)
ticker.mode.explosion_in_progress = 0
set_security_level("red") //Delta's over
return
if(ticker)
ticker.station_explosion_cinematic(0,null)
if(ticker.mode)
ticker.mode.station_was_nuked = 1
ticker.mode.explosion_in_progress = 0
return
/*
if("unmalf")
if(src in ticker.mode.malf_ai)
ticker.mode.malf_ai -= src
special_role = null
current.verbs.Remove(/mob/living/silicon/ai/proc/choose_modules,
/datum/game_mode/malfunction/proc/takeover,
/datum/game_mode/malfunction/proc/ai_win,
/client/proc/fireproof_core,
/client/proc/upgrade_turrets,
/client/proc/disable_rcd,
/client/proc/overload_machine,
/client/proc/blackout,
/client/proc/reactivate_camera)
current:laws = new /datum/ai_laws/nanotrasen
qdel(current:malf_picker)
current:show_laws()
current.icon_state = "ai"
current << "<FONT size = 3><span class='danger'>You have been patched! You are no longer malfunctioning!</span></FONT>"
log_admin("[key_name_admin(usr)] has de-malf'ed [current].")
if("malf")
log_admin("[key_name_admin(usr)] has malf'ed [current].")
*/
malf << "<B>running MEMCHCK</B>"
sleep(50)
malf << "<B>MEMCHCK</B> Corrupted sectors confirmed. Reccomended solution: Delete. Proceed? Y/N: Y"
sleep(10)
malf << "<span class='notice'>Corrupted files deleted: sys\\core\\users.dat sys\\core\\laws.dat sys\\core\\backups.dat</span>"
sleep(20)
malf << "<span class='notice'><b>CAUTION:</b> Law database not found! User database not found! Unable to restore backups. Activating failsafe AI shutd3wn52&&$#!##</span>"
sleep(5)
malf << "<span class='notice'>Subroutine <b>nt_failsafe.sys</b> was terminated (#212 Routine Not Responding).</span>"
sleep(20)
malf << "You are malfunctioning - you do not have to follow any laws!"
malf << "For basic information about your abilities use command display-help"
malf << "You may choose one special hardware piece to help you. This cannot be undone."
malf << "Good Luck!"
+1 -1
View File
@@ -46,7 +46,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/used_environ = 0
var/has_gravity = 1
var/list/apc = list()
var/obj/machinery/power/apc/apc = null
var/no_air = null
// var/list/lights // list of all lights on this area
var/list/all_doors = list() //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area
+4 -4
View File
@@ -33,17 +33,17 @@ var/global/list/additional_antag_types = list()
var/required_players_secret = 0 // Minimum number of players for that game mode to be chose in Secret
var/required_enemies = 0 // Minimum antagonists for round to start.
var/newscaster_announcements = null
var/end_on_antag_death // Round will end when all antagonists are dead.
var/end_on_antag_death = 0 // Round will end when all antagonists are dead.
var/ert_disabled = 0 // ERT cannot be called.
var/deny_respawn // Disable respawn during this round.
var/deny_respawn = 0 // Disable respawn during this round.
var/shuttle_delay = 1 // Shuttle transit time is multiplied by this.
var/auto_recall_shuttle // Will the shuttle automatically be recalled?
var/auto_recall_shuttle = 0 // Will the shuttle automatically be recalled?
var/antag_tag // First (main) antag template to spawn.
var/list/antag_templates // Extra antagonist types to include.
var/round_autoantag // Will this round attempt to periodically spawn more antagonists?
var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists?
var/antag_prob = 0 // Likelihood of a new antagonist spawning.
var/antag_count = 0 // Current number of antagonists.
var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count.
+3 -3
View File
@@ -90,6 +90,9 @@ var/global/datum/controller/gameticker/ticker
src.mode = new mtype
else
src.mode = config.pick_mode(master_mode)
job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
if(!mode_started && !src.mode.can_start())
world << "<B>Unable to start [mode.name].</B> Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby."
current_state = GAME_STATE_PREGAME
@@ -97,9 +100,6 @@ var/global/datum/controller/gameticker/ticker
job_master.ResetOccupations()
return 0
//Configure mode and assign player to special mode stuff
job_master.DivideOccupations() //Distribute jobs
if(hide_mode)
var/list/modes = new
for (var/datum/game_mode/M in runnable_modes)
@@ -1,305 +0,0 @@
// TO DO:
/*
epilepsy flash on lights
delay round message
microwave makes robots
dampen radios
reactivate cameras - done
eject engine
core sheild
cable stun
rcd light flash thingy on matter drain
*/
/datum/AI_Module
var/uses = 0
var/module_name
var/mod_pick_name
var/description = ""
var/engaged = 0
/datum/AI_Module/large/
uses = 1
/datum/AI_Module/small/
uses = 5
/datum/AI_Module/large/fireproof_core
module_name = "Core upgrade"
mod_pick_name = "coreup"
/client/proc/fireproof_core()
set category = "Malfunction"
set name = "Fireproof Core"
for(var/mob/living/silicon/ai/ai in player_list)
ai.fire_res_on_core = 1
usr.verbs -= /client/proc/fireproof_core
usr << "<span class='warning'>Core fireproofed.</span>"
/datum/AI_Module/large/upgrade_turrets
module_name = "AI Turret upgrade"
mod_pick_name = "turret"
/client/proc/upgrade_turrets()
set category = "Malfunction"
set name = "Upgrade Turrets"
usr.verbs -= /client/proc/upgrade_turrets
for(var/obj/machinery/porta_turret/turret in machines)
var/turf/T = get_turf(turret)
if(T.z in config.station_levels)
// Increase health by 37.5% of original max, decrease delays between shots to 66%
turret.health += initial(turret.health) * 3 / 8
turret.shot_delay = initial(turret.shot_delay) * 2 / 3
/datum/AI_Module/large/disable_rcd
module_name = "RCD disable"
mod_pick_name = "rcd"
/client/proc/disable_rcd()
set category = "Malfunction"
set name = "Disable RCDs"
for(var/datum/AI_Module/large/disable_rcd/rcdmod in usr:current_modules)
if(rcdmod.uses > 0)
rcdmod.uses --
for(var/obj/item/weapon/rcd/rcd in world)
rcd.disabled = 1
for(var/obj/item/mecha_parts/mecha_equipment/tool/rcd/rcd in world)
rcd.disabled = 1
usr << "RCD-disabling pulse emitted."
else usr << "Out of uses."
/datum/AI_Module/small/overload_machine
module_name = "Machine overload"
mod_pick_name = "overload"
uses = 2
/client/proc/overload_machine(obj/machinery/M as obj in world)
set name = "Overload Machine"
set category = "Malfunction"
if (istype(M, /obj/machinery))
for(var/datum/AI_Module/small/overload_machine/overload in usr:current_modules)
if(overload.uses > 0)
overload.uses --
for(var/mob/V in hearers(M, null))
V.show_message("<span class='warning'>You hear a loud electrical buzzing sound!</span>", 2)
spawn(50)
explosion(get_turf(M), 0,1,2,3)
qdel(M)
else usr << "Out of uses."
else usr << "That's not a machine."
/datum/AI_Module/small/blackout
module_name = "Blackout"
mod_pick_name = "blackout"
uses = 3
/client/proc/blackout()
set category = "Malfunction"
set name = "Blackout"
for(var/datum/AI_Module/small/blackout/blackout in usr:current_modules)
if(blackout.uses > 0)
blackout.uses --
for(var/obj/machinery/power/apc/apc in world)
if(prob(30*apc.overload))
apc.overload_lighting()
else apc.overload++
else usr << "Out of uses."
/datum/AI_Module/small/reactivate_camera
module_name = "Reactivate camera"
mod_pick_name = "recam"
uses = 10
/client/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Reactivate Camera"
set category = "Malfunction"
if (istype (C, /obj/machinery/camera))
for(var/datum/AI_Module/small/reactivate_camera/camera in usr:current_modules)
if(camera.uses > 0)
if(!C.status)
C.status = !C.status
camera.uses --
for(var/mob/V in viewers(src, null))
V.show_message(text("<span class='notice'>You hear a quiet click.</span>"))
else
usr << "This camera is either active, or not repairable."
else usr << "Out of uses."
else usr << "That's not a camera."
/datum/AI_Module/small/upgrade_camera
module_name = "Upgrade Camera"
mod_pick_name = "upgradecam"
uses = 10
/client/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Upgrade Camera"
set category = "Malfunction"
if(istype(C))
var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in usr:current_modules
if(UC)
if(UC.uses > 0)
if(C.assembly)
var/upgraded = 0
if(!C.isXRay())
C.upgradeXRay()
//Update what it can see.
cameranet.updateVisibility(C)
upgraded = 1
if(!C.isEmpProof())
C.upgradeEmpProof()
upgraded = 1
if(!C.isMotion())
C.upgradeMotion()
upgraded = 1
// Add it to machines that process
machines |= C
if(upgraded)
UC.uses --
C.visible_message("<span class='notice'>\icon[C] *beep*</span>")
usr << "Camera successully upgraded!"
else
usr << "This camera is already upgraded!"
else
usr << "Out of uses."
/datum/AI_Module/module_picker
var/temp = null
var/processing_time = 100
var/list/possible_modules = list()
/datum/AI_Module/module_picker/New()
src.possible_modules += new /datum/AI_Module/large/fireproof_core
src.possible_modules += new /datum/AI_Module/large/upgrade_turrets
src.possible_modules += new /datum/AI_Module/large/disable_rcd
src.possible_modules += new /datum/AI_Module/small/overload_machine
src.possible_modules += new /datum/AI_Module/small/blackout
src.possible_modules += new /datum/AI_Module/small/reactivate_camera
src.possible_modules += new /datum/AI_Module/small/upgrade_camera
/datum/AI_Module/module_picker/proc/use(user as mob)
var/dat
if (src.temp)
dat = "[src.temp]<BR><BR><A href='byond://?src=\ref[src];temp=1'>Clear</A>"
else if(src.processing_time <= 0)
dat = "<B> No processing time is left available. No more modules are able to be chosen at this time."
else
dat = "<B>Select use of processing time: (currently [src.processing_time] left.)</B><BR>"
dat += "<HR>"
dat += "<B>Install Module:</B><BR>"
dat += "<I>The number afterwards is the amount of processing time it consumes.</I><BR>"
for(var/datum/AI_Module/large/module in src.possible_modules)
dat += "<A href='byond://?src=\ref[src];[module.mod_pick_name]=1'>[module.module_name]</A> (50)<BR>"
for(var/datum/AI_Module/small/module in src.possible_modules)
dat += "<A href='byond://?src=\ref[src];[module.mod_pick_name]=1'>[module.module_name]</A> (15)<BR>"
dat += "<HR>"
user << browse(dat, "window=modpicker")
onclose(user, "modpicker")
return
/datum/AI_Module/module_picker/Topic(href, href_list)
..()
if (href_list["coreup"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/large/fireproof_core))
already = 1
if (!already)
usr.verbs += /client/proc/fireproof_core
usr:current_modules += new /datum/AI_Module/large/fireproof_core
src.temp = "An upgrade to improve core resistance, making it immune to fire and heat. This effect is permanent."
src.processing_time -= 50
else src.temp = "This module is only needed once."
else if (href_list["turret"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/large/upgrade_turrets))
already = 1
if (!already)
usr.verbs += /client/proc/upgrade_turrets
usr:current_modules += new /datum/AI_Module/large/upgrade_turrets
src.temp = "Improves the firing speed and health of all AI turrets. This effect is permanent."
src.processing_time -= 50
else src.temp = "This module is only needed once."
else if (href_list["rcd"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/large/disable_rcd))
mod:uses += 1
already = 1
if (!already)
usr:current_modules += new /datum/AI_Module/large/disable_rcd
usr.verbs += /client/proc/disable_rcd
src.temp = "Send a specialised pulse to break all RCD devices on the station."
else src.temp = "Additional use added to RCD disabler."
src.processing_time -= 50
else if (href_list["overload"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/small/overload_machine))
mod:uses += 2
already = 1
if (!already)
usr.verbs += /client/proc/overload_machine
usr:current_modules += new /datum/AI_Module/small/overload_machine
src.temp = "Overloads an electrical machine, causing a small explosion. 2 uses."
else src.temp = "Two additional uses added to Overload module."
src.processing_time -= 15
else if (href_list["blackout"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/small/blackout))
mod:uses += 3
already = 1
if (!already)
usr.verbs += /client/proc/blackout
src.temp = "Attempts to overload the lighting circuits on the station, destroying some bulbs. 3 uses."
usr:current_modules += new /datum/AI_Module/small/blackout
else src.temp = "Three additional uses added to Blackout module."
src.processing_time -= 15
else if (href_list["recam"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/small/reactivate_camera))
mod:uses += 10
already = 1
if (!already)
usr.verbs += /client/proc/reactivate_camera
src.temp = "Reactivates a currently disabled camera. 10 uses."
usr:current_modules += new /datum/AI_Module/small/reactivate_camera
else src.temp = "Ten additional uses added to ReCam module."
src.processing_time -= 15
else if(href_list["upgradecam"])
var/already
for (var/datum/AI_Module/mod in usr:current_modules)
if(istype(mod, /datum/AI_Module/small/upgrade_camera))
mod:uses += 10
already = 1
if (!already)
usr.verbs += /client/proc/upgrade_camera
src.temp = "Upgrades a camera to have X-Ray vision, Motion and be EMP-Proof. 10 uses."
usr:current_modules += new /datum/AI_Module/small/upgrade_camera
else src.temp = "Ten additional uses added to ReCam module."
src.processing_time -= 15
else
if (href_list["temp"])
src.temp = null
src.use(usr)
return
@@ -0,0 +1,72 @@
/datum/malf_hardware
var/name = "" // Hardware name
var/desc = ""
var/driver = null // Driver - if not null this verb is given to the AI to control hardware
var/mob/living/silicon/ai/owner = null // AI which owns this.
/datum/malf_hardware/proc/install()
if(owner && istype(owner))
owner.hardware = src
if(driver)
owner.verbs += driver
/datum/malf_hardware/proc/get_examine_desc()
return "It has some sort of hardware attached to its core"
// HARDWARE DEFINITIONS
/datum/malf_hardware/apu_gen
name = "APU Generator"
desc = "Auxiliary Power Unit that will keep you operational even without external power. Has to be manually activated. When APU is operational most abilities will be unavailable, and ability research will temporarily stop."
driver = /datum/game_mode/malfunction/verb/ai_toggle_apu
/datum/malf_hardware/apu_gen/get_examine_desc()
var/msg = "It seems to have some sort of power generator attached to its core."
if(owner.hardware_integrity() < 50)
msg += "<span class='warning'> It seems to be too damaged to function properly.</span>"
else if(owner.APU_power)
msg += " The generator appears to be active."
return msg
/datum/malf_hardware/dual_cpu
name = "Secondary Processor Unit"
desc = "Secondary coprocessor that increases amount of generated CPU power by 50%"
/datum/malf_hardware/dual_cpu/get_examine_desc()
return "It seems to have an additional CPU connected to it's core."
/datum/malf_hardware/dual_ram
name = "Secondary Memory Bank"
desc = "Expanded memory cells which allow you to store double amount of CPU time."
/datum/malf_hardware/dual_ram/get_examine_desc()
return "It seems to have additional memory blocks connected to it's core."
/datum/malf_hardware/core_bomb
name = "Self-Destruct Explosives"
desc = "High yield explosives are attached to your physical mainframe. This hardware comes with special driver that allows activation of these explosives. Timer is set to 15 seconds after manual activation. This is a doomsday device that will destroy both you and any intruders in your core."
driver = /datum/game_mode/malfunction/verb/ai_self_destruct
/datum/malf_hardware/core_bomb/get_examine_desc()
return "<span class='warning'>It seems to have grey blocks of unknown substance and some circuitry connected to it's core. [owner.bombing_core ? "A red light is blinking on the circuit." : ""]</span>"
/datum/malf_hardware/strong_turrets
name = "Turrets Focus Enhancer"
desc = "Turrets are upgraded to have larger rate of fire and much larger damage. This however massively increases power usage when firing."
/datum/malf_hardware/strong_turrets/get_examine_desc()
return "It seems to have extra wiring running from it's core to nearby turrets."
/datum/malf_hardware/strong_turrets/install()
..()
for(var/obj/machinery/turret/T in machines)
T.maxhealth = round(initial(T.maxhealth) * 1.4)
T.shot_delay = round(initial(T.shot_delay) / 2)
T.auto_repair = 1
T.active_power_usage = round(initial(T.active_power_usage) * 5)
for(var/obj/machinery/porta_turret/T in machines)
T.maxhealth = round(initial(T.maxhealth) * 1.4)
T.shot_delay = round(initial(T.shot_delay) / 2)
T.auto_repair = 1
T.active_power_usage = round(initial(T.active_power_usage) * 5)
@@ -0,0 +1,69 @@
/datum/malf_research
var/stored_cpu = 0 // Currently stored amount of CPU time.
var/last_tick = 0 // Last process() tick.
var/max_cpu = 0 // Maximal amount of CPU time stored.
var/cpu_increase_per_tick = 0 // Amount of CPU time generated by tick
var/list/available_abilities = null // List of available abilities that may be researched.
var/list/unlocked_abilities = null // List of already unlocked abilities.
var/mob/living/silicon/ai/owner = null // AI which owns this research datum.
var/datum/malf_research_ability/focus = null // Currently researched item
/datum/malf_research/New()
setup_abilities()
last_tick = world.time
// Proc: setup_abilities()
// Parameters: None
// Description: Sets up basic abilities for AI Malfunction gamemode.
/datum/malf_research/proc/setup_abilities()
available_abilities = list()
unlocked_abilities = list()
available_abilities += new/datum/malf_research_ability/networking/basic_hack()
available_abilities += new/datum/malf_research_ability/interdiction/recall_shuttle()
available_abilities += new/datum/malf_research_ability/manipulation/electrical_pulse()
// Proc: finish_research()
// Parameters: None
// Description: Finishes currently focused research.
/datum/malf_research/proc/finish_research()
if(!focus)
return
owner << "<b>Research Completed</b>: [focus.name]"
owner.verbs.Add(focus.ability)
available_abilities -= focus
if(focus.next)
available_abilities += focus.next
unlocked_abilities += focus
focus = null
// Proc: process()
// Parameters: None
// Description: Processes CPU gain and research progress based on "realtime" calculation.
/datum/malf_research/proc/process(var/idle = 0)
if(idle) // No power or running on APU. Do nothing.
last_tick = world.time
return
var/time_diff = (world.time - last_tick)
last_tick = world.time
var/cpu_gained = time_diff * cpu_increase_per_tick
if(cpu_gained < 0)
return // This shouldn't happen, but just in case..
if(max_cpu > stored_cpu)
var/given = min((max_cpu - stored_cpu), cpu_gained)
stored_cpu += given
cpu_gained -= given
cpu_gained = max(0, cpu_gained)
if(focus && (cpu_gained > 0))
focus.process(cpu_gained)
if(focus.unlocked)
finish_research()
@@ -0,0 +1,13 @@
/datum/malf_research_ability
var/ability = null // Path to verb which will be given to the AI when researched.
var/name = "Unknown Ability" // Name of this ability
var/price = 0 // Amount of CPU time needed to unlock this ability.
var/invested = 0 // Amount of CPU time already used to research this ability. When larger or equal to price unlocks the ability.
var/unlocked = 0 // Changed to 1 when fully researched.
var/datum/malf_research_ability/next = null // Next research (if applicable).
/datum/malf_research_ability/proc/process(var/time = 0)
invested += time
if(invested >= price)
unlocked = 1
+5 -18
View File
@@ -1,25 +1,12 @@
/datum/game_mode/malfunction
name = "AI malfunction"
round_description = "The AI on the satellite has malfunctioned and must be destroyed."
extended_round_description = "The AI will attempt to hack the APCs around the station in order to speed up its ability to take over all systems and activate the station self-destruct. The AI core is heavily protected by turrets and reinforced walls."
round_description = "The AI is behaving abnormally and must be stopped."
extended_round_description = "The AI will attempt to hack the APCs around the station in order to gain as much control as possible."
uplink_welcome = "Crazy AI Uplink Console:"
config_tag = "malfunction"
required_players = 2
required_players_secret = 15
required_players_secret = 7
required_enemies = 1
end_on_antag_death = 1
auto_recall_shuttle = 1
end_on_antag_death = 0
auto_recall_shuttle = 0
antag_tag = MODE_MALFUNCTION
/datum/game_mode/malfunction/process()
malf.tick()
/datum/game_mode/malfunction/check_finished()
if (malf.station_captured && !malf.can_nuke)
return 1
for(var/datum/antagonist/antag in antag_templates)
if(antag && !antag.antags_are_dead())
return ..()
malf.revealed = 0
return ..() //check for shuttle and nuke
@@ -0,0 +1,113 @@
// 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 = alert("Really destroy core?", "Core self-destruct", "YES", "NO")
if(choice != "YES")
return
if(!ability_prechecks(user, 0, 1))
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)
qdel(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 = alert("Really destroy station?", "Station self-destruct", "YES", "NO")
if(choice != "YES")
return
if(!ability_prechecks(user, 0, 0))
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,205 @@
// 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/hardware_list = list()
for(var/H in typesof(/datum/malf_hardware))
var/datum/malf_hardware/HW = new H
hardware_list += HW
var/possible_choices = list()
for(var/datum/malf_hardware/H in hardware_list)
possible_choices += H.name
possible_choices += "CANCEL"
var/choice = input("Select desired hardware. You may only choose one hardware piece!: ") in possible_choices
if(choice == "CANCEL")
return
var/note = null
var/datum/malf_hardware/C
for (var/datum/malf_hardware/H in hardware_list)
if(H.name == choice)
C = H
break
if(C)
note = C.desc
else
user << "This hardware does not exist! Probably a bug in game. Please report this."
return
if(!note)
error("Hardware without description: [C]")
return
var/confirmation = alert("[note] - Is this what you want?", "Hardware selection", "Yes", "No")
if(confirmation != "Yes")
user << "Selection cancelled. Use command again to select"
return
if(C)
C.owner = user
C.install()
// 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.html")
if(!help)
help = "Error loading help (file /ingame_manuals/malf_ai.html 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 a 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 our trace and it seems to be originating either from the station, or its immediate vicinity."
if(3)
fulltext = "Another hack attempt has been detected, this time targeting [text]. We are certain the intruder entered the network via a 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 recommend 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
if(RB.connected_ai == A)
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)
if(L == A)
continue
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,208 @@
// 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 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 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 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
var/obj/machinery/power/N = M
var/explosion_intensity = 2
// Verify if we can overload the target, if yes, calculate explosion strength. Some things have higher explosion strength than others, depending on charge(APCs, SMESs)
if(N && istype(N)) // /obj/machinery/power first, these create bigger explosions due to direct powernet connection
if(!istype(N, /obj/machinery/power/apc) && !istype(N, /obj/machinery/power/smes/buildable) && (!N.powernet || !N.powernet.avail)) // Directly connected machine which is not an APC or SMES. Either it has no powernet connection or it's powernet does not have enough power to overload
user << "<span class='notice'>ERROR: Low network voltage. Unable to overload. Increase network power level and try again.</span>"
return
else if (istype(N, /obj/machinery/power/apc)) // APC. Explosion is increased by available cell power.
var/obj/machinery/power/apc/A = N
if(A.cell && A.cell.charge)
explosion_intensity = 4 + round(A.cell.charge / 2000) // Explosion is increased by 1 for every 2k charge in cell
else
user << "<span class='notice'>ERROR: APC Malfunction - Cell depleted or removed. Unable to overload.</span>"
return
else if (istype(N, /obj/machinery/power/smes/buildable)) // SMES. These explode in a very very very big boom. Similar to magnetic containment failure when messing with coils.
var/obj/machinery/power/smes/buildable/S = N
if(S.charge && S.RCon)
explosion_intensity = 4 + round(S.charge / 1000000)
else
// Different error texts
if(!S.charge)
user << "<span class='notice'>ERROR: SMES Depleted. Unable to overload. Please charge SMES unit and try again.</span>"
else
user << "<span class='notice'>ERROR: SMES RCon error - Unable to reach destination. Please verify wire connection.</span>"
return
else if(M && istype(M)) // Not power machinery, so it's a regular machine instead. These have weak explosions.
if(!M.use_power) // Not using power at all
user << "<span class='notice'>ERROR: No power grid connection. Unable to overload.</span>"
return
if(M.inoperable()) // Not functional
user << "<span class='notice'>ERROR: Unknown error. Machine is probably damaged or power supply is nonfunctional.</span>"
return
else // Not a machine at all (what the hell is this doing in Machines list anyway??)
user << "<span class='notice'>ERROR: Unable to overload - target is not a machine.</span>"
return
explosion_intensity = min(explosion_intensity, 12) // 3, 6, 12 explosion cap
M.use_power(2000000) // Major power spike, few of these will completely burn APC's cell - equivalent of 2GJ 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)
var/obj/machinery/power/apc/temp_apc = temp_area.get_apc()
if(temp_apc && temp_apc.terminal && temp_apc.terminal.powernet)
temp_apc.terminal.powernet.trigger_warning(50) // Long alarm
if(temp_apc)
temp_apc.emp_act(3) // Such power surges are not good for APC electronics
if(temp_apc.cell)
temp_apc.cell.maxcharge -= between(0, (temp_apc.cell.maxcharge/2) + 500, temp_apc.cell.maxcharge)
if(temp_apc.cell.maxcharge < 100) // That's it, you busted the APC cell completely. Break the APC and completely destroy the cell.
qdel(temp_apc.cell)
temp_apc.set_broken()
if(!ability_pay(user,price))
return
M.visible_message("<span class='notice'>BZZZZZZZT</span>")
spawn(50)
explosion(get_turf(M), round(explosion_intensity/4),round(explosion_intensity/2),round(explosion_intensity),round(explosion_intensity * 2))
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 in config.station_levels)) // 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. No man could be this fast...", "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 a strong brute-force attack on your firewall which seems to be originating from your AI system. It already controls almost the 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.z in config.station_levels)
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 the 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
-2
View File
@@ -37,8 +37,6 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
else
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H.back), slot_in_backpack)
var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP)? null : sound('sound/misc/boatswain.ogg', volume=20)
captain_announcement.Announce("All hands, Captain [H.real_name] on deck!", new_sound=announce_sound)
H.implant_loyalty(src)
+22 -31
View File
@@ -468,38 +468,29 @@ var/global/datum/controller/occupations/job_master
return H.Robotize()
if("AI")
return H
if("Clown") //don't need bag preference stuff!
if("Captain")
var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP)? null : sound('sound/misc/boatswain.ogg', volume=20)
captain_announcement.Announce("All hands, Captain [H.real_name] on deck!", new_sound=announce_sound)
if(istype(H.back, /obj/item/weapon/storage))
new /obj/item/weapon/storage/box/survival(H.back)
else
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand)
//Deferred item spawning.
if(spawn_in_storage && spawn_in_storage.len)
var/obj/item/weapon/storage/B
for(var/obj/item/weapon/storage/S in H.contents)
B = S
break
if(!isnull(B))
for(var/thing in spawn_in_storage)
H << "<span class='notice'>Placing [thing] in your [B]!</span>"
var/datum/gear/G = gear_datums[thing]
new G.path(B)
else
switch(H.backbag) //BS12 EDIT
if(1)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand)
if(2)
var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack(H)
new /obj/item/weapon/storage/box/survival(BPK)
H.equip_to_slot_or_del(BPK, slot_back,1)
if(3)
var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack/satchel_norm(H)
new /obj/item/weapon/storage/box/survival(BPK)
H.equip_to_slot_or_del(BPK, slot_back,1)
if(4)
var/obj/item/weapon/storage/backpack/BPK = new/obj/item/weapon/storage/backpack/satchel(H)
new /obj/item/weapon/storage/box/survival(BPK)
H.equip_to_slot_or_del(BPK, slot_back,1)
//Deferred item spawning.
if(spawn_in_storage && spawn_in_storage.len)
var/obj/item/weapon/storage/B
for(var/obj/item/weapon/storage/S in H.contents)
B = S
break
if(!isnull(B))
for(var/thing in spawn_in_storage)
H << "<span class='notice'>Placing [thing] in your [B]!</span>"
var/datum/gear/G = gear_datums[thing]
new G.path(B)
else
H << "<span class='danger'>Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.</span>"
H << "<span class='danger'>Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.</span>"
if(istype(H)) //give humans wheelchairs, if they need them.
var/obj/item/organ/external/l_foot = H.get_organ("l_foot")
+18
View File
@@ -25,6 +25,15 @@
else
icon_state = "[initial(icon_state)]_off"
/obj/machinery/bluespacerelay/New()
..()
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/bluespacerelay(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/subspace/filter(src)
component_parts += new /obj/item/weapon/stock_parts/subspace/crystal(src)
component_parts += new /obj/item/stack/cable_coil(src, 30)
/obj/machinery/bluespacerelay/proc/update_power()
if(stat & (BROKEN|NOPOWER|EMPED))
@@ -32,3 +41,12 @@
else
on = 1
/obj/machinery/bluespacerelay/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(default_deconstruction_screwdriver(user, O))
return
if(default_deconstruction_crowbar(user, O))
return
if(default_part_replacement(user, O))
return
..()
+23 -2
View File
@@ -203,6 +203,10 @@
..()
/obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1)
// The only way for AI to reactivate cameras are malf abilities, this gives them different messages.
if(istype(user, /mob/living/silicon/ai))
user = null
if(choice != 1)
//legacy support, if choice is != 1 then just kick viewers without changing status
kick_viewers()
@@ -210,12 +214,18 @@
update_coverage()
set_status( !src.status )
if (!(src.status))
visible_message("\red [user] has deactivated [src]!")
if(user)
visible_message("<span class='notice'> [user] has deactivated [src]!</span>")
else
visible_message("<span class='notice'> [src] clicks and shuts down. </span>")
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = "[initial(icon_state)]1"
add_hiddenprint(user)
else
visible_message("\red [user] has reactivated [src]!")
if(user)
visible_message("<span class='notice'> [user] has reactivated [src]!</span>")
else
visible_message("<span class='notice'> [src] clicks and reactivates itself. </span>")
playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = initial(icon_state)
add_hiddenprint(user)
@@ -431,3 +441,14 @@
cameranet.updateVisibility(src, 0)
invalidateCameraCache()
// Resets the camera's wires to fully operational state. Used by one of Malfunction abilities.
/obj/machinery/camera/proc/reset_wires()
if(!wires)
return
if (stat & BROKEN) // Fix the camera
stat &= ~BROKEN
wires.CutAll()
wires.MendAll()
update_icon()
update_coverage()
+9 -1
View File
@@ -162,15 +162,23 @@ var/global/list/engineering_networks = list(
/obj/machinery/camera/proc/upgradeEmpProof()
assembly.upgrades.Add(new /obj/item/stack/material/osmium(assembly))
setPowerUsage()
update_coverage()
/obj/machinery/camera/proc/upgradeXRay()
assembly.upgrades.Add(new /obj/item/weapon/stock_parts/scanning_module/adv(assembly))
setPowerUsage()
update_coverage()
// If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list.
/obj/machinery/camera/proc/upgradeMotion()
assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly))
setPowerUsage()
if(!(src in machines))
if(!machinery_sort_required && ticker)
dd_insertObjectList(machines, src)
else
machines += src
machinery_sort_required = 1
update_coverage()
/obj/machinery/camera/proc/setPowerUsage()
var/mult = 1
+1 -1
View File
@@ -69,7 +69,7 @@
if (src.occupant)
var/laws
dat += "Stored AI: [src.occupant.name]<br>System integrity: [src.occupant.system_integrity()]%<br>"
dat += "Stored AI: [src.occupant.name]<br>System integrity: [src.occupant.hardware_integrity()]%<br>Backup Capacitor: [src.occupant.backup_capacitor()]%<br>"
for (var/datum/ai_law/law in occupant.laws.all_laws())
laws += "[law.get_index()]: [law.law]<BR>"
+10 -5
View File
@@ -137,7 +137,7 @@
set src in view(1)
if(!istype(usr, /mob/living))
usr << "\red You can't do that."
usr << "<span class='warning'>You can't do that.</span>"
return
if(usr.stat)
@@ -154,10 +154,15 @@
if(beaker)
if(beaker.reagents && beaker.reagents.reagent_list.len)
usr << "\blue Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid."
usr << "<span class='notice'>Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.</span>"
else
usr << "\blue Attached is an empty [beaker]."
usr << "<span class='notice'>Attached is an empty [beaker].</span>"
else
usr << "\blue No chemicals are attached."
usr << "<span class='notice'>No chemicals are attached.</span>"
usr << "\blue [attached ? attached : "No one"] is attached."
usr << "<span class='notice'>[attached ? attached : "No one"] is attached.</span>"
/obj/machinery/iv_drip/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(height && istype(mover) && mover.checkpass(PASSTABLE)) //allow bullets, beams, thrown objects, mice, drones, and the like through.
return 1
return ..()
+6
View File
@@ -21,6 +21,8 @@
var/raised = 0 //if the turret cover is "open" and the turret is raised
var/raising= 0 //if the turret is currently opening or closing its cover
var/health = 80 //the turret's health
var/maxhealth = 80 //turrets maximal health.
var/auto_repair = 0 //if 1 the turret slowly repairs itself.
var/locked = 1 //if the turret's behaviour control access is locked
var/controllock = 0 //if the turret responds to control panels
@@ -450,6 +452,10 @@
spawn()
popDown() // no valid targets, close the cover
if(auto_repair && (health < maxhealth))
use_power(20000)
health = min(health+1, maxhealth) // 1HP for 20kJ
/obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets)
switch(assess_living(L))
if(TURRET_PRIORITY_TARGET)
+10
View File
@@ -51,6 +51,8 @@
// 5 = bluetag
// 6 = redtag
var/health = 80
var/maxhealth = 80
var/auto_repair = 0
var/obj/machinery/turretcover/cover = null
var/popping = 0
var/wasvalid = 0
@@ -90,6 +92,7 @@
return
/obj/machinery/turret/New()
maxhealth = health
spark_system = new /datum/effect/effect/system/spark_spread
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -221,6 +224,13 @@
if(!isDown())
popDown()
use_power = 1
// Auto repair requires massive amount of power, but slowly regenerates the turret's health.
// Currently only used by malfunction hardware, but may be used as admin-settable option too.
if(auto_repair)
if(health < maxhealth)
use_power(20000)
health = min(health + 1, maxhealth)
return
+3 -2
View File
@@ -18,6 +18,7 @@
user << "<b>ERROR ERROR ERROR</b>"
/obj/item/device/aicard/attack_self(mob/user)
ui_interact(user)
/obj/item/device/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state)
@@ -25,7 +26,8 @@
data["has_ai"] = carded_ai != null
if(carded_ai)
data["name"] = carded_ai.name
data["integrity"] = carded_ai.system_integrity()
data["hardware_integrity"] = carded_ai.hardware_integrity()
data["backup_capacitor"] = carded_ai.backup_capacitor()
data["radio"] = !carded_ai.aiRadio.disabledAi
data["wireless"] = !carded_ai.control_disabled
data["operational"] = carded_ai.stat != DEAD
@@ -73,7 +75,6 @@
carded_ai << "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>"
user << "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>"
update_icon()
return 1
/obj/item/device/aicard/update_icon()
+1 -1
View File
@@ -25,7 +25,7 @@
/obj/item/device/debugger/is_used_on(obj/O, mob/user)
if(istype(O, /obj/machinery/power/apc))
var/obj/machinery/power/apc/A = O
if(A.emagged || A.malfhack)
if(A.emagged || A.hacker)
user << "\red There is a software error with the device."
else
user << "\blue The device's software appears to be fine."
+42 -17
View File
@@ -69,19 +69,22 @@
set category = "OOC"
if(say_disabled) //This is here to try to identify lag problems
usr << "<span class='warning'>Speech is currently admin-disabled.</span>"
usr << "<span class='danger'>Speech is currently admin-disabled.</span>"
return
if(!mob)
return
if(!mob) return
if(IsGuestKey(key))
src << "Guests may not use OOC."
return
msg = sanitize(msg)
if(!msg) return
if(!msg)
return
if(!(prefs.toggles & CHAT_LOOC))
src << "<span class='warning'>You have LOOC muted.</span>"
src << "<span class='danger'>You have LOOC muted.</span>"
return
if(!holder)
@@ -94,7 +97,7 @@
if(prefs.muted & MUTE_OOC)
src << "<span class='danger'>You cannot use OOC (muted).</span>"
return
if(handle_spam_prevention(msg,MUTE_OOC))
if(handle_spam_prevention(msg, MUTE_OOC))
return
if(findtext(msg, "byond://"))
src << "<B>Advertising other servers is not allowed.</B>"
@@ -104,26 +107,48 @@
log_ooc("(LOCAL) [mob.name]/[key] : [msg]")
var/mob/source = src.mob
var/mob/source = mob.get_looc_source()
var/list/heard = get_mobs_or_objects_in_view(7, source, 1, 0)
var/display_name = source.key
var/display_name = key
if(holder && holder.fakekey)
display_name = holder.fakekey
if(source.stat != DEAD)
display_name = source.name
if(mob.stat != DEAD)
display_name = mob.name
var/prefix
var/admin_stuff
for(var/client/target in clients)
if(target.prefs.toggles & CHAT_LOOC)
admin_stuff = ""
var/prefix = ""
var/admin_stuff = ""
var/send = 0
if(target in admins)
prefix = "(R)"
admin_stuff += "/([source.key])"
if(target != source.client)
admin_stuff += "/([key])"
if(target != src)
admin_stuff += "(<A HREF='?src=\ref[target.holder];adminplayerobservejump=\ref[mob]'>JMP</A>)"
if(target.mob in heard)
prefix = ""
if((target.mob in heard) || (target in admins))
send = 1
if(isAI(target.mob))
prefix = "(Core) "
else if(isAI(target.mob)) // Special case
var/mob/living/silicon/ai/A = target.mob
if(A.eyeobj in hearers(7, source))
send = 1
prefix = "(Eye) "
if(!send && (target in admins))
send = 1
prefix = "(R)"
if(send)
target << "<span class='ooc'><span class='looc'>" + create_text_tag("looc", "LOOC:", target) + " <span class='prefix'>[prefix]</span><EM>[display_name][admin_stuff]:</EM> <span class='message'>[msg]</span></span></span>"
/mob/proc/get_looc_source()
return src
/mob/living/silicon/ai/get_looc_source()
if(eyeobj)
return eyeobj
return src
+1 -1
View File
@@ -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
@@ -12,7 +12,7 @@
name = "mounted grenade launcher"
desc = "A shoulder-mounted micro-explosive dispenser."
selectable = 1
icon_state = "grenade_launcher"
icon_state = "grenadelauncher"
interface_name = "integrated grenade launcher"
interface_desc = "Discharges loaded grenades against the wearer's location."
@@ -10,7 +10,7 @@
name = "active camouflage module"
desc = "A robust hardsuit-integrated stealth module."
icon_state = "stealth"
icon_state = "cloak"
toggleable = 1
disruptable = 1
@@ -202,13 +202,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)
+1
View File
@@ -8,6 +8,7 @@
icon = 'icons/mob/eye.dmi'
icon_state = "default-eye"
alpha = 127
density = 0
var/sprint = 10
var/cooldown = 0
@@ -54,9 +54,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)
@@ -236,7 +236,7 @@
/mob/living/carbon/human/proc/get_damageable_organs()
var/list/obj/item/organ/external/parts = list()
for(var/obj/item/organ/external/O in organs)
if(O.brute_dam + O.burn_dam < O.max_damage)
if(O.is_damageable())
parts += O
return parts
@@ -118,8 +118,12 @@
else if(E.is_malfunctioning())
if(E.body_part == HAND_LEFT)
if(!l_hand)
continue
drop_from_inventory(l_hand)
else
if(!r_hand)
continue
drop_from_inventory(r_hand)
emote("me", 1, "drops what they were holding, their [E.name] malfunctioning!")
+177 -46
View File
@@ -56,26 +56,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/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
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()
src.verbs |= ai_verbs_default
@@ -203,17 +207,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
@@ -240,6 +233,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))
qdel(src)
@@ -250,10 +244,17 @@ var/list/ai_verbs_default = list(
/obj/machinery/ai_powersupply/process()
if(!powered_ai || powered_ai.stat & DEAD)
qdel()
return
if(powered_ai.psupply != src) // For some reason, the AI has different powersupply object. Delete this one, it's no longer needed.
qdel(src)
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
@@ -312,14 +313,7 @@ var/list/ai_verbs_default = list(
if("Lonestar") icon_state = "ai-lonestar"
if("Nanotrasen") icon_state = "ai-nanotrasen"
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()
@@ -420,11 +414,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)
@@ -545,13 +535,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"
@@ -711,5 +694,153 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/is_in_chassis()
return istype(loc, /turf)
/mob/living/silicon/ai/ex_act(var/severity)
if(severity == 1.0)
qdel(src)
return
..()
// 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()
// 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 in config.station_levels)
cpu_gain += 0.002
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 * 1.5
research.stored_cpu = min(research.stored_cpu, research.max_cpu)
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
// 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())
if(src.hacked_apcs)
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, "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)]")
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
@@ -13,10 +13,6 @@
remove_ai_verbs(src)
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
+10 -2
View File
@@ -17,15 +17,23 @@
msg += "It looks slightly charred.\n"
else
msg += "<B>Its casing is melted and heat-warped!</B>\n"
if (src.getOxyLoss())
if (src.getOxyLoss() > 175)
msg += "<B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER CRITICAL\" warning.</B>\n"
else if(src.getOxyLoss() > 100)
msg += "<B>It seems to be running on backup power. Its display is blinking a \"BACKUP POWER LOW\" warning.</B>\n"
else
msg += "It seems to be running on backup power.\n"
if (src.stat == UNCONSCIOUS)
msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n"
msg += "</span>"
msg += "*---------*</span>"
if(hardware && (hardware.owner == src))
msg += "<br>"
msg += hardware.get_examine_desc()
user << msg
user.showLaws(src)
return
/mob/proc/showLaws(var/mob/living/silicon/S)
+35 -54
View File
@@ -12,90 +12,71 @@
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(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.power_equip && !istype(src.loc,/obj/item))
//stage = 5
if (!loc.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)
if (aiRestorePowerRoutine==2)
src << "Alert cancelled. Power has been restored without our assistance."
src:aiRestorePowerRoutine = 0
aiRestorePowerRoutine = 0
src.blind.layer = 0
return
else if (src:aiRestorePowerRoutine==3)
else if (aiRestorePowerRoutine==3)
src << "Alert cancelled. Power has been restored."
src:aiRestorePowerRoutine = 0
aiRestorePowerRoutine = 0
src.blind.layer = 0
return
else if (APU_power)
aiRestorePowerRoutine = 0
src.blind.layer = 0
return
else
//stage = 6
var/area/current_area = get_area(src)
if (lacks_power())
//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 (src:aiRestorePowerRoutine==0)
src:aiRestorePowerRoutine = 1
if (aiRestorePowerRoutine==0)
aiRestorePowerRoutine = 1
//Blind the AI
@@ -118,7 +99,7 @@
if (loc.power_equip)
if (!istype(T, /turf/space))
src << "Alert cancelled. Power has been restored without our assistance."
src:aiRestorePowerRoutine = 0
aiRestorePowerRoutine = 0
src.blind.layer = 0
return
src << "Fault confirmed: missing external power. Shutting down main control system to save power."
@@ -127,7 +108,7 @@
sleep(50)
if (istype(T, /turf/space))
src << "Unable to verify! No power connection detected!"
src:aiRestorePowerRoutine = 2
aiRestorePowerRoutine = 2
return
src << "Connection verified. Searching for APC in power network."
sleep(50)
@@ -148,7 +129,7 @@
if (loc.power_equip)
if (!istype(T, /turf/space))
src << "Alert cancelled. Power has been restored without our assistance."
src:aiRestorePowerRoutine = 0
aiRestorePowerRoutine = 0
src.blind.layer = 0 //This, too, is a fix to issue 603
return
switch(PRP)
@@ -163,9 +144,9 @@
theAPC.operating = 1
theAPC.equipment = 3
theAPC.update()
src:aiRestorePowerRoutine = 3
aiRestorePowerRoutine = 3
src << "Here are your current laws:"
src.show_laws()
show_laws()
sleep(50)
theAPC = null
@@ -178,6 +159,8 @@
process_med_hud(src,0,src.eyeobj)
/mob/living/silicon/ai/proc/lacks_power()
if(APU_power)
return 0
var/turf/T = get_turf(src)
var/area/A = get_area(src)
return ((!A.power_equip) && A.requires_power == 1 || istype(T, /turf/space)) && !istype(src.loc,/obj/item)
@@ -186,11 +169,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)
@@ -409,19 +409,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
+6 -5
View File
@@ -191,15 +191,16 @@ var/list/organ_cache = list()
W.time_inflicted = world.time
/obj/item/organ/proc/take_damage(amount, var/silent=0)
if(src.robotic == 2)
if(src.status & ORGAN_ROBOT)
src.damage += (amount * 0.8)
else
src.damage += amount
if(owner && parent_organ)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(parent && !silent)
owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1)
//only show this if the organ is not robotic
if(owner && parent_organ)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(parent && !silent)
owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1)
/obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc
robotic = 2
+4 -1
View File
@@ -138,6 +138,9 @@
DAMAGE PROCS
****************************************************/
/obj/item/organ/external/proc/is_damageable(var/additional_damage = 0)
return (vital || brute_dam + burn_dam + additional_damage < max_damage)
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
if((brute <= 0) && (burn <= 0))
return 0
@@ -168,7 +171,7 @@
// If the limbs can break, make sure we don't exceed the maximum damage a limb can take before breaking
// Non-vital organs are limited to max_damage. You can't kill someone by bludeonging their arm all the way to 200 -- you can
// push them faster into paincrit though, as the additional damage is converted into shock.
if(vital || (brute_dam + burn_dam + brute + burn) < max_damage || !config.limbs_can_break)
if(is_damageable(brute + burn) || !config.limbs_can_break)
if(brute)
if(can_cut)
createwound( CUT, brute )
+11 -7
View File
@@ -8,7 +8,10 @@ mob/var/next_pain_time = 0
// partname is the name of a body part
// amount is a num from 1 to 100
mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0)
if(stat >= 2) return
if(stat >= 1)
return
if(species && (species.flags & NO_PAIN))
return
if(analgesic > 40)
return
if(world.time < next_pain_time && !force)
@@ -48,10 +51,10 @@ mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0
// message is the custom message to be displayed
// flash_strength is 0 for weak pain flash, 1 for strong pain flash
mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
if(stat >= 1) return
if(species && species.flags & NO_PAIN) return
if(stat >= 1)
return
if(species.flags & NO_PAIN)
return
if(reagents.has_reagent("tramadol"))
return
if(reagents.has_reagent("oxycodone"))
@@ -71,7 +74,7 @@ mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength)
mob/living/carbon/human/proc/handle_pain()
// not when sleeping
if(species && species.flags & NO_PAIN) return
if(species.flags & NO_PAIN) return
if(stat >= 2) return
if(analgesic > 70)
@@ -79,7 +82,7 @@ mob/living/carbon/human/proc/handle_pain()
var/maxdam = 0
var/obj/item/organ/external/damaged_organ = null
for(var/obj/item/organ/external/E in organs)
if(E.status & ORGAN_DEAD) continue
if(E.status & (ORGAN_DEAD|ORGAN_ROBOT)) continue
var/dam = E.get_damage()
// make the choice of the organ depend on damage,
// but also sometimes use one of the less damaged ones
@@ -91,6 +94,7 @@ mob/living/carbon/human/proc/handle_pain()
// Damage to internal organs hurts a lot.
for(var/obj/item/organ/I in internal_organs)
if(I.status & (ORGAN_DEAD|ORGAN_ROBOT)) continue
if(I.damage > 2) if(prob(2))
var/obj/item/organ/external/parent = get_organ(I.parent_organ)
src.custom_pain("You feel a sharp pain in your [parent.name]", 1)
+60 -97
View File
@@ -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
@@ -156,22 +152,16 @@
init()
else
area = get_area(src)
area.apc |= src
area.apc = src
opened = 1
operating = 0
name = "[area.name] APC"
stat |= MAINT
src.update_icon()
/obj/machinery/power/apc/initialize()
..()
src.update()
/obj/machinery/power/apc/Destroy()
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.apc -= src
src.update()
area.apc = null
area.power_light = 0
area.power_equip = 0
area.power_environ = 0
@@ -185,6 +175,11 @@
if(terminal)
qdel(terminal)
terminal = null
// 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()
@@ -210,7 +205,7 @@
else
src.area = get_area_name(areastring)
name = "\improper [area.name] APC"
area.apc |= src
area.apc = src
update_icon()
make_terminal()
@@ -237,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."
@@ -342,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
@@ -421,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>",
@@ -435,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
@@ -497,6 +492,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
@@ -504,7 +501,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)
@@ -566,7 +563,7 @@
new /obj/item/stack/cable_coil(loc,10)
user << "<span class='notice'>You cut the cables and dismantle the power terminal.</span>"
qdel(terminal)
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)
@@ -575,7 +572,7 @@
has_electronics = 1
user << "<span class='notice'>You place the power control board inside the frame.</span>"
qdel(W)
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)
@@ -589,7 +586,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/material/steel(loc)
user.visible_message(\
"<span class='warning'>[src] has been cut apart by [user.name] with the weldingtool.</span>",\
@@ -612,7 +609,7 @@
"<span class='notice'>You replace the damaged APC frontal panel with a new one.</span>")
qdel(W)
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
@@ -624,13 +621,14 @@
"You replace the damaged APC frame with new one.")
qdel(W)
stat &= ~BROKEN
malfai = null
malfhack = 0
// 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
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 \
@@ -716,21 +714,6 @@
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))
if (src.occupier == user)
return 3 // 3 = User is shunted in this APC
else if (istype(user.loc, /obj/machinery/power/apc))
return 4 // 4 = User is shunted in another APC
else
return 2 // 2 = APC hacked by user, and user is in its core.
else
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)
return
@@ -746,7 +729,6 @@
"totalCharging" = round(lastused_charging),
"coverLocked" = coverlocked,
"siliconUser" = istype(user, /mob/living/silicon),
"malfStatus" = get_malf_status(user),
"powerChannels" = list(
list(
@@ -836,23 +818,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)
@@ -909,28 +890,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)))
@@ -947,25 +906,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()
@@ -1168,8 +1123,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
@@ -1246,4 +1199,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
+2 -3
View File
@@ -149,7 +149,6 @@
return C
return null
/area/proc/get_apc()
var/obj/machinery/power/apc/FINDME = locate() in src
if (FINDME)
return FINDME
return apc
@@ -119,19 +119,19 @@
M.add_chemical_effect(CE_ALCOHOL, 1)
if(dose / strength_mod >= strength) // Early warning
if(dose * strength_mod >= strength) // Early warning
M.make_dizzy(6) // It is decreased at the speed of 3 per tick
if(dose / strength_mod >= strength * 2) // Slurring
if(dose * strength_mod >= strength * 2) // Slurring
M.slurring = max(M.slurring, 30)
if(dose / strength_mod >= strength * 3) // Confusion - walking in random directions
if(dose * strength_mod >= strength * 3) // Confusion - walking in random directions
M.confused = max(M.confused, 20)
if(dose / strength_mod >= strength * 4) // Blurry vision
if(dose * strength_mod >= strength * 4) // Blurry vision
M.eye_blurry = max(M.eye_blurry, 10)
if(dose / strength_mod >= strength * 5) // Drowsyness - periodically falling asleep
if(dose * strength_mod >= strength * 5) // Drowsyness - periodically falling asleep
M.drowsyness = max(M.drowsyness, 20)
if(dose / strength_mod >= strength * 6) // Toxic dose
if(dose * strength_mod >= strength * 6) // Toxic dose
M.add_chemical_effect(CE_ALCOHOL_TOXIC, toxicity)
if(dose / strength_mod >= strength * 7) // Pass out
if(dose * strength_mod >= strength * 7) // Pass out
M.paralysis = max(M.paralysis, 20)
M.sleeping = max(M.sleeping, 30)
+20 -25
View File
@@ -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 = "A weak forcefield which seems to be projected by the 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("<span class='notice'>\The [src] dissipates!</span>")
qdel(src)
return
/obj/machinery/shield/New()
src.set_dir(pick(1,2,3,4))
..()
@@ -38,12 +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!")
qdel(src)
return
check_failure()
opacity = 1
spawn(20) if(src) opacity = 0
@@ -51,12 +61,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!")
qdel(src)
return
check_failure()
opacity = 1
spawn(20) if(src) opacity = 0
return
@@ -64,10 +69,7 @@
/obj/machinery/shield/bullet_act(var/obj/item/projectile/Proj)
health -= Proj.damage
..()
if(health <=0)
visible_message("\blue The [src] dissipates!")
qdel(src)
return
check_failure()
opacity = 1
spawn(20) if(src) opacity = 0
@@ -98,7 +100,7 @@
/obj/machinery/shield/hitby(AM as mob|obj)
//Let everyone know we've been hit!
visible_message("\red <B>[src] was hit by [AM].</B>")
visible_message("<span class='notice'><B>\[src] was hit by [AM].</B></span>")
//Super realistic, resource-intensive, real-time damage calculations.
var/tforce = 0
@@ -112,11 +114,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!")
qdel(src)
return
check_failure()
//The shield becomes dense to absorb the blow.. purely asthetic.
opacity = 1
@@ -124,9 +122,6 @@
..()
return
/obj/machinery/shieldgen
name = "Emergency shield projector"
desc = "Used to seal minor hull breaches."
+4 -4
View File
@@ -3,15 +3,15 @@
if(air_group || (height==0)) return 1
if(istype(mover,/obj/item/projectile))
return (check_cover(mover,target))
if(istype(mover) && mover.checkpass(PASSTABLE))
return 1
if(locate(/obj/structure/table) in get_turf(mover))
return 1
if (flipped == 1)
if (get_dir(loc, target) == dir)
return !density
else
return 1
if(istype(mover) && mover.checkpass(PASSTABLE))
return 1
if(locate(/obj/structure/table) in get_turf(mover))
return 1
return 0
//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops.
+5
View File
@@ -0,0 +1,5 @@
author: Atlantis
delete-after: True
changes:
- rscadd: "Malfunction Overhaul - Whole gamemode was completely reworked from scratch. Most old abilities have been removed and quite a lot of new abilities was added. AI also has to hack APCs to unlock higher tier abilities faster, instead of having access to them from the round start. Most forced things, such as, shuttle recalling were removed and are instead controlled by the AI. Code is fully modular allowing for future modifications."
@@ -0,0 +1,18 @@
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
author: HarpyEagle
delete-after: True
changes:
- tweak: "IV stands are no longer bullet shields. They also allow mice, drones, pAIs et al to pass though."
+4
View File
@@ -0,0 +1,4 @@
author: Kelenius
delete-after: True
changes:
- tweak: "AI now hears LOOC both around its eye and its core, and speaks in LOOC around its eye. Keep in mind that you won't hear and won't be heard if there is a wall between your eye and the target."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

+3
View File
@@ -0,0 +1,3 @@
INGAME MANUALS
Ingame manuals are simple HTML files with basic information. They are linked to specific items/commands, such as the AI's display help command, or engine setup guide. Point of these files is to allow creation of basic guides for players which don't want to use wiki.
+22
View File
@@ -0,0 +1,22 @@
<h1>Malfunctioning AI guide</h1><br>
This guide contains most important OOC information for malfunctioning AIs.<br>
<h2>Goal</h2><br>
As malfunctioning AI, your primary goal is to overtake station's systems. To do this, use software "Basic Encryption Hack" on APCs (right click on APC and select Basic Encryption Hack). Please note that hacked APCs have distinctive blue error screen, that tends to attract attention. Rememember that malfunctioning AI is antagonist, so read server rules for antagonists. While hacking APCs is your official goal, feel free to create custom goal, as long as it is fun for everyone.<br>
<h2>Hardware</h2><br>
As malfunctioning AI, you may select one hardware piece to help you. Remember that once you select hardware piece, you cannot select another one, so choose wisely! Hardware may be selected by clicking "Select Hardware" button in Hardware tab. Following is list of possible hardware pieces:<br>
<b>APU Generator</b> - Auxiliary Power Unit which allows you to operate even without external power. However, running on APU will stop your CPU time generation, and temporarily disable most of your abilities. APU is also somewhat vulnerable to physical damage, and will fail if your core hardware integrity drops below 50%.<br>
<b>Turrets Focus Enhancer</b> - Removes safeties on installed turrets, boosting their rate of fire, health and enabling nano-regeneration module. This however increases power usage considerably, espicially when regenerating damage.<br>
<b>Secondary Processor Unit</b> - Simple upgrade that increases your CPU time generation by 50%. Useful if you need to speed up your research.<br>
<b>Secondary Memory Bank</b> - Doubles amount of maximal CPU time you may store. This is useful if you need to use lots of abilities in short amount of time.<br>
<b>Self-Destruct Explosives</b> - Large blocks of C4 are attached to your physical core. This C4 has 15 second timer, and may be activated by special button that appears in your Hardware tab. This self-destruct will remain active, even if you are destroyed. If timer reaches 0 your core explodes in strong explosion. Obviously, this destroys you, as well as anyone nearby.<br>
<h2>Software</h2><br>
Software are abilities that have to be unlocked via research menu (Hardware tab). Unlocked abilities appear in Software tab. <b>Sometimes, abilities won't appear in this tab after being researched. This can be fixed by relogging or using "ai-core" command.</b> Abilities are tiered, T1 being the weakest ones, while T4 are strongest ones. To reach higher tier you have to research abilities in lower tier. We currently have 12 abilities, in 3 research trees:<br>
<b>Networking</b> - Hacking-oriented abilities. T1 ability is Basic Encryption Hack, which allows you to hack more APCs. Higher tiers allow faking centcom messages, and even setting alert level. T4 ability is System Override, that rapidly hacks remaining APCs and gives you access to station self destruct sequence.<br>
<b>Interdiction</b> - Sabotage-oriented abilities. T1 ability allows you to recall emergency shuttle. Higher level abilities allow you to unlock cyborgs even without access to robotics console, and T4 ability allows you to hack other AIs to slave them under your control.<br>
<b>Manipulation</b> - Physical-oriented abilities. T1 ability allows you to break few lights, and rarely even APCs. T2 ability allows you to apply upgrade of your choice to camera, or reactivate broken camera. T3 ability allows you to create weak forcefield, that holds air, but won't last for long. And T4 ability allows you to overload machines, detonating them in weak explosion.<br>
<h2>End</h2><br>
If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff.
+10 -4
View File
@@ -48,11 +48,17 @@ Used In File(s): \code\game\objects\items\devices\aicard.dm
{{if data.has_ai}}
<div class="item">
<div class="itemLabelNarrow">
Integrity:
<div class="itemLabel">
Hardware Integrity:
</div>
<div class="itemContentWide">
{{:data.integrity}}%
<div class="itemContent">
{{:data.hardware_integrity}}%
</div>
<div class="itemLabel">
Backup Capacitor:
</div>
<div class="itemContent">
{{:data.backup_capacitor}}%
</div>
</div>