[READY]AI latejoins

This commit is contained in:
kevinz000
2018-04-05 01:09:52 -07:00
committed by CitadelStationBot
parent 49fd917fee
commit 38ae8beefc
11 changed files with 199 additions and 83 deletions

View File

@@ -32,3 +32,5 @@ GLOBAL_LIST_EMPTY(all_languages)
GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes.
GLOBAL_LIST_EMPTY(sentient_disease_instances)
GLOBAL_LIST_EMPTY(latejoin_ai_cores)

View File

@@ -66,18 +66,18 @@ SUBSYSTEM_DEF(job)
SetupOccupations()
return type_occupations[jobtype]
/datum/controller/subsystem/job/proc/AssignRole(mob/dead/new_player/player, rank, latejoin=0)
/datum/controller/subsystem/job/proc/AssignRole(mob/dead/new_player/player, rank, latejoin = FALSE)
Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]")
if(player && player.mind && rank)
var/datum/job/job = GetJob(rank)
if(!job)
return 0
return FALSE
if(jobban_isbanned(player, rank))
return 0
return FALSE
if(!job.player_old_enough(player.client))
return 0
return FALSE
if(job.required_playtime_remaining(player.client))
return 0
return FALSE
var/position_limit = job.total_positions
if(!latejoin)
position_limit = job.spawn_positions
@@ -85,9 +85,9 @@ SUBSYSTEM_DEF(job)
player.mind.assigned_role = rank
unassigned -= player
job.current_positions++
return 1
return TRUE
Debug("AR has failed, Player: [player], Rank: [rank]")
return 0
return FALSE
/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level, flag)
@@ -224,6 +224,8 @@ SUBSYSTEM_DEF(job)
if(SSticker.triai)
for(var/datum/job/ai/A in occupations)
A.spawn_positions = 3
for(var/obj/effect/landmark/start/ai/secondary/S in GLOB.start_landmarks_list)
S.latejoin_active = TRUE
//Get the players who are ready
for(var/mob/dead/new_player/player in GLOB.player_list)
@@ -359,7 +361,7 @@ SUBSYSTEM_DEF(job)
return 1
//Gives the player the stuff he should have with his rank
/datum/controller/subsystem/job/proc/EquipRank(mob/M, rank, joined_late=0)
/datum/controller/subsystem/job/proc/EquipRank(mob/M, rank, joined_late = FALSE)
var/mob/dead/new_player/N
var/mob/living/H
if(!joined_late)
@@ -382,6 +384,7 @@ SUBSYSTEM_DEF(job)
if(locate(/mob/living) in sloc.loc)
continue
S = sloc
sloc.used = TRUE
break
if(length(GLOB.jobspawn_overrides[rank]))
S = pick(GLOB.jobspawn_overrides[rank])
@@ -396,9 +399,13 @@ SUBSYSTEM_DEF(job)
H.mind.assigned_role = rank
if(job)
<<<<<<< HEAD
if(!job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
var/new_mob = job.equip(H)
=======
var/new_mob = job.equip(H, null, null, joined_late)
>>>>>>> 0c27e22... Latejoin Silicons (#36560)
if(ismob(new_mob))
H = new_mob
if(!joined_late)
@@ -406,23 +413,28 @@ SUBSYSTEM_DEF(job)
else
M = H
SSpersistence.antag_rep_change[M.client.ckey] += job.antag_rep
SSpersistence.antag_rep_change[M.client.ckey] += job.antag_rep
to_chat(M, "<b>You are the [rank].</b>")
to_chat(M, "<b>As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.</b>")
to_chat(M, "<b>To speak on your departments radio, use the :h button. To see others, look closely at your headset.</b>")
if(job.req_admin_notify)
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(job)
to_chat(M, "<b>As the [rank] you answer directly to [job.supervisors]. Special circumstances may change this.</b>")
to_chat(M, "<b>To speak on your departments radio, use the :h button. To see others, look closely at your headset.</b>")
if(job.req_admin_notify)
to_chat(M, "<b>You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via adminhelp.</b>")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "<FONT color='blue'><B>As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.</B></font>")
if(job && H)
<<<<<<< HEAD
if(job.dresscodecompliant)// CIT CHANGE - dress code compliance
equip_loadout(N, H) // CIT CHANGE - allows players to spawn with loadout items
job.after_spawn(H, M)
equip_loadout(N, H, TRUE)//CIT CHANGE - makes players spawn with in-backpack loadout items properly. A little hacky but it works
//handle_roundstart_items(H, M.ckey, H.mind.assigned_role, H.mind.special_role) //CIT CHANGE - makes donators spawn with their items. This can safely be commented out when all of the donator items are migrated to the loadout system
=======
job.after_spawn(H, M, joined_late)
>>>>>>> 0c27e22... Latejoin Silicons (#36560)
return H

View File

@@ -323,11 +323,6 @@ SUBSYSTEM_DEF(ticker)
mode.post_setup()
GLOB.start_state = new /datum/station_state()
GLOB.start_state.count()
//Cleanup some stuff
for(var/obj/effect/landmark/start/S in GLOB.landmarks_list)
//Deleting Startpoints but we need the ai point to AI-ize people later
if(S.delete_after_roundstart)
qdel(S)
//assign crew objectives and generate miscreants
if(CONFIG_GET(flag/allow_extended_miscreants) && GLOB.master_mode == "extended")
@@ -341,6 +336,14 @@ SUBSYSTEM_DEF(ticker)
send2irc("Server", "Round [GLOB.round_id ? "#[GLOB.round_id]:" : "of"] [hide_mode ? "secret":"[mode.name]"] has started[allmins.len ? ".":" with no active admins online!"]")
setup_done = TRUE
for(var/i in GLOB.start_landmarks_list)
var/obj/effect/landmark/start/S = i
if(istype(S)) //we can not runtime here. not in this important of a proc.
S.after_round_start()
else
stack_trace("[S] [S.type] found in start landmarks list, which isn't a start landmark!")
//These callbacks will fire after roundstart key transfer
/datum/controller/subsystem/ticker/proc/OnRoundstart(datum/callback/cb)
if(!HasRoundStarted())

View File

@@ -111,7 +111,7 @@
if(current)
current.transfer_observers_to(new_character) //transfer anyone observing the old character to the new one
current = new_character //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
new_character.mind = src //and associate our new body with ourself
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
var/datum/antagonist/A = a
A.on_body_transfer(old_current, current)
@@ -311,7 +311,7 @@
else
uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key)
var/unlock_note
if(uplink_loc == R)
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
@@ -331,7 +331,7 @@
if(!silent)
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
unlock_note = "<B>Uplink Degrees:</B> [P.traitor_unlock_degrees] ([P.name])."
if(uplink_owner)
uplink_owner.antag_memory += unlock_note + "<br>"
else

View File

@@ -35,6 +35,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
layer = MOB_LAYER
var/jobspawn_override = FALSE
var/delete_after_roundstart = TRUE
var/used = FALSE
/obj/effect/landmark/start/proc/after_round_start()
if(delete_after_roundstart)
qdel(src)
/obj/effect/landmark/start/New()
GLOB.start_landmarks_list += src
@@ -187,12 +192,18 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
icon_state = "AI"
delete_after_roundstart = FALSE
var/primary_ai = TRUE
var/latejoin_active = TRUE
/obj/effect/landmark/start/ai/after_round_start()
if(latejoin_active && !used)
new /obj/structure/AIcore/latejoin_inactive(loc)
return ..()
/obj/effect/landmark/start/ai/secondary
icon = 'icons/effects/landmarks_static.dmi'
icon_state = "ai_spawn"
primary_ai = FALSE
latejoin_active = FALSE
//Department Security spawns

View File

@@ -7,12 +7,14 @@
desc = "The framework for an artificial intelligence core."
max_integrity = 500
var/state = 0
var/datum/ai_laws/laws = new()
var/datum/ai_laws/laws
var/obj/item/circuitboard/circuit = null
var/obj/item/device/mmi/brain = null
var/can_deconstruct = TRUE
/obj/structure/AIcore/New()
..()
/obj/structure/AIcore/Initialize()
. = ..()
laws = new
laws.set_laws_config()
/obj/structure/AIcore/Destroy()
@@ -24,11 +26,60 @@
brain = null
return ..()
/obj/structure/AIcore/latejoin_inactive
name = "Networked AI core"
desc = "This AI core is connected by bluespace transmitters to NTNet, allowing for an AI personality to be downloaded to it on the fly mid-shift."
can_deconstruct = FALSE
icon_state = "ai-empty"
anchored = TRUE
state = AI_READY_CORE
var/available = TRUE
var/safety_checks = TRUE
var/active = TRUE
/obj/structure/AIcore/latejoin_inactive/examine(mob/user)
. = ..()
to_chat(user, "Its transmitter seems to be [active? "on" : "off"].")
/obj/structure/AIcore/latejoin_inactive/proc/is_available() //If people still manage to use this feature to spawn-kill AI latejoins ahelp them.
if(!available)
return FALSE
if(!safety_checks)
return TRUE
if(!active)
return FALSE
var/turf/T = get_turf(src)
var/area/A = get_area(src)
if(!A.blob_allowed)
return FALSE
if(!A.power_equip)
return FALSE
if(!SSmapping.level_trait(T.z,ZTRAIT_STATION))
return FALSE
if(!istype(T, /turf/open/floor))
return FALSE
return TRUE
/obj/structure/AIcore/latejoin_inactive/attackby(obj/item/P, mob/user, params)
if(istype(P, /obj/item/device/multitool))
active = !active
to_chat(user, "You [active? "activate" : "deactivate"] [src]'s transimtters.")
return
return ..()
/obj/structure/AIcore/latejoin_inactive/Initialize()
. = ..()
GLOB.latejoin_ai_cores += src
/obj/structure/AIcore/latejoin_inactive/Destroy()
GLOB.latejoin_ai_cores -= src
return ..()
/obj/structure/AIcore/attackby(obj/item/P, mob/user, params)
if(istype(P, /obj/item/wrench))
return default_unfasten_wrench(user, P, 20)
if(!anchored)
if(istype(P, /obj/item/weldingtool))
if(istype(P, /obj/item/weldingtool) && can_deconstruct)
if(state != EMPTY_CORE)
to_chat(user, "<span class='warning'>The core must be empty to deconstruct it!</span>")
return
@@ -259,7 +310,6 @@ That prevents a few funky behaviors.
return 0
return 1
/obj/structure/AIcore/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(state != AI_READY_CORE || !..())
return
@@ -275,6 +325,5 @@ That prevents a few funky behaviors.
else //If for some reason you use an empty card on an empty AI terminal.
to_chat(user, "There is no AI loaded on this terminal!")
/obj/item/circuitboard/aicore
name = "AI core (AI Core Board)" //Well, duh, but best to be consistent

View File

@@ -769,11 +769,7 @@
var/J_totPos = html_encode(job.total_positions)
dat += "<tr><td>[J_title]:</td> <td>[J_opPos]/[job.total_positions < 0 ? " (unlimited)" : J_totPos]"
if(job.title == "AI" || job.title == "Cyborg")
dat += " </td><td>(Cannot Late Join)</td>"
continue
else
dat += "</td>"
dat += "</td>"
dat += "<td>"
if(job.total_positions >= 0)
dat += "<A href='?src=[REF(src)];[HrefToken()];customjobslot=[job.title]'>Custom</A> | "

View File

@@ -53,19 +53,24 @@
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M)
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
//do actions on H but send messages to M as the key may not have been transferred_yet
/datum/job/proc/announce(mob/living/carbon/human/H)
if(head_announce)
announce_head(H, head_announce)
/datum/job/proc/override_latejoin_spawn(mob/living/carbon/human/H) //Return TRUE to force latejoining to not automatically place the person in latejoin shuttle/whatever.
return FALSE
//Used for a special check of whether to allow a client to latejoin as this job.
/datum/job/proc/special_check_latejoin(client/C)
return TRUE
//Don't override this unless the job transforms into a non-human (Silicons do this for example)
/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE)
/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE)
if(!H)
return 0
return FALSE
if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions))
if(H.dna.species.id != "human")
@@ -106,8 +111,8 @@
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/job/proc/player_old_enough(client/C)
if(available_in_days(C) == 0)
return 1 //Available in 0 days = available right now = player is old enough to play.
return 0
return TRUE //Available in 0 days = available right now = player is old enough to play.
return FALSE
/datum/job/proc/available_in_days(client/C)
@@ -123,7 +128,7 @@
return max(0, minimal_player_age - C.player_age)
/datum/job/proc/config_check()
return 1
return TRUE
/datum/job/proc/map_check()
return TRUE

