April sync (#360)
* Maps and things no code/icons * helpers defines globalvars * Onclick world.dm orphaned_procs * subsystems Round vote and shuttle autocall done here too * datums * Game folder * Admin - chatter modules * clothing - mining * modular computers - zambies * client * mob level 1 * mob stage 2 + simple_animal * silicons n brains * mob stage 3 + Alien/Monkey * human mobs * icons updated * some sounds * emitter y u no commit * update tgstation.dme * compile fixes * travis fixes Also removes Fast digest mode, because reasons. * tweaks for travis Mentors are broke again Also fixes Sizeray guns * oxygen loss fix for vore code. * removes unused code * some code updates * bulk fixes * further fixes * outside things * whoops. * Maint bar ported * GLOBs.
This commit is contained in:
@@ -36,9 +36,11 @@
|
||||
if(is_servant_of_ratvar(src) && user.Adjacent(src) && !stat) //To counter pseudo-stealth by using headlamps
|
||||
msg += "<span class='warning'>Its eyes are glowing a blazing yellow!</span>\n"
|
||||
|
||||
switch(src.stat)
|
||||
switch(stat)
|
||||
if(CONSCIOUS)
|
||||
if(!src.client)
|
||||
if(shell)
|
||||
msg += "It appears to be an [deployed ? "active" : "empty"] AI shell.\n"
|
||||
else if(!client)
|
||||
msg += "It appears to be in stand-by mode.\n" //afk
|
||||
if(UNCONSCIOUS)
|
||||
msg += "<span class='warning'>It doesn't seem to be responding.</span>\n"
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
|
||||
to_chat(who, "<b>Obey these laws:</b>")
|
||||
laws.show_laws(who)
|
||||
if (is_special_character(src) && connected_ai)
|
||||
if (shell) //AI shell
|
||||
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
|
||||
else if (is_special_character(src) && connected_ai)
|
||||
to_chat(who, "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>")
|
||||
else if (connected_ai)
|
||||
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
update_cell_hud_icon()
|
||||
|
||||
if(syndicate)
|
||||
if(ticker.mode.name == "traitor")
|
||||
for(var/datum/mind/tra in ticker.mode.traitors)
|
||||
if(SSticker.mode.name == "traitor")
|
||||
for(var/datum/mind/tra in SSticker.mode.traitors)
|
||||
if(tra.current)
|
||||
var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") //no traitor sprite in that dmi!
|
||||
src.client.images += I
|
||||
@@ -48,7 +48,7 @@
|
||||
if(mind)
|
||||
if(!mind.special_role)
|
||||
mind.special_role = "traitor"
|
||||
ticker.mode.traitors += mind
|
||||
SSticker.mode.traitors += mind
|
||||
|
||||
|
||||
/mob/living/silicon/robot/update_health_hud()
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
regenerate_icons()
|
||||
show_laws(0)
|
||||
if(mind)
|
||||
ticker.mode.remove_revolutionary(mind)
|
||||
ticker.mode.remove_gangster(mind,1,remove_bosses=1)
|
||||
SSticker.mode.remove_revolutionary(mind)
|
||||
SSticker.mode.remove_gangster(mind,1,remove_bosses=1)
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
|
||||
var/obj/item/device/mmi/mmi = null
|
||||
|
||||
var/shell = FALSE
|
||||
var/deployed = FALSE
|
||||
var/mob/living/silicon/ai/mainframe = null
|
||||
var/datum/action/innate/undeployment/undeployment_action = new
|
||||
|
||||
//Hud stuff
|
||||
|
||||
@@ -47,7 +51,7 @@
|
||||
|
||||
var/ident = 0
|
||||
var/locked = 1
|
||||
var/list/req_access = list(access_robotics)
|
||||
var/list/req_access = list(GLOB.access_robotics)
|
||||
|
||||
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
|
||||
|
||||
@@ -73,7 +77,7 @@
|
||||
|
||||
var/sight_mode = 0
|
||||
var/updating = 0 //portable camera camerachunk update
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
|
||||
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD)
|
||||
|
||||
var/list/upgrades = list()
|
||||
|
||||
@@ -129,8 +133,12 @@
|
||||
update_icons()
|
||||
..()
|
||||
|
||||
//If this body is meant to be a borg controlled by the AI player
|
||||
if(shell)
|
||||
make_shell()
|
||||
|
||||
//MMI stuff. Held togheter by magic. ~Miauw
|
||||
if(!mmi || !mmi.brainmob)
|
||||
else if(!mmi || !mmi.brainmob)
|
||||
mmi = new (src)
|
||||
mmi.brain = new /obj/item/organ/brain(mmi)
|
||||
mmi.brain.name = "[real_name]'s brain"
|
||||
@@ -159,8 +167,8 @@
|
||||
if(mmi.brainmob)
|
||||
if(mmi.brainmob.stat == DEAD)
|
||||
mmi.brainmob.stat = CONSCIOUS
|
||||
dead_mob_list -= mmi.brainmob
|
||||
living_mob_list += mmi.brainmob
|
||||
GLOB.dead_mob_list -= mmi.brainmob
|
||||
GLOB.living_mob_list += mmi.brainmob
|
||||
mind.transfer_to(mmi.brainmob)
|
||||
mmi.update_icon()
|
||||
else
|
||||
@@ -170,6 +178,8 @@
|
||||
mmi = null
|
||||
if(connected_ai)
|
||||
connected_ai.connected_robots -= src
|
||||
if(shell)
|
||||
GLOB.available_ai_shells -= src
|
||||
qdel(wires)
|
||||
qdel(module)
|
||||
qdel(eye_lights)
|
||||
@@ -204,6 +214,8 @@
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/updatename()
|
||||
if(shell)
|
||||
return
|
||||
var/changed_name = ""
|
||||
if(custom_name)
|
||||
changed_name = custom_name
|
||||
@@ -424,7 +436,9 @@
|
||||
update_icons()
|
||||
|
||||
else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio
|
||||
if(radio)
|
||||
if(shell)
|
||||
to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
|
||||
else if(radio)
|
||||
radio.attackby(W,user)//Push it to the radio to let it handle everything
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
|
||||
@@ -453,6 +467,9 @@
|
||||
if(!cell)
|
||||
to_chat(user, "<span class='warning'>You need to install a power cell to do that!</span>")
|
||||
return
|
||||
if(shell) //AI shells always have the laws of the AI
|
||||
to_chat(user, "<span class='warning'>[src] is controlled remotely! You cannot upload new laws this way!</span>")
|
||||
return
|
||||
if(emagged || (connected_ai && lawupdate)) //Can't be sure which, metagamers
|
||||
emote("buzz-[user.name]")
|
||||
return
|
||||
@@ -594,7 +611,7 @@
|
||||
|
||||
/mob/living/silicon/robot/proc/do_camera_update(oldLoc)
|
||||
if(oldLoc != src.loc)
|
||||
cameranet.updatePortableCamera(src.camera)
|
||||
GLOB.cameranet.updatePortableCamera(src.camera)
|
||||
updating = 0
|
||||
|
||||
/mob/living/silicon/robot/Move(a, b, flag)
|
||||
@@ -606,36 +623,6 @@
|
||||
updating = 1
|
||||
addtimer(CALLBACK(src, .proc/do_camera_update, oldLoc), BORG_CAMERA_BUFFER)
|
||||
if(module)
|
||||
if(istype(module, /obj/item/weapon/robot_module/janitor))
|
||||
var/turf/tile = loc
|
||||
if(isturf(tile))
|
||||
tile.clean_blood()
|
||||
for(var/A in tile)
|
||||
if(is_cleanable(A))
|
||||
qdel(A)
|
||||
else if(istype(A, /obj/item))
|
||||
var/obj/item/cleaned_item = A
|
||||
cleaned_item.clean_blood()
|
||||
else if(ishuman(A))
|
||||
var/mob/living/carbon/human/cleaned_human = A
|
||||
if(cleaned_human.lying)
|
||||
if(cleaned_human.head)
|
||||
cleaned_human.head.clean_blood()
|
||||
cleaned_human.update_inv_head()
|
||||
if(cleaned_human.wear_suit)
|
||||
cleaned_human.wear_suit.clean_blood()
|
||||
cleaned_human.update_inv_wear_suit()
|
||||
else if(cleaned_human.w_uniform)
|
||||
cleaned_human.w_uniform.clean_blood()
|
||||
cleaned_human.update_inv_w_uniform()
|
||||
if(cleaned_human.shoes)
|
||||
cleaned_human.shoes.clean_blood()
|
||||
cleaned_human.update_inv_shoes()
|
||||
cleaned_human.clean_blood()
|
||||
cleaned_human.wash_cream()
|
||||
to_chat(cleaned_human, "<span class='danger'>[src] cleans your face!</span>")
|
||||
return
|
||||
|
||||
if(istype(module, /obj/item/weapon/robot_module/miner))
|
||||
if(istype(loc, /turf/open/floor/plating/asteroid))
|
||||
for(var/obj/item/I in held_items)
|
||||
@@ -806,7 +793,7 @@
|
||||
icon_state = "syndie_bloodhound"
|
||||
faction = list("syndicate")
|
||||
bubble_icon = "syndibot"
|
||||
req_access = list(access_syndicate)
|
||||
req_access = list(GLOB.access_syndicate)
|
||||
lawupdate = FALSE
|
||||
scrambledcodes = TRUE // These are rogue borgs.
|
||||
ionpulse = TRUE
|
||||
@@ -829,6 +816,9 @@
|
||||
if(playstyle_string)
|
||||
to_chat(src, playstyle_string)
|
||||
|
||||
/mob/living/silicon/robot/syndicate/ResetModule()
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/syndicate/medical
|
||||
icon_state = "syndi-medi"
|
||||
playstyle_string = "<span class='userdanger'>You are a Syndicate medical cyborg!</span><br>\
|
||||
@@ -843,12 +833,14 @@
|
||||
if(!connected_ai)
|
||||
return
|
||||
switch(notifytype)
|
||||
if(1) //New Cyborg
|
||||
if(NEW_BORG) //New Cyborg
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg connection detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
|
||||
if(2) //New Module
|
||||
if(NEW_MODULE) //New Module
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.</span><br>")
|
||||
if(3) //New Name
|
||||
if(RENAME) //New Name
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].</span><br>")
|
||||
if(AI_SHELL) //New Shell
|
||||
to_chat(connected_ai, "<br><br><span class='notice'>NOTICE - New cyborg shell detected: <a href='?src=\ref[connected_ai];track=[html_encode(name)]'>[name]</a></span><br>")
|
||||
|
||||
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close = 0)
|
||||
if(stat || lockcharge || low_power_mode)
|
||||
@@ -889,12 +881,12 @@
|
||||
|
||||
if(sight_mode & BORGMESON)
|
||||
sight |= SEE_TURFS
|
||||
see_invisible = min(see_invisible, SEE_INVISIBLE_MINIMUM)
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
see_in_dark = 1
|
||||
|
||||
if(sight_mode & BORGMATERIAL)
|
||||
sight |= SEE_OBJS
|
||||
see_invisible = min(see_invisible, SEE_INVISIBLE_MINIMUM)
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
see_in_dark = 1
|
||||
|
||||
if(sight_mode & BORGXRAY)
|
||||
@@ -909,6 +901,7 @@
|
||||
|
||||
if(see_override)
|
||||
see_invisible = see_override
|
||||
sync_lighting_plane_alpha()
|
||||
|
||||
/mob/living/silicon/robot/update_stat()
|
||||
if(status_flags & GODMODE)
|
||||
@@ -931,6 +924,7 @@
|
||||
update_headlamp()
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
diag_hud_set_aishell()
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0)
|
||||
@@ -940,13 +934,13 @@
|
||||
update_headlamp()
|
||||
if(admin_revive)
|
||||
locked = 1
|
||||
notify_ai(1)
|
||||
notify_ai(NEW_BORG)
|
||||
. = 1
|
||||
|
||||
/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
|
||||
..()
|
||||
if(oldname != real_name)
|
||||
notify_ai(3, oldname, newname)
|
||||
notify_ai(RENAME, oldname, newname)
|
||||
if(camera)
|
||||
camera.c_tag = real_name
|
||||
custom_name = newname
|
||||
@@ -967,6 +961,7 @@
|
||||
|
||||
speed = 0
|
||||
ionpulse = FALSE
|
||||
revert_shell()
|
||||
|
||||
return 1
|
||||
|
||||
@@ -985,6 +980,11 @@
|
||||
else
|
||||
status_flags &= ~CANPUSH
|
||||
|
||||
if(module.clean_on_move)
|
||||
flags |= CLEAN_ON_MOVE
|
||||
else
|
||||
flags &= ~CLEAN_ON_MOVE
|
||||
|
||||
hat_offset = module.hat_offset
|
||||
|
||||
magpulse = module.magpulsing
|
||||
@@ -998,6 +998,97 @@
|
||||
new_hat.forceMove(src)
|
||||
update_icons()
|
||||
|
||||
/mob/living/silicon/robot/proc/make_shell(var/obj/item/borg/upgrade/ai/board)
|
||||
if(!board)
|
||||
upgrades |= new /obj/item/borg/upgrade/ai(src)
|
||||
shell = TRUE
|
||||
braintype = "AI Shell"
|
||||
name = "[designation] AI Shell [rand(100,999)]"
|
||||
real_name = name
|
||||
GLOB.available_ai_shells |= src
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
diag_hud_set_aishell()
|
||||
notify_ai(AI_SHELL)
|
||||
|
||||
/mob/living/silicon/robot/proc/revert_shell()
|
||||
if(!shell)
|
||||
return
|
||||
undeploy()
|
||||
for(var/obj/item/borg/upgrade/ai/boris in src)
|
||||
//A player forced reset of a borg would drop the module before this is called, so this is for catching edge cases
|
||||
qdel(boris)
|
||||
shell = FALSE
|
||||
GLOB.available_ai_shells -= src
|
||||
name = "Unformatted Cyborg [rand(100,999)]"
|
||||
real_name = name
|
||||
if(camera)
|
||||
camera.c_tag = real_name
|
||||
diag_hud_set_aishell()
|
||||
|
||||
/mob/living/silicon/robot/proc/deploy_init(var/mob/living/silicon/ai/AI)
|
||||
real_name = "[AI.real_name] shell [rand(100, 999)] - [designation]" //Randomizing the name so it shows up seperately in the shells list
|
||||
name = real_name
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
mainframe = AI
|
||||
deployed = TRUE
|
||||
connected_ai = mainframe
|
||||
mainframe.connected_robots |= src
|
||||
lawupdate = TRUE
|
||||
lawsync()
|
||||
if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor
|
||||
if(AI.radio.syndie)
|
||||
radio.make_syndie()
|
||||
radio.subspace_transmission = TRUE
|
||||
radio.channels = AI.radio.channels
|
||||
for(var/chan in radio.channels)
|
||||
radio.secure_radio_connections[chan] = add_radio(radio, GLOB.radiochannels[chan])
|
||||
|
||||
diag_hud_set_aishell()
|
||||
undeployment_action.Grant(src)
|
||||
|
||||
/datum/action/innate/undeployment
|
||||
name = "Disconnect from shell"
|
||||
desc = "Stop controlling your shell and resume normal core operations."
|
||||
button_icon_state = "ai_core"
|
||||
|
||||
/datum/action/innate/undeployment/Trigger()
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/mob/living/silicon/robot/R = owner
|
||||
|
||||
R.undeploy()
|
||||
return TRUE
|
||||
|
||||
|
||||
/mob/living/silicon/robot/proc/undeploy()
|
||||
|
||||
if(!deployed || !mind || !mainframe)
|
||||
return
|
||||
mainframe.redeploy_action.Grant(mainframe)
|
||||
mainframe.redeploy_action.last_used_shell = src
|
||||
mind.transfer_to(mainframe)
|
||||
deployed = FALSE
|
||||
mainframe.deployed_shell = null
|
||||
undeployment_action.Remove(src)
|
||||
if(radio) //Return radio to normal
|
||||
radio.recalculateChannels()
|
||||
if(camera)
|
||||
camera.c_tag = real_name //update the camera name too
|
||||
diag_hud_set_aishell()
|
||||
mainframe.diag_hud_set_deployed()
|
||||
mainframe.show_laws() //Always remind the AI when switching
|
||||
mainframe = null
|
||||
|
||||
/mob/living/silicon/robot/attack_ai(mob/user)
|
||||
if(shell && (!connected_ai || connected_ai == user))
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
AI.deploy_to_shell(src)
|
||||
|
||||
/mob/living/silicon/robot/shell
|
||||
shell = TRUE
|
||||
|
||||
/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
|
||||
. = ..()
|
||||
if(!(M in buckled_mobs) && isliving(M))
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
if (M.a_intent == INTENT_DISARM)
|
||||
if(!(lying))
|
||||
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
|
||||
if(get_active_held_item())
|
||||
var/obj/item/I = get_active_held_item()
|
||||
if(I)
|
||||
uneq_active()
|
||||
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
|
||||
"<span class='userdanger'>[M] has disabled [src]'s active module!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
add_logs(M, src, "disarmed")
|
||||
add_logs(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
|
||||
else
|
||||
Stun(2)
|
||||
step(src,get_dir(M,src))
|
||||
@@ -92,6 +93,8 @@
|
||||
if(locked)
|
||||
to_chat(user, "<span class='notice'>You emag the cover lock.</span>")
|
||||
locked = 0
|
||||
if(shell) //A warning to Traitors who may not know that emagging AI shells does not slave them.
|
||||
to_chat(user, "<span class='boldwarning'>[src] seems to be controlled remotely! Emagging the interface may not work as expected.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The cover is already unlocked!</span>")
|
||||
return
|
||||
@@ -125,6 +128,12 @@
|
||||
log_game("[key_name(user)] attempted to emag cyborg [key_name(src)], but they were slaved to traitor AI [connected_ai].")
|
||||
return
|
||||
|
||||
if(shell) //AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however.
|
||||
to_chat(user, "<span class='danger'>[src] is remotely controlled! Your emag attempt has triggered a system reset instead!</span>")
|
||||
log_game("[key_name(user)] attempted to emag an AI shell belonging to [key_name(src) ? key_name(src) : connected_ai]. The shell has been reset as a result.")
|
||||
ResetModule()
|
||||
return
|
||||
|
||||
SetEmagged(1)
|
||||
SetStunned(3) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
|
||||
lawupdate = 0
|
||||
@@ -132,7 +141,7 @@
|
||||
message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
|
||||
log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
|
||||
GLOB.lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
|
||||
to_chat(src, "<span class='danger'>ALERT: Foreign software detected.</span>")
|
||||
sleep(5)
|
||||
to_chat(src, "<span class='danger'>Initiating diagnostics...</span>")
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
var/can_be_pushed = TRUE
|
||||
var/magpulsing = FALSE
|
||||
var/clean_on_move = FALSE
|
||||
|
||||
var/did_feedback = FALSE
|
||||
var/feedback_key
|
||||
@@ -217,7 +218,7 @@
|
||||
R.SetLockdown(0)
|
||||
R.anchored = FALSE
|
||||
R.notransform = FALSE
|
||||
R.notify_ai(2)
|
||||
R.notify_ai(NEW_MODULE)
|
||||
if(R.hud_used)
|
||||
R.hud_used.update_robot_modules_display()
|
||||
if(feedback_key && !did_feedback)
|
||||
@@ -228,8 +229,17 @@
|
||||
basic_modules = list(
|
||||
/obj/item/device/assembly/flash/cyborg,
|
||||
/obj/item/weapon/reagent_containers/borghypo/epi,
|
||||
/obj/item/device/healthanalyzer,
|
||||
/obj/item/weapon/weldingtool/largetank/cyborg,
|
||||
/obj/item/weapon/wrench/cyborg,
|
||||
/obj/item/weapon/crowbar/cyborg,
|
||||
/obj/item/stack/sheet/metal/cyborg,
|
||||
/obj/item/stack/rods/cyborg,
|
||||
/obj/item/stack/tile/plasteel/cyborg,
|
||||
/obj/item/weapon/extinguisher,
|
||||
/obj/item/weapon/pickaxe,
|
||||
/obj/item/device/t_scanner/adv_mining_scanner,
|
||||
/obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg,
|
||||
/obj/item/weapon/soap/nanotrasen,
|
||||
/obj/item/borg/cyborghug)
|
||||
emag_modules = list(/obj/item/weapon/melee/energy/sword/cyborg)
|
||||
@@ -382,6 +392,7 @@
|
||||
moduleselect_icon = "janitor"
|
||||
feedback_key = "cyborg_janitor"
|
||||
hat_offset = -5
|
||||
clean_on_move = TRUE
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/cyborg_drying
|
||||
name = "drying agent spray"
|
||||
|
||||
Reference in New Issue
Block a user