View File

@@ -6,21 +6,35 @@ AI
flag = AI_JF
department_flag = ENGSEC
faction = "Station"
total_positions = 0
total_positions = 1
spawn_positions = 1
selection_color = "#ccffcc"
supervisors = "your laws"
req_admin_notify = 1
req_admin_notify = TRUE
minimal_player_age = 30
exp_requirements = 180
exp_type = EXP_TYPE_CREW
antag_rep = 20
var/do_special_check = TRUE
/datum/job/ai/equip(mob/living/carbon/human/H)
return H.AIize(FALSE)
/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin)
. = H.AIize(latejoin)
/datum/job/ai/after_spawn(mob/living/silicon/ai/AI, mob/M)
AI.rename_self("ai", M.client)
/datum/job/ai/after_spawn(mob/H, mob/M, latejoin)
. = ..()
if(latejoin)
var/obj/structure/AIcore/latejoin_inactive/lateJoinCore
for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores)
if(P.is_available())
lateJoinCore = P
GLOB.latejoin_ai_cores -= P
break
if(lateJoinCore)
lateJoinCore.available = FALSE
H.forceMove(lateJoinCore.loc)
qdel(lateJoinCore)
var/mob/living/silicon/ai/AI = H
AI.rename_self("ai", M.client) //If this runtimes oh well jobcode is fucked.
//we may have been created after our borg
if(SSticker.current_state == GAME_STATE_SETTING_UP)
@@ -28,6 +42,27 @@ AI
if(!R.connected_ai)
R.TryConnectToAI()
if(latejoin)
announce(AI)
/datum/job/ai/override_latejoin_spawn()
return TRUE
/datum/job/ai/special_check_latejoin(client/C)
if(!do_special_check)
return TRUE
for(var/i in GLOB.latejoin_ai_cores)
var/obj/structure/AIcore/latejoin_inactive/LAI = i
if(istype(LAI))
if(LAI.is_available())
return TRUE
return FALSE
/datum/job/ai/announce(mob/living/silicon/ai/AI)
. = ..()
var/area/A = get_area(AI)
var/turf/T = get_turf(AI)
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "[AI] has been downloaded to an empty bluespace-networked AI core at [COORD(T)], [A.name]."))
/datum/job/ai/config_check()
return CONFIG_GET(flag/allow_ai)

View File

@@ -293,8 +293,8 @@
if(JOB_UNAVAILABLE_SLOTFULL)
return "[jobtitle] is already filled to capacity."
return "Error: Unknown job availability."
/mob/dead/new_player/proc/IsJobUnavailable(rank)
/mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE)
var/datum/job/job = SSjob.GetJob(rank)
if(!job)
return JOB_UNAVAILABLE_GENERIC
@@ -313,6 +313,8 @@
return JOB_UNAVAILABLE_ACCOUNTAGE
if(job.required_playtime_remaining(client))
return JOB_UNAVAILABLE_PLAYTIME
if(latejoin && !job.special_check_latejoin(client))
return JOB_UNAVAILABLE_GENERIC
return JOB_AVAILABLE
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
@@ -343,18 +345,20 @@
SSjob.AssignRole(src, rank, 1)
var/mob/living/character = create_character(TRUE) //creates the human and transfers vars and mind
var/equip = SSjob.EquipRank(character, rank, 1)
var/equip = SSjob.EquipRank(character, rank, TRUE)
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
character = equip
SSjob.SendToLateJoin(character)
var/datum/job/job = SSjob.GetJob(rank)
if(!arrivals_docked)
var/obj/screen/splash/Spl = new(character.client, TRUE)
Spl.Fade(TRUE)
character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
if(job && !job.override_latejoin_spawn(character))
SSjob.SendToLateJoin(character)
if(!arrivals_docked)
var/obj/screen/splash/Spl = new(character.client, TRUE)
Spl.Fade(TRUE)
character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
character.update_parallax_teleport()
character.update_parallax_teleport()
SSticker.minds += character.mind
@@ -395,7 +399,7 @@
if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
SSticker.mode.make_antag_chance(humanc)
if(CONFIG_GET(flag/roundstart_traits))
if(humanc && CONFIG_GET(flag/roundstart_traits))
SStraits.AssignTraits(humanc, humanc.client, TRUE)
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
@@ -421,10 +425,9 @@
var/available_job_count = 0
for(var/datum/job/job in SSjob.occupations)
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
available_job_count++;
for(var/datum/job/prioritized_job in SSjob.prioritized_jobs)
if(prioritized_job.current_positions >= prioritized_job.total_positions)
SSjob.prioritized_jobs -= prioritized_job
@@ -444,7 +447,7 @@
dat += "<div class='jobs'><div class='jobsColumn'>"
var/job_count = 0
for(var/datum/job/job in SSjob.occupations)
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
job_count++;
if (job_count > round(available_job_count / 2))
dat += "</div><div class='jobsColumn'>"

View File

@@ -18,7 +18,7 @@
icon_state = "ai"
anchored = TRUE
density = TRUE
canmove = 0
canmove = FALSE
status_flags = CANSTUN|CANPUSH
a_intent = INTENT_HARM //so we always get pushed instead of trying to swap
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
@@ -28,7 +28,7 @@
d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED
mob_size = MOB_SIZE_LARGE
var/list/network = list("ss13")
var/obj/machinery/camera/current = null
var/obj/machinery/camera/current
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
var/requires_power = POWER_REQ_ALL
@@ -37,44 +37,44 @@
var/viewalerts = 0
var/icon/holo_icon//Default is assigned when AI is created.
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
var/radio_enabled = 1 //Determins if a carded AI can speak with its built in radio or not.
var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not.
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
var/obj/item/device/pda/ai/aiPDA = null
var/obj/item/device/multitool/aiMulti = null
var/obj/item/device/pda/ai/aiPDA
var/obj/item/device/multitool/aiMulti
var/mob/living/simple_animal/bot/Bot
var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
//MALFUNCTION
var/datum/module_picker/malf_picker
var/list/datum/AI_Module/current_modules = list()
var/can_dominate_mechs = 0
var/shunted = 0 //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead
var/can_dominate_mechs = FALSE
var/shunted = FALSE //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead
var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click()
var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite
var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown
var/control_disabled = FALSE // Set to 1 to stop AI from interacting via Click()
var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite
var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown
var/obj/machinery/power/apc/malfhack = null
var/explosive = 0 //does the AI explode when it dies?
var/obj/machinery/power/apc/malfhack
var/explosive = FALSE //does the AI explode when it dies?
var/mob/living/silicon/ai/parent = null
var/camera_light_on = 0
var/mob/living/silicon/ai/parent
var/camera_light_on = FALSE
var/list/obj/machinery/camera/lit_cameras = list()
var/datum/trackable/track = new()
var/datum/trackable/track = new
var/last_paper_seen = null
var/can_shunt = 1
var/last_announcement = "" // For AI VOX, if enabled
var/can_shunt = TRUE
var/last_announcement = "" // For AI VOX, if enabled
var/turf/waypoint //Holds the turf of the currently selected waypoint.
var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
var/call_bot_cooldown = 0 //time of next call bot command
var/apc_override = 0 //hack for letting the AI use its APC even when visionless
var/waypoint_mode = FALSE //Waypoint mode is for selecting a turf via clicking.
var/call_bot_cooldown = 0 //time of next call bot command
var/apc_override = FALSE //hack for letting the AI use its APC even when visionless
var/nuking = FALSE
var/obj/machinery/doomsday_device/doomsday_device
var/mob/camera/aiEye/eyeobj = new()
var/mob/camera/aiEye/eyeobj = new
var/sprint = 10
var/cooldown = 0
var/acceleration = 1