Merge branch 'master' into upstream-merge-31116

This commit is contained in:
LetterJay
2017-10-01 15:09:10 -04:00
committed by GitHub
199 changed files with 71828 additions and 5775 deletions
+1 -1
View File
@@ -118,7 +118,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
else if(dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
if(dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = config.starlight ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
dynamic_lighting = CONFIG_GET(flag/starlight) ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
. = ..()
+1 -1
View File
@@ -78,7 +78,7 @@ GLOBAL_LIST_EMPTY(blobs_legit) //used for win-score calculations, contains only
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
B.mind.name = B.name
var/turf/T = pick(GLOB.blobstart)
B.loc = T
B.forceMove(T)
B.base_point_rate = blob_point_rate
SSshuttle.registerHostileEnvironment(src)
+1 -1
View File
@@ -7,7 +7,7 @@
if(B.blob_core || !B.placed)
return 0
if(!GLOB.blob_cores.len) //blob is dead
if(config.continuous["blob"])
if(CONFIG_GET(keyed_flag_list/continuous)["blob"])
message_sent = FALSE //disable the win count at this point
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
SSshuttle.clearHostileEnvironment(src)
+1 -1
View File
@@ -59,7 +59,7 @@
set name = "Jump to Core"
set desc = "Move your camera to your core."
if(blob_core)
src.loc = blob_core.loc
forceMove(blob_core.drop_location())
/mob/camera/blob/verb/jump_to_node()
set category = "Blob"
+1 -1
View File
@@ -190,7 +190,7 @@
B.density = TRUE
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
B.density = initial(B.density)
B.loc = T
B.forceMove(T)
B.update_icon()
if(B.overmind && expand_reaction)
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
+6 -5
View File
@@ -17,7 +17,7 @@
/datum/objective_team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, config.brother_objectives_amount + (members.len > 2) - is_hijacker))
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
@@ -58,16 +58,17 @@
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/game_mode/traitor/bros/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER)
var/num_teams = team_amount
if(config.brother_scaling_coeff)
num_teams = max(1, round(num_players()/config.brother_scaling_coeff))
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
if(bsc)
num_teams = max(1, round(num_players() / bsc))
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
+18 -10
View File
@@ -52,16 +52,17 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
/datum/game_mode/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*2))+2, round(num_players()/config.changeling_scaling_coeff) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 2)) + 2, round(num_players() / csc)))
else
num_changelings = max(1, min(num_players(), changeling_amount))
@@ -102,10 +103,11 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2))+2, round(GLOB.joined_player_list.len/config.changeling_scaling_coeff) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (config.changeling_scaling_coeff*2)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
@@ -131,10 +133,16 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
changeling.objectives += absorb_objective
if(prob(60))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
if(prob(85))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
else
var/datum/objective/download/download_objective = new
download_objective.owner = changeling
download_objective.gen_amount_goal()
changeling.objectives += download_objective
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
@@ -30,7 +30,7 @@
sleep(5) // So it's not killed in explosion
var/mob/living/simple_animal/hostile/headcrab/crab = new(turf)
for(var/obj/item/organ/I in organs)
I.loc = crab
I.forceMove(crab)
crab.origin = M
if(crab.origin)
crab.origin.active = 1
@@ -25,18 +25,19 @@
return 1
/datum/game_mode/traitor/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING)
var/num_changelings = 1
if(config.changeling_scaling_coeff)
num_changelings = max(1, min( round(num_players()/(config.changeling_scaling_coeff*4))+2, round(num_players()/(config.changeling_scaling_coeff*2)) ))
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
if(csc)
num_changelings = max(1, min(round(num_players() / (csc * 4)) + 2, round(num_players() / (csc * 2))))
else
num_changelings = max(1, min(num_players(), changeling_amount/2))
@@ -64,11 +65,12 @@
return
/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/changelingcap = min( round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*4))+2, round(GLOB.joined_player_list.len/(config.changeling_scaling_coeff*2)) )
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2)))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (config.changeling_scaling_coeff * 4)))
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
+2 -2
View File
@@ -107,9 +107,9 @@ Credit where due:
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
/datum/game_mode/clockwork_cult/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/starter_servants = 4 //Guaranteed four servants
var/number_players = num_players()
+2 -2
View File
@@ -55,10 +55,10 @@
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
//cult scaling goes here
+5 -4
View File
@@ -20,15 +20,16 @@
+ <span class='notice'>Crew</span>: Resist the lure of sin and remain pure!"
/datum/game_mode/devil/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_devils = 1
if(config.traitor_scaling_coeff)
num_devils = max(minimum_devils, min( round(num_players()/(config.traitor_scaling_coeff*3))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff*1.5)) + num_modifier ))
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
if(tsc)
num_devils = max(minimum_devils, min( round(num_players() / (tsc * 3))+ 2 + num_modifier, round(num_players() / (tsc * 1.5)) + num_modifier))
else
num_devils = max(minimum_devils, min(num_players(), traitors_possible))
+18 -14
View File
@@ -78,7 +78,7 @@
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
report = config.intercept
report = !CONFIG_GET(flag/no_intercept_report)
addtimer(CALLBACK(GLOBAL_PROC, .proc/display_roundstart_logout_report), ROUNDSTART_LOGOUT_REPORT_TIME)
if(SSdbcore.Connect())
@@ -113,8 +113,9 @@
for(var/mob/Player in GLOB.mob_list)
if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) && !isbrain(Player) && Player.client)
living_crew += Player
if(living_crew.len / GLOB.joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
var/malc = CONFIG_GET(number/midround_antag_life_check)
if(living_crew.len / GLOB.joined_player_list.len <= malc) //If a lot of the player base died, we start fresh
message_admins("Convert_roundtype failed due to too many dead people. Limit is [malc * 100]% living crew")
return null
var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew.len)
@@ -138,8 +139,9 @@
if(SSshuttle.emergency.timeLeft(1) < initial(SSshuttle.emergencyCallTime)*0.5)
return 1
if(world.time >= (config.midround_antag_time_check * 600))
message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
var/matc = CONFIG_GET(number/midround_antag_time_check)
if(world.time >= (matc * 600))
message_admins("Convert_roundtype failed due to round length. Limit is [matc] minutes.")
return null
var/list/antag_candidates = list()
@@ -154,9 +156,9 @@
antag_candidates = shuffle(antag_candidates)
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
replacementmode.restricted_jobs += replacementmode.protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
replacementmode.restricted_jobs += "Assistant"
message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit <A HREF='?_src_=holder;[HrefToken()];toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;[HrefToken()];end_round=\ref[usr]'>end the round now</A>.")
@@ -168,7 +170,7 @@
round_converted = 0
return
//somewhere between 1 and 3 minutes from now
if(!config.midround_antag[SSticker.mode.config_tag])
if(!CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag])
round_converted = 0
return 1
for(var/mob/living/carbon/human/H in antag_candidates)
@@ -189,7 +191,9 @@
return TRUE
if(station_was_nuked)
return TRUE
if(!round_converted && (!config.continuous[config_tag] || (config.continuous[config_tag] && config.midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
var/list/continuous = CONFIG_GET(keyed_flag_list/continuous)
var/list/midround_antag = CONFIG_GET(keyed_flag_list/midround_antag)
if(!round_converted && (!continuous[config_tag] || (continuous[config_tag] && midround_antag[config_tag]))) //Non-continuous or continous with replacement antags
if(!continuous_sanity_checked) //make sure we have antags to be checking in the first place
for(var/mob/Player in GLOB.mob_list)
if(Player.mind)
@@ -198,8 +202,8 @@
return 0
if(!continuous_sanity_checked)
message_admins("The roundtype ([config_tag]) has no antagonists, continuous round has been defaulted to on and midround_antag has been defaulted to off.")
config.continuous[config_tag] = 1
config.midround_antag[config_tag] = 0
continuous[config_tag] = TRUE
midround_antag[config_tag] = FALSE
SSshuttle.clearHostileEnvironment(src)
return 0
@@ -213,7 +217,7 @@
living_antag_player = Player
return 0
if(!config.continuous[config_tag] || force_ending)
if(!continuous[config_tag] || force_ending)
return 1
else
@@ -222,7 +226,7 @@
if(round_ends_with_antag_death)
return 1
else
config.midround_antag[config_tag] = 0
midround_antag[config_tag] = 0
return 0
return 0
@@ -517,7 +521,7 @@
/datum/game_mode/proc/get_remaining_days(client/C)
if(!C)
return 0
if(!config.use_age_restriction_for_jobs)
if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
return 0
if(!isnum(C.player_age))
return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
@@ -34,7 +34,7 @@
to_chat(world, "<b>Crew</b> - don't get abducted and stop the abductors.")
/datum/game_mode/abduction/pre_setup()
var/num_teams = max(1, min(max_teams, round(num_players() / config.abductor_scaling_coeff)))
var/num_teams = max(1, min(max_teams, round(num_players() / CONFIG_GET(number/abductor_scaling_coeff))))
var/possible_teams = max(1, round(antag_candidates.len / 2))
num_teams = min(num_teams, possible_teams)
@@ -60,9 +60,8 @@
/obj/machinery/abductor/gland_dispenser/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/organ/heart/gland))
if(!user.drop_item())
if(!user.transferItemToLoc(W, src))
return
W.loc = src
for(var/i=1,i<=gland_colors.len,i++)
if(gland_types[i] == W.type)
amounts[i]++
@@ -62,7 +62,7 @@
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.gender == FEMALE) ? "f" : "m"
if(!config.mutant_races || H.dna.species.use_skintones)
if(!CONFIG_GET(flag/join_with_mutant_race) || H.dna.species.use_skintones)
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]")
else
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]")
@@ -502,7 +502,7 @@
var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
M.amount = 5
for(var/obj/item/I in target.component_parts)
I.loc = M.loc
I.forceMove(M.drop_location())
var/obj/effect/temp_visual/swarmer/disintegration/N = new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
N.pixel_x = target.pixel_x
N.pixel_y = target.pixel_y
@@ -511,7 +511,7 @@
if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
if(C.circuit)
C.circuit.loc = M.loc
C.circuit.forceMove(M.drop_location())
qdel(target)
@@ -77,7 +77,7 @@
/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A)
if(A && A.loc != src)
visible_message("<span class='warning'>[src] swallows [A] whole!</span>")
A.loc = src
A.forceMove(src)
return 1
return 0
@@ -153,7 +153,7 @@
/mob/living/simple_animal/hostile/morph/proc/barf_contents()
for(var/atom/movable/AM in src)
AM.loc = loc
AM.forceMove(loc)
if(prob(90))
step(AM, pick(GLOB.alldirs))
+1 -1
View File
@@ -110,7 +110,7 @@
P.info = "The nuclear authorization code is: <b>[nuke_code]</b>"
P.name = "nuclear bomb code"
var/mob/living/carbon/human/H = synd_mind.current
P.loc = H.loc
P.forceMove(H.drop_location())
H.put_in_hands_or_del(P)
H.update_icons()
else
@@ -58,7 +58,7 @@
U.hidden_uplink.owner = "[user.key]"
U.hidden_uplink.telecrystals = CHALLENGE_TELECRYSTALS
U.hidden_uplink.set_gamemode(/datum/game_mode/nuclear)
config.shuttle_refuel_delay = max(config.shuttle_refuel_delay, CHALLENGE_SHUTTLE_DELAY)
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.set_val("nuclear_challenge_mode",1)
qdel(src)
+25 -18
View File
@@ -506,24 +506,31 @@ GLOBAL_LIST_EMPTY(possible_items_special)
explanation_text = "Download [target_amount] research level\s."
return target_amount
/datum/objective/download/check_completion()//NINJACODE.
var/current_amount = 0
/datum/objective/download/check_completion()
var/list/current_tech = list()
var/list/datum/mind/owners = get_owners()
for(var/datum/mind/M in owners)
if(!ishuman(owner.current))
continue
var/mob/living/carbon/human/H = owner.current
if(!H || H.stat == DEAD || !istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
continue
var/obj/item/clothing/suit/space/space_ninja/SN = H.wear_suit
if(!SN.s_initialized)
continue
for(var/datum/tech/current_data in SN.stored_research)
if(current_data.level)
current_amount += (current_data.level-1)
return current_amount >= target_amount
for(var/datum/mind/owner in owners)
if(ismob(owner.current))
var/mob/M = owner.current //Yeah if you get morphed and you eat a quantum tech disk with the RD's latest backup good on you soldier.
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H && (H.stat != DEAD) && istype(H.wear_suit, /obj/item/clothing/suit/space/space_ninja))
var/obj/item/clothing/suit/space/space_ninja/S = H.wear_suit
for(var/datum/tech/T in S.stored_research)
current_tech[T.id] = T.level? T.level : 0
var/list/otherwise = M.GetAllContents()
for(var/obj/item/disk/tech_disk/TD in otherwise)
for(var/datum/tech/T in TD.tech_stored)
if(!T.id || !T.level)
continue
else if(!current_tech[T.id])
current_tech[T.id] = T.level
else if(T.level > current_tech[T.id])
current_tech[T.id] = T.level
var/total = 0
for(var/i in current_tech)
total += current_tech[i]
return total >= target_amount
/datum/objective/capture
@@ -586,7 +593,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
for(var/datum/mind/M in owners)
if(!owner || !owner.changeling || !owner.changeling.stored_profiles)
continue
absorbedcount += M.changeling.absorbedcount
absorbedcount += M.changeling.absorbedcount
return absorbedcount >= target_amount
+3 -3
View File
@@ -44,10 +44,10 @@
///////////////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
for (var/i=1 to max_headrevs)
@@ -230,7 +230,7 @@
//Checks if the round is over//
///////////////////////////////
/datum/game_mode/revolution/check_finished()
if(config.continuous["revolution"])
if(CONFIG_GET(keyed_flag_list/continuous)["revolution"])
if(finished)
SSshuttle.clearHostileEnvironment(src)
return ..()
+298 -298
View File
@@ -1,303 +1,303 @@
GLOBAL_VAR_INIT(hsboxspawn, TRUE)
/mob
var/datum/hSB/sandbox = null
/mob/proc/CanBuild()
sandbox = new/datum/hSB
sandbox.owner = src.ckey
if(src.client.holder)
sandbox.admin = 1
verbs += new/mob/proc/sandbox_panel
/mob/proc/sandbox_panel()
set name = "Sandbox Panel"
if(sandbox)
sandbox.update()
/datum/hSB
var/owner = null
var/admin = 0
GLOBAL_VAR_INIT(hsboxspawn, TRUE)
/mob
var/datum/hSB/sandbox = null
/mob/proc/CanBuild()
sandbox = new/datum/hSB
sandbox.owner = src.ckey
if(src.client.holder)
sandbox.admin = 1
verbs += new/mob/proc/sandbox_panel
/mob/proc/sandbox_panel()
set name = "Sandbox Panel"
if(sandbox)
sandbox.update()
/datum/hSB
var/owner = null
var/admin = 0
var/static/clothinfo = null
var/static/reaginfo = null
var/static/objinfo = null
var/canisterinfo = null
var/hsbinfo = null
//items that shouldn't spawn on the floor because they would bug or act weird
var/global/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
var/canisterinfo = null
var/hsbinfo = null
//items that shouldn't spawn on the floor because they would bug or act weird
var/global/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
/obj/item/assembly, /obj/item/device/onetankbomb, /obj/item/radio, /obj/item/device/pda/ai,
/obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/projectile,
/obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/projectile,
/obj/item/borg/sight, /obj/item/borg/stun, /obj/item/robot_module)
/datum/hSB/proc/update()
var/global/list/hrefs = list(
"Space Gear",
"Suit Up (Space Travel Gear)" = "hsbsuit",
"Spawn Gas Mask" = "hsbspawn&path=[/obj/item/clothing/mask/gas]",
"Spawn Emergency Air Tank" = "hsbspawn&path=[/obj/item/tank/internals/emergency_oxygen/double]",
"Standard Tools",
"Spawn Flashlight" = "hsbspawn&path=[/obj/item/device/flashlight]",
"Spawn Toolbox" = "hsbspawn&path=[/obj/item/storage/toolbox/mechanical]",
"Spawn Light Replacer" = "hsbspawn&path=[/obj/item/device/lightreplacer]",
"Spawn Medical Kit" = "hsbspawn&path=[/obj/item/storage/firstaid/regular]",
"Spawn All-Access ID" = "hsbaaid",
"Building Supplies",
"Spawn 50 Wood" = "hsbwood",
"Spawn 50 Metal" = "hsbmetal",
"Spawn 50 Plasteel" = "hsbplasteel",
"Spawn 50 Reinforced Glass" = "hsbrglass",
"Spawn 50 Glass" = "hsbglass",
"Spawn Full Cable Coil" = "hsbspawn&path=[/obj/item/stack/cable_coil]",
"Spawn Hyper Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/hyper]",
"Spawn Inf. Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/infinite]",
"Spawn Rapid Construction Device" = "hsbrcd",
"Spawn RCD Ammo" = "hsb_safespawn&path=[/obj/item/rcd_ammo]",
"Spawn Airlock" = "hsbairlock",
"Miscellaneous",
"Spawn Air Scrubber" = "hsbscrubber",
"Spawn Welding Fuel Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/fueltank]",
"Spawn Water Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",
"Bots",
"Spawn Cleanbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/cleanbot]",
"Spawn Floorbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/floorbot]",
"Spawn Medbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/medbot]",
"Canisters",
"Spawn O2 Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
"Spawn Air Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/air]")
if(!hsbinfo)
hsbinfo = "<center><b>Sandbox Panel</b></center><hr>"
if(admin)
hsbinfo += "<b>Administration</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "<b>Canister Spawning</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
else
hsbinfo += "<i>Some item spawning may be disabled by the administrators.</i><br>"
hsbinfo += "<i>Only administrators may spawn dangerous canisters.</i><br>"
for(var/T in hrefs)
var/href = hrefs[T]
if(href)
hsbinfo += "- <a href='?\ref[src];hsb=[hrefs[T]]'>[T]</a><br>"
else
hsbinfo += "<br><b>[T]</b><br>"
hsbinfo += "<hr>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
usr << browse(hsbinfo, "window=hsbpanel")
/datum/hSB/Topic(href, href_list)
if(!usr || !src || !(src.owner == usr.ckey))
if(usr)
usr << browse(null,"window=sandbox")
return
if(href_list["hsb"])
switch(href_list["hsb"])
//
// Admin: toggle spawning
//
if("hsbtobj")
if(!admin) return
if(GLOB.hsboxspawn)
to_chat(world, "<span class='boldannounce'>Sandbox:</span> <b>\black[usr.key] has disabled object spawning!</b>")
GLOB.hsboxspawn = FALSE
return
else
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black[usr.key] has enabled object spawning!</b>")
GLOB.hsboxspawn = TRUE
return
//
// Admin: Toggle auto-close
//
if("hsbtac")
if(!admin) return
if(config.sandbox_autoclose)
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black [usr.key] has removed the object spawn limiter.</b>")
config.sandbox_autoclose = FALSE
else
to_chat(world, "<span class='danger'>Sandbox:</span> <b>\black [usr.key] has added a limiter to object spawning. The window will now auto-close after use.</b>")
config.sandbox_autoclose = TRUE
return
//
// Spacesuit with full air jetpack set as internals
//
if("hsbsuit")
var/mob/living/carbon/human/P = usr
if(!istype(P)) return
if(P.wear_suit)
P.wear_suit.loc = P.loc
P.wear_suit.layer = initial(P.wear_suit.layer)
P.wear_suit.plane = initial(P.wear_suit.plane)
P.wear_suit = null
P.wear_suit = new/obj/item/clothing/suit/space(P)
P.wear_suit.layer = ABOVE_HUD_LAYER
P.wear_suit.plane = ABOVE_HUD_PLANE
P.update_inv_wear_suit()
if(P.head)
P.head.loc = P.loc
P.head.layer = initial(P.head.layer)
P.head.plane = initial(P.head.plane)
P.head = null
P.head = new/obj/item/clothing/head/helmet/space(P)
P.head.layer = ABOVE_HUD_LAYER
P.head.plane = ABOVE_HUD_PLANE
P.update_inv_head()
if(P.wear_mask)
P.wear_mask.loc = P.loc
P.wear_mask.layer = initial(P.wear_mask.layer)
P.wear_mask.plane = initial(P.wear_mask.plane)
P.wear_mask = null
P.wear_mask = new/obj/item/clothing/mask/gas(P)
P.wear_mask.layer = ABOVE_HUD_LAYER
P.wear_mask.plane = ABOVE_HUD_PLANE
P.update_inv_wear_mask()
if(P.back)
P.back.loc = P.loc
P.back.layer = initial(P.back.layer)
P.back.plane = initial(P.back.plane)
P.back = null
P.back = new/obj/item/tank/jetpack/oxygen(P)
P.back.layer = ABOVE_HUD_LAYER
P.back.plane = ABOVE_HUD_PLANE
P.update_inv_back()
P.internal = P.back
P.update_internals_hud_icon(1)
if("hsbscrubber") // This is beyond its normal capability but this is sandbox and you spawned one, I assume you need it
var/obj/hsb = new/obj/machinery/portable_atmospherics/scrubber{volume_rate=50*ONE_ATMOSPHERE;on=1}(usr.loc)
hsb.update_icon() // hackish but it wasn't meant to be spawned I guess?
//
// Stacked Materials
//
if("hsbrglass")
new/obj/item/stack/sheet/rglass{amount=50}(usr.loc)
if("hsbmetal")
new/obj/item/stack/sheet/metal{amount=50}(usr.loc)
if("hsbplasteel")
new/obj/item/stack/sheet/plasteel{amount=50}(usr.loc)
if("hsbglass")
new/obj/item/stack/sheet/glass{amount=50}(usr.loc)
if("hsbwood")
new/obj/item/stack/sheet/mineral/wood{amount=50}(usr.loc)
//
// All access ID
//
if("hsbaaid")
var/obj/item/card/id/gold/ID = new(usr.loc)
ID.registered_name = usr.real_name
ID.assignment = "Sandbox"
ID.access = get_all_accesses()
ID.update_label()
//
// RCD - starts with full clip
// Spawn check due to grief potential (destroying floors, walls, etc)
//
if("hsbrcd")
if(!GLOB.hsboxspawn) return
new/obj/item/construction/rcd/combat(usr.loc)
//
// New sandbox airlock maker
//
if("hsbairlock")
new /datum/airlock_maker(usr.loc)
//
// Object spawn window
//
// Clothing
if("hsbcloth")
if(!GLOB.hsboxspawn) return
if(!clothinfo)
clothinfo = "<b>Clothing</b> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/clothing)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
clothinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(clothinfo,"window=sandbox")
// Reagent containers
if("hsbreag")
if(!GLOB.hsboxspawn) return
if(!reaginfo)
reaginfo = "<b>Reagent Containers</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
reaginfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(reaginfo,"window=sandbox")
// Other items
if("hsbobj")
if(!GLOB.hsboxspawn) return
if(!objinfo)
objinfo = "<b>Other Items</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
objinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(objinfo,"window=sandbox")
//
// Safespawn checks to see if spawning is disabled.
//
if("hsb_safespawn")
if(!GLOB.hsboxspawn)
usr << browse(null,"window=sandbox")
return
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(config.sandbox_autoclose)
usr << browse(null,"window=sandbox")
//
// For everything else in the href list
//
if("hsbspawn")
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(config.sandbox_autoclose)
usr << browse(null,"window=sandbox")
/datum/hSB/proc/update()
var/global/list/hrefs = list(
"Space Gear",
"Suit Up (Space Travel Gear)" = "hsbsuit",
"Spawn Gas Mask" = "hsbspawn&path=[/obj/item/clothing/mask/gas]",
"Spawn Emergency Air Tank" = "hsbspawn&path=[/obj/item/tank/internals/emergency_oxygen/double]",
"Standard Tools",
"Spawn Flashlight" = "hsbspawn&path=[/obj/item/device/flashlight]",
"Spawn Toolbox" = "hsbspawn&path=[/obj/item/storage/toolbox/mechanical]",
"Spawn Light Replacer" = "hsbspawn&path=[/obj/item/device/lightreplacer]",
"Spawn Medical Kit" = "hsbspawn&path=[/obj/item/storage/firstaid/regular]",
"Spawn All-Access ID" = "hsbaaid",
"Building Supplies",
"Spawn 50 Wood" = "hsbwood",
"Spawn 50 Metal" = "hsbmetal",
"Spawn 50 Plasteel" = "hsbplasteel",
"Spawn 50 Reinforced Glass" = "hsbrglass",
"Spawn 50 Glass" = "hsbglass",
"Spawn Full Cable Coil" = "hsbspawn&path=[/obj/item/stack/cable_coil]",
"Spawn Hyper Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/hyper]",
"Spawn Inf. Capacity Power Cell" = "hsbspawn&path=[/obj/item/stock_parts/cell/infinite]",
"Spawn Rapid Construction Device" = "hsbrcd",
"Spawn RCD Ammo" = "hsb_safespawn&path=[/obj/item/rcd_ammo]",
"Spawn Airlock" = "hsbairlock",
"Miscellaneous",
"Spawn Air Scrubber" = "hsbscrubber",
"Spawn Welding Fuel Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/fueltank]",
"Spawn Water Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",
"Bots",
"Spawn Cleanbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/cleanbot]",
"Spawn Floorbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/floorbot]",
"Spawn Medbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/medbot]",
"Canisters",
"Spawn O2 Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
"Spawn Air Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/air]")
if(!hsbinfo)
hsbinfo = "<center><b>Sandbox Panel</b></center><hr>"
if(admin)
hsbinfo += "<b>Administration</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "<b>Canister Spawning</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
else
hsbinfo += "<i>Some item spawning may be disabled by the administrators.</i><br>"
hsbinfo += "<i>Only administrators may spawn dangerous canisters.</i><br>"
for(var/T in hrefs)
var/href = hrefs[T]
if(href)
hsbinfo += "- <a href='?\ref[src];hsb=[hrefs[T]]'>[T]</a><br>"
else
hsbinfo += "<br><b>[T]</b><br>"
hsbinfo += "<hr>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
usr << browse(hsbinfo, "window=hsbpanel")
/datum/hSB/Topic(href, href_list)
if(!usr || !src || !(src.owner == usr.ckey))
if(usr)
usr << browse(null,"window=sandbox")
return
if(href_list["hsb"])
switch(href_list["hsb"])
//
// Admin: toggle spawning
//
if("hsbtobj")
if(!admin) return
if(GLOB.hsboxspawn)
to_chat(world, "<span class='boldannounce'>Sandbox:</span> <b>\black[usr.key] has disabled object spawning!</b>")
GLOB.hsboxspawn = FALSE
return
else
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black[usr.key] has enabled object spawning!</b>")
GLOB.hsboxspawn = TRUE
return
//
// Admin: Toggle auto-close
//
if("hsbtac")
if(!admin) return
var/sbac = CONFIG_GET(flag/sandbox_autoclose)
if(sbac)
to_chat(world, "<span class='boldnotice'>Sandbox:</span> <b>\black [usr.key] has removed the object spawn limiter.</b>")
else
to_chat(world, "<span class='danger'>Sandbox:</span> <b>\black [usr.key] has added a limiter to object spawning. The window will now auto-close after use.</b>")
CONFIG_SET(flag/sandbox_autoclose, !sbac)
return
//
// Spacesuit with full air jetpack set as internals
//
if("hsbsuit")
var/mob/living/carbon/human/P = usr
if(!istype(P)) return
if(P.wear_suit)
P.wear_suit.forceMove(P.drop_location())
P.wear_suit.layer = initial(P.wear_suit.layer)
P.wear_suit.plane = initial(P.wear_suit.plane)
P.wear_suit = null
P.wear_suit = new/obj/item/clothing/suit/space(P)
P.wear_suit.layer = ABOVE_HUD_LAYER
P.wear_suit.plane = ABOVE_HUD_PLANE
P.update_inv_wear_suit()
if(P.head)
P.head.forceMove(P.drop_location())
P.head.layer = initial(P.head.layer)
P.head.plane = initial(P.head.plane)
P.head = null
P.head = new/obj/item/clothing/head/helmet/space(P)
P.head.layer = ABOVE_HUD_LAYER
P.head.plane = ABOVE_HUD_PLANE
P.update_inv_head()
if(P.wear_mask)
P.wear_mask.forceMove(P.drop_location())
P.wear_mask.layer = initial(P.wear_mask.layer)
P.wear_mask.plane = initial(P.wear_mask.plane)
P.wear_mask = null
P.wear_mask = new/obj/item/clothing/mask/gas(P)
P.wear_mask.layer = ABOVE_HUD_LAYER
P.wear_mask.plane = ABOVE_HUD_PLANE
P.update_inv_wear_mask()
if(P.back)
P.back.forceMove(P.drop_location())
P.back.layer = initial(P.back.layer)
P.back.plane = initial(P.back.plane)
P.back = null
P.back = new/obj/item/tank/jetpack/oxygen(P)
P.back.layer = ABOVE_HUD_LAYER
P.back.plane = ABOVE_HUD_PLANE
P.update_inv_back()
P.internal = P.back
P.update_internals_hud_icon(1)
if("hsbscrubber") // This is beyond its normal capability but this is sandbox and you spawned one, I assume you need it
var/obj/hsb = new/obj/machinery/portable_atmospherics/scrubber{volume_rate=50*ONE_ATMOSPHERE;on=1}(usr.loc)
hsb.update_icon() // hackish but it wasn't meant to be spawned I guess?
//
// Stacked Materials
//
if("hsbrglass")
new/obj/item/stack/sheet/rglass{amount=50}(usr.loc)
if("hsbmetal")
new/obj/item/stack/sheet/metal{amount=50}(usr.loc)
if("hsbplasteel")
new/obj/item/stack/sheet/plasteel{amount=50}(usr.loc)
if("hsbglass")
new/obj/item/stack/sheet/glass{amount=50}(usr.loc)
if("hsbwood")
new/obj/item/stack/sheet/mineral/wood{amount=50}(usr.loc)
//
// All access ID
//
if("hsbaaid")
var/obj/item/card/id/gold/ID = new(usr.loc)
ID.registered_name = usr.real_name
ID.assignment = "Sandbox"
ID.access = get_all_accesses()
ID.update_label()
//
// RCD - starts with full clip
// Spawn check due to grief potential (destroying floors, walls, etc)
//
if("hsbrcd")
if(!GLOB.hsboxspawn) return
new/obj/item/construction/rcd/combat(usr.loc)
//
// New sandbox airlock maker
//
if("hsbairlock")
new /datum/airlock_maker(usr.loc)
//
// Object spawn window
//
// Clothing
if("hsbcloth")
if(!GLOB.hsboxspawn) return
if(!clothinfo)
clothinfo = "<b>Clothing</b> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/clothing)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
clothinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(clothinfo,"window=sandbox")
// Reagent containers
if("hsbreag")
if(!GLOB.hsboxspawn) return
if(!reaginfo)
reaginfo = "<b>Reagent Containers</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
reaginfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(reaginfo,"window=sandbox")
// Other items
if("hsbobj")
if(!GLOB.hsboxspawn) return
if(!objinfo)
objinfo = "<b>Other Items</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
objinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(objinfo,"window=sandbox")
//
// Safespawn checks to see if spawning is disabled.
//
if("hsb_safespawn")
if(!GLOB.hsboxspawn)
usr << browse(null,"window=sandbox")
return
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(CONFIG_GET(flag/sandbox_autoclose))
usr << browse(null,"window=sandbox")
//
// For everything else in the href list
//
if("hsbspawn")
var/typepath = text2path(href_list["path"])
if(!typepath)
to_chat(usr, "Bad path: \"[href_list["path"]]\"")
return
new typepath(usr.loc)
if(CONFIG_GET(flag/sandbox_autoclose))
usr << browse(null,"window=sandbox")
+8 -6
View File
@@ -31,16 +31,17 @@
/datum/game_mode/traitor/pre_setup()
if(config.protect_roles_from_antagonist)
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/num_traitors = 1
if(config.traitor_scaling_coeff)
num_traitors = max(1, min( round(num_players()/(config.traitor_scaling_coeff*2))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff)) + num_modifier ))
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
if(tsc)
num_traitors = max(1, min(round(num_players() / (tsc * 2)) + 2 + num_modifier, round(num_players() / tsc) + num_modifier))
else
num_traitors = max(1, min(num_players(), traitors_possible))
@@ -68,10 +69,11 @@
return 1
/datum/game_mode/traitor/make_antag_chance(mob/living/carbon/human/character) //Assigns traitor to latejoiners
var/traitorcap = min(round(GLOB.joined_player_list.len / (config.traitor_scaling_coeff * 2)) + 2 + num_modifier, round(GLOB.joined_player_list.len/config.traitor_scaling_coeff) + num_modifier )
var/tsc = CONFIG_GET(number/traitor_scaling_coeff)
var/traitorcap = min(round(GLOB.joined_player_list.len / (tsc * 2)) + 2 + num_modifier, round(GLOB.joined_player_list.len / tsc) + num_modifier)
if((SSticker.mode.traitors.len + pre_traitors.len) >= traitorcap) //Upper cap for number of latejoin antagonists
return
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (config.traitor_scaling_coeff * 2)))
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2)))
if(ROLE_TRAITOR in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_TRAITOR) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
+4 -5
View File
@@ -234,11 +234,10 @@
if(!link)
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
user.drop_item()
I.loc = src
link = I
to_chat(user, "You attach [I] to the doll.")
update_targets()
if (user.transferItemToLoc(I,src))
link = I
to_chat(user, "You attach [I] to the doll.")
update_targets()
/obj/item/voodoo/check_eye(mob/user)
if(loc != user)
+1 -1
View File
@@ -164,7 +164,7 @@
if(contents.len)
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
else
T.loc = src //put shade in stone
T.forceMove(src) //put shade in stone
T.status_flags |= GODMODE
T.canmove = 0
T.health = T.maxHealth
+3 -3
View File
@@ -478,7 +478,7 @@
/datum/spellbook_entry/summon/guns/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_guns)
return !CONFIG_GET(flag/no_summon_guns)
/datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
@@ -495,7 +495,7 @@
/datum/spellbook_entry/summon/magic/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_magic)
return !CONFIG_GET(flag/no_summon_magic)
/datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
@@ -513,7 +513,7 @@
/datum/spellbook_entry/summon/events/IsAvailible()
if(!SSticker.mode) // In case spellbook is placed on map
return 0
return (!config.no_summon_events)
return !CONFIG_GET(flag/no_summon_events)
/datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
SSblackbox.add_details("wizard_spell_learned", name)
+1 -1
View File
@@ -30,7 +30,7 @@
to_chat(wizard.current, "<span class='boldannounce'>A starting location for you could not be found, please report this bug!</span>")
return 0
for(var/datum/mind/wiz in wizards)
wiz.current.loc = pick(GLOB.wizardstart)
wiz.current.forceMove(pick(GLOB.wizardstart))
return 1
+2 -2
View File
@@ -44,10 +44,10 @@
var/turf/T = loc
Beacon = new /obj/item/device/radio/beacon
Beacon.invisibility = INVISIBILITY_MAXIMUM
Beacon.loc = T
Beacon.forceMove(T)
if(Beacon)
if(Beacon.loc != loc)
Beacon.loc = loc
Beacon.forceMove(loc)
updateicon()
+1 -1
View File
@@ -429,7 +429,7 @@ Class Procs:
W.handle_item_insertion(A, 1)
component_parts -= A
component_parts += B
B.loc = null
B.moveToNullspace()
to_chat(user, "<span class='notice'>[A.name] replaced with [B.name].</span>")
shouldplaysound = 1 //Only play the sound when parts are actually replaced!
break
+1 -1
View File
@@ -43,7 +43,7 @@
say("Station funds depleted. Halting siphon.")
siphoning = FALSE
else
new /obj/item/stack/spacecash/c200(get_turf(src)) // will autostack
new /obj/item/stack/spacecash/c200(drop_location()) // will autostack
playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
SSshuttle.points -= 200
if(next_warning < world.time && prob(15))
+2 -2
View File
@@ -127,10 +127,10 @@
if(panel_open)
if(device || board)
if(device)
device.loc = get_turf(src)
device.forceMove(drop_location())
device = null
if(board)
board.loc = get_turf(src)
board.forceMove(drop_location())
req_access = list()
req_one_access = list()
board = null
+1 -1
View File
@@ -246,7 +246,7 @@
if(disassembled)
if(!assembly)
assembly = new()
assembly.loc = src.loc
assembly.forceMove(drop_location())
assembly.state = 1
assembly.setDir(dir)
assembly = null
+141 -141
View File
@@ -1,145 +1,145 @@
/obj/item/wallframe/camera
name = "camera assembly"
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
icon = 'icons/obj/monitors.dmi'
icon_state = "cameracase"
materials = list(MAT_METAL=400, MAT_GLASS=250)
result_path = /obj/structure/camera_assembly
/obj/structure/camera_assembly
name = "camera assembly"
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
icon = 'icons/obj/monitors.dmi'
icon_state = "camera1"
max_integrity = 150
// Motion, EMP-Proof, X-Ray
var/static/list/possible_upgrades = typecacheof(list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/plasma, /obj/item/device/analyzer))
var/list/upgrades
var/state = 1
/*
1 = Wrenched in place
2 = Welded in place
3 = Wires attached to it (you can now attach/dettach upgrades)
4 = Screwdriver panel closed and is fully built (you cannot attach upgrades)
*/
/obj/structure/camera_assembly/Initialize(mapload, ndir, building)
. = ..()
if(building)
setDir(ndir)
upgrades = list()
/obj/structure/camera_assembly/Destroy()
QDEL_LIST(upgrades)
return ..()
/obj/structure/camera_assembly/attackby(obj/item/W, mob/living/user, params)
switch(state)
if(1)
// State 1
if(istype(W, /obj/item/weldingtool))
if(weld(W, user))
to_chat(user, "<span class='notice'>You weld the assembly securely into place.</span>")
/obj/item/wallframe/camera
name = "camera assembly"
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
icon = 'icons/obj/monitors.dmi'
icon_state = "cameracase"
materials = list(MAT_METAL=400, MAT_GLASS=250)
result_path = /obj/structure/camera_assembly
/obj/structure/camera_assembly
name = "camera assembly"
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
icon = 'icons/obj/monitors.dmi'
icon_state = "camera1"
max_integrity = 150
// Motion, EMP-Proof, X-Ray
var/static/list/possible_upgrades = typecacheof(list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/plasma, /obj/item/device/analyzer))
var/list/upgrades
var/state = 1
/*
1 = Wrenched in place
2 = Welded in place
3 = Wires attached to it (you can now attach/dettach upgrades)
4 = Screwdriver panel closed and is fully built (you cannot attach upgrades)
*/
/obj/structure/camera_assembly/Initialize(mapload, ndir, building)
. = ..()
if(building)
setDir(ndir)
upgrades = list()
/obj/structure/camera_assembly/Destroy()
QDEL_LIST(upgrades)
return ..()
/obj/structure/camera_assembly/attackby(obj/item/W, mob/living/user, params)
switch(state)
if(1)
// State 1
if(istype(W, /obj/item/weldingtool))
if(weld(W, user))
to_chat(user, "<span class='notice'>You weld the assembly securely into place.</span>")
anchored = TRUE
state = 2
return
else if(istype(W, /obj/item/wrench))
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You unattach the assembly from its place.</span>")
new /obj/item/wallframe/camera(get_turf(src))
qdel(src)
return
if(2)
// State 2
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.use(2))
to_chat(user, "<span class='notice'>You add wires to the assembly.</span>")
state = 3
else
to_chat(user, "<span class='warning'>You need two lengths of cable to wire a camera!</span>")
return
return
else if(istype(W, /obj/item/weldingtool))
if(weld(W, user))
to_chat(user, "<span class='notice'>You unweld the assembly from its place.</span>")
state = 1
state = 2
return
else if(istype(W, /obj/item/wrench))
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You unattach the assembly from its place.</span>")
new /obj/item/wallframe/camera(get_turf(src))
qdel(src)
return
if(2)
// State 2
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.use(2))
to_chat(user, "<span class='notice'>You add wires to the assembly.</span>")
state = 3
else
to_chat(user, "<span class='warning'>You need two lengths of cable to wire a camera!</span>")
return
return
else if(istype(W, /obj/item/weldingtool))
if(weld(W, user))
to_chat(user, "<span class='notice'>You unweld the assembly from its place.</span>")
state = 1
anchored = TRUE
return
if(3)
// State 3
if(istype(W, /obj/item/screwdriver))
playsound(src.loc, W.usesound, 50, 1)
return
if(3)
// State 3
if(istype(W, /obj/item/screwdriver))
playsound(src.loc, W.usesound, 50, 1)
var/input = stripped_input(user, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: SS13,Security,Secret ", "Set Network", "SS13")
if(!input)
to_chat(user, "<span class='warning'>No input found, please hang up and try your call again!</span>")
return
var/list/tempnetwork = splittext(input, ",")
if(tempnetwork.len < 1)
to_chat(user, "<span class='warning'>No network found, please hang up and try your call again!</span>")
return
state = 4
var/obj/machinery/camera/C = new(src.loc)
src.loc = C
C.assembly = src
C.setDir(src.dir)
C.network = tempnetwork
var/area/A = get_area(src)
C.c_tag = "[A.name] ([rand(1, 999)])"
else if(istype(W, /obj/item/wirecutters))
new/obj/item/stack/cable_coil(get_turf(src), 2)
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You cut the wires from the circuits.</span>")
state = 2
return
// Upgrades!
if(is_type_in_typecache(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already.
if(!user.drop_item(W))
return
to_chat(user, "<span class='notice'>You attach \the [W] into the assembly inner circuits.</span>")
upgrades += W
W.forceMove(src)
return
// Taking out upgrades
else if(istype(W, /obj/item/crowbar) && upgrades.len)
var/obj/U = locate(/obj) in upgrades
if(U)
to_chat(user, "<span class='notice'>You unattach an upgrade from the assembly.</span>")
playsound(src.loc, W.usesound, 50, 1)
U.loc = get_turf(src)
upgrades -= U
return
return ..()
/obj/structure/camera_assembly/proc/weld(obj/item/weldingtool/WT, mob/living/user)
if(!WT.remove_fuel(0, user))
return 0
to_chat(user, "<span class='notice'>You start to weld \the [src]...</span>")
playsound(src.loc, WT.usesound, 50, 1)
if(do_after(user, 20*WT.toolspeed, target = src))
if(WT.isOn())
playsound(loc, 'sound/items/welder2.ogg', 50, 1)
return 1
return 0
/obj/structure/camera_assembly/deconstruct(disassembled = TRUE)
if(!input)
to_chat(user, "<span class='warning'>No input found, please hang up and try your call again!</span>")
return
var/list/tempnetwork = splittext(input, ",")
if(tempnetwork.len < 1)
to_chat(user, "<span class='warning'>No network found, please hang up and try your call again!</span>")
return
state = 4
var/obj/machinery/camera/C = new(src.loc)
forceMove(C)
C.assembly = src
C.setDir(src.dir)
C.network = tempnetwork
var/area/A = get_area(src)
C.c_tag = "[A.name] ([rand(1, 999)])"
else if(istype(W, /obj/item/wirecutters))
new/obj/item/stack/cable_coil(get_turf(src), 2)
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You cut the wires from the circuits.</span>")
state = 2
return
// Upgrades!
if(is_type_in_typecache(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already.
if(!user.drop_item(W))
return
to_chat(user, "<span class='notice'>You attach \the [W] into the assembly inner circuits.</span>")
upgrades += W
W.forceMove(src)
return
// Taking out upgrades
else if(istype(W, /obj/item/crowbar) && upgrades.len)
var/obj/U = locate(/obj) in upgrades
if(U)
to_chat(user, "<span class='notice'>You unattach an upgrade from the assembly.</span>")
playsound(src.loc, W.usesound, 50, 1)
U.forceMove(drop_location())
upgrades -= U
return
return ..()
/obj/structure/camera_assembly/proc/weld(obj/item/weldingtool/WT, mob/living/user)
if(!WT.remove_fuel(0, user))
return 0
to_chat(user, "<span class='notice'>You start to weld \the [src]...</span>")
playsound(src.loc, WT.usesound, 50, 1)
if(do_after(user, 20*WT.toolspeed, target = src))
if(WT.isOn())
playsound(loc, 'sound/items/welder2.ogg', 50, 1)
return 1
return 0
/obj/structure/camera_assembly/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
new /obj/item/stack/sheet/metal(loc)
qdel(src)
new /obj/item/stack/sheet/metal(loc)
qdel(src)
+5 -6
View File
@@ -45,14 +45,13 @@
if(!isarea(a))
return
if(a.power_equip == 0) // There's no APC in this area, don't try to cheat power!
to_chat(user, "<span class='warning'>The [name] blinks red as you try to insert the cell!</span>")
to_chat(user, "<span class='warning'>The [src] blinks red as you try to insert the cell!</span>")
return
if(!user.drop_item())
if(!user.transferItemToLoc(W,src))
return
W.loc = src
charging = W
user.visible_message("[user] inserts a cell into the charger.", "<span class='notice'>You insert a cell into the charger.</span>")
user.visible_message("[user] inserts a cell into [src].", "<span class='notice'>You insert a cell into [src].</span>")
chargelevel = -1
updateicon()
else if(istype(W, /obj/item/wrench))
@@ -61,7 +60,7 @@
return
anchored = !anchored
to_chat(user, "<span class='notice'>You [anchored ? "attach" : "detach"] the cell charger [anchored ? "to" : "from"] the ground</span>")
to_chat(user, "<span class='notice'>You [anchored ? "attach" : "detach"] [src] [anchored ? "to" : "from"] the ground</span>")
playsound(src.loc, W.usesound, 75, 1)
else
return ..()
@@ -80,7 +79,7 @@
user.put_in_hands(charging)
charging.add_fingerprint(user)
user.visible_message("[user] removes the cell from the charger.", "<span class='notice'>You remove the cell from the charger.</span>")
user.visible_message("[user] removes [charging] from [src].", "<span class='notice'>You remove [charging] from [src].</span>")
removecell()
+3 -3
View File
@@ -231,9 +231,9 @@
else if(mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Unconscious(80)
var/dmg_mult = CONFIG_GET(number/damage_multiplier)
//Slowly get that clone healed and finished.
mob_occupant.adjustCloneLoss(-((speed_coeff/2) * config.damage_multiplier))
mob_occupant.adjustCloneLoss(-((speed_coeff / 2) * dmg_mult))
var/progress = CLONE_INITIAL_DAMAGE - mob_occupant.getCloneLoss()
// To avoid the default cloner making incomplete clones
progress += (100 - MINIMUM_HEAL_LEVEL)
@@ -251,7 +251,7 @@
BP.attach_limb(mob_occupant)
//Premature clones may have brain damage.
mob_occupant.adjustBrainLoss(-((speed_coeff/2) * config.damage_multiplier))
mob_occupant.adjustBrainLoss(-((speed_coeff / 2) * dmg_mult))
check_brine()
+146 -146
View File
@@ -1,146 +1,146 @@
/obj/machinery/computer/aifixer
name = "\improper AI system integrity restorer"
desc = "Used with intelliCards containing nonfunctioning AIs to restore them to working order."
req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS)
var/mob/living/silicon/ai/occupier = null
var/active = 0
circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
/obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params)
if(occupier && istype(I, /obj/item/screwdriver))
if(stat & (NOPOWER|BROKEN))
to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge.</span>")
else
to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge and it emits a warning beep.</span>")
else
return ..()
/obj/machinery/computer/aifixer/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/aifixer/interact(mob/user)
var/dat = ""
if (src.occupier)
var/laws
dat += "<h3>Stored AI: [src.occupier.name]</h3>"
dat += "<b>System integrity:</b> [(src.occupier.health+100)/2]%<br>"
if (src.occupier.laws.zeroth)
laws += "<b>0:</b> [src.occupier.laws.zeroth]<BR>"
for (var/index = 1, index <= src.occupier.laws.ion.len, index++)
var/law = src.occupier.laws.ion[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
var/number = 1
for (var/index = 1, index <= src.occupier.laws.inherent.len, index++)
var/law = src.occupier.laws.inherent[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
for (var/index = 1, index <= src.occupier.laws.supplied.len, index++)
var/law = src.occupier.laws.supplied[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
dat += "<b>Laws:</b><br>[laws]<br>"
if (src.occupier.stat == DEAD)
dat += "<span class='bad'>AI non-functional</span>"
else
dat += "<span class='good'>AI functional</span>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=\ref[src];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {"<br><A href='?src=\ref[user];mach_close=computer'>Close</A>"}
var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
occupier.adjustOxyLoss(-1, 0)
occupier.adjustFireLoss(-1, 0)
occupier.adjustToxLoss(-1, 0)
occupier.adjustBruteLoss(-1, 0)
occupier.updatehealth()
occupier.updatehealth()
if(occupier.health >= 0 && occupier.stat == DEAD)
occupier.revive()
return occupier.health < 100
/obj/machinery/computer/aifixer/process()
if(..())
if(active)
active = Fix()
updateDialog()
update_icon()
/obj/machinery/computer/aifixer/Topic(href, href_list)
if(..())
return
if(href_list["fix"])
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
active = TRUE
add_fingerprint(usr)
/obj/machinery/computer/aifixer/update_icon()
..()
if(stat & (NOPOWER|BROKEN))
return
else
if(active)
add_overlay("ai-fixer-on")
if (occupier)
switch (occupier.stat)
if (0)
add_overlay("ai-fixer-full")
if (2)
add_overlay("ai-fixer-404")
else
add_overlay("ai-fixer-empty")
/obj/machinery/computer/aifixer/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(!..())
return
//Downloading AI from card to terminal.
if(interaction == AI_TRANS_FROM_CARD)
if(stat & (NOPOWER|BROKEN))
to_chat(user, "[src] is offline and cannot take an AI at this time!")
return
AI.forceMove(src)
occupier = AI
AI.control_disabled = 1
AI.radio_enabled = 0
to_chat(AI, "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here.")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.")
card.AI = null
update_icon()
else //Uploading AI from terminal to card
if(occupier && !active)
to_chat(occupier, "You have been downloaded to a mobile storage device. Still no remote access.")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [occupier.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.")
occupier.loc = card
card.AI = occupier
occupier = null
update_icon()
else if (active)
to_chat(user, "<span class='boldannounce'>ERROR</span>: Reconstruction in progress.")
else if (!occupier)
to_chat(user, "<span class='boldannounce'>ERROR</span>: Unable to locate artificial intelligence.")
/obj/machinery/computer/aifixer
name = "\improper AI system integrity restorer"
desc = "Used with intelliCards containing nonfunctioning AIs to restore them to working order."
req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS)
var/mob/living/silicon/ai/occupier = null
var/active = 0
circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
/obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params)
if(occupier && istype(I, /obj/item/screwdriver))
if(stat & (NOPOWER|BROKEN))
to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge.</span>")
else
to_chat(user, "<span class='warning'>The screws on [name]'s screen won't budge and it emits a warning beep.</span>")
else
return ..()
/obj/machinery/computer/aifixer/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/aifixer/interact(mob/user)
var/dat = ""
if (src.occupier)
var/laws
dat += "<h3>Stored AI: [src.occupier.name]</h3>"
dat += "<b>System integrity:</b> [(src.occupier.health+100)/2]%<br>"
if (src.occupier.laws.zeroth)
laws += "<b>0:</b> [src.occupier.laws.zeroth]<BR>"
for (var/index = 1, index <= src.occupier.laws.ion.len, index++)
var/law = src.occupier.laws.ion[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
var/number = 1
for (var/index = 1, index <= src.occupier.laws.inherent.len, index++)
var/law = src.occupier.laws.inherent[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
for (var/index = 1, index <= src.occupier.laws.supplied.len, index++)
var/law = src.occupier.laws.supplied[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
dat += "<b>Laws:</b><br>[laws]<br>"
if (src.occupier.stat == DEAD)
dat += "<span class='bad'>AI non-functional</span>"
else
dat += "<span class='good'>AI functional</span>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=\ref[src];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {"<br><A href='?src=\ref[user];mach_close=computer'>Close</A>"}
var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
occupier.adjustOxyLoss(-1, 0)
occupier.adjustFireLoss(-1, 0)
occupier.adjustToxLoss(-1, 0)
occupier.adjustBruteLoss(-1, 0)
occupier.updatehealth()
occupier.updatehealth()
if(occupier.health >= 0 && occupier.stat == DEAD)
occupier.revive()
return occupier.health < 100
/obj/machinery/computer/aifixer/process()
if(..())
if(active)
active = Fix()
updateDialog()
update_icon()
/obj/machinery/computer/aifixer/Topic(href, href_list)
if(..())
return
if(href_list["fix"])
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
active = TRUE
add_fingerprint(usr)
/obj/machinery/computer/aifixer/update_icon()
..()
if(stat & (NOPOWER|BROKEN))
return
else
if(active)
add_overlay("ai-fixer-on")
if (occupier)
switch (occupier.stat)
if (0)
add_overlay("ai-fixer-full")
if (2)
add_overlay("ai-fixer-404")
else
add_overlay("ai-fixer-empty")
/obj/machinery/computer/aifixer/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(!..())
return
//Downloading AI from card to terminal.
if(interaction == AI_TRANS_FROM_CARD)
if(stat & (NOPOWER|BROKEN))
to_chat(user, "[src] is offline and cannot take an AI at this time!")
return
AI.forceMove(src)
occupier = AI
AI.control_disabled = 1
AI.radio_enabled = 0
to_chat(AI, "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here.")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [AI.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed.")
card.AI = null
update_icon()
else //Uploading AI from terminal to card
if(occupier && !active)
to_chat(occupier, "You have been downloaded to a mobile storage device. Still no remote access.")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [occupier.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.")
occupier.forceMove(card)
card.AI = occupier
occupier = null
update_icon()
else if (active)
to_chat(user, "<span class='boldannounce'>ERROR</span>: Reconstruction in progress.")
else if (!occupier)
to_chat(user, "<span class='boldannounce'>ERROR</span>: Unable to locate artificial intelligence.")
@@ -19,7 +19,7 @@
var/obj/item/weldingtool/WT = P
if(!WT.remove_fuel(0, user))
if(!WT.isOn())
to_chat(user, "<span class='warning'>The welding tool must be on to complete this task!</span>")
to_chat(user, "<span class='warning'>[WT] must be on to complete this task!</span>")
return
playsound(src.loc, P.usesound, 50, 1)
to_chat(user, "<span class='notice'>You start deconstructing the frame...</span>")
@@ -40,14 +40,13 @@
state = 0
return
if(istype(P, /obj/item/circuitboard/computer) && !circuit)
if(!user.drop_item())
if(!user.transferItemToLoc(P, null))
return
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
to_chat(user, "<span class='notice'>You place the circuit board inside the frame.</span>")
to_chat(user, "<span class='notice'>You place [P] inside the frame.</span>")
icon_state = "1"
circuit = P
circuit.add_fingerprint(user)
P.loc = null
return
else if(istype(P, /obj/item/circuitboard) && !circuit)
@@ -55,16 +54,16 @@
return
if(istype(P, /obj/item/screwdriver) && circuit)
playsound(src.loc, P.usesound, 50, 1)
to_chat(user, "<span class='notice'>You screw the circuit board into place.</span>")
to_chat(user, "<span class='notice'>You screw [circuit] into place.</span>")
state = 2
icon_state = "2"
return
if(istype(P, /obj/item/crowbar) && circuit)
playsound(src.loc, P.usesound, 50, 1)
to_chat(user, "<span class='notice'>You remove the circuit board.</span>")
to_chat(user, "<span class='notice'>You remove [circuit].</span>")
state = 1
icon_state = "0"
circuit.loc = src.loc
circuit.forceMove(drop_location())
circuit.add_fingerprint(user)
circuit = null
return
+10 -15
View File
@@ -47,29 +47,26 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
/obj/machinery/computer/card/Initialize()
. = ..()
change_position_cooldown = config.id_console_jobslot_delay
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
/obj/machinery/computer/card/attackby(obj/O, mob/user, params)//TODO:SANITY
if(istype(O, /obj/item/card/id))
var/obj/item/card/id/idcard = O
if(check_access(idcard))
if(!scan)
if(!usr.drop_item())
if (!user.transferItemToLoc(idcard,src))
return
idcard.loc = src
scan = idcard
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
else if(!modify)
if(!usr.drop_item())
if (!user.transferItemToLoc(idcard,src))
return
idcard.loc = src
modify = idcard
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
else
if(!modify)
if(!usr.drop_item())
if (!user.transferItemToLoc(idcard,src))
return
idcard.loc = src
modify = idcard
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
else
@@ -95,10 +92,10 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
/obj/machinery/computer/card/on_deconstruction()
if(scan)
scan.forceMove(loc)
scan.forceMove(drop_location())
scan = null
if(modify)
modify.forceMove(loc)
modify.forceMove(drop_location())
modify = null
//Check if you can't open a new position for a certain job
@@ -355,7 +352,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
if (modify)
GLOB.data_core.manifest_modify(modify.registered_name, modify.assignment)
modify.update_label()
modify.loc = loc
modify.forceMove(drop_location())
modify.verb_pickup()
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
modify = null
@@ -364,26 +361,24 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.drop_item())
if (!usr.transferItemToLoc(I,src))
return
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
I.loc = src
modify = I
authenticated = 0
if ("scan")
if (scan)
scan.loc = src.loc
scan.forceMove(drop_location())
scan.verb_pickup()
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
scan = null
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.drop_item())
if (!usr.transferItemToLoc(I,src))
return
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
I.loc = src
scan = I
authenticated = 0
if ("auth")
+496 -497
View File
@@ -1,502 +1,501 @@
/obj/machinery/computer/cloning
name = "cloning console"
desc = "Used to clone people and manage DNA."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning
/obj/machinery/computer/cloning
name = "cloning console"
desc = "Used to clone people and manage DNA."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp = "Ready to Scan"
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/cloning/Initialize()
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp = "Ready to Scan"
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/cloning/Initialize()
. = ..()
updatemodules(TRUE)
/obj/machinery/computer/cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
if(scanner.occupant && scanner.scan_level > 2)
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
if(!pod)
return
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
src.scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(dir in list(NORTH,EAST,SOUTH,WEST))
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
for(dir in list(NORTH,EAST,SOUTH,WEST))
podf = locate(/obj/machinery/clonepod, get_step(src, dir))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/cloning/proc/DetachCloner(obj/machinery/clonepod/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
if(!user.drop_item())
return
W.loc = src
src.diskette = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
updatemodules(TRUE)
/obj/machinery/computer/cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
return
if(scanner.occupant && scanner.scan_level > 2)
scan_occupant(scanner.occupant)
for(var/datum/data/record/R in records)
var/obj/machinery/clonepod/pod = GetAvailableEfficientPod(R.fields["mind"])
if(!pod)
return
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
records -= R
/obj/machinery/computer/cloning/proc/updatemodules(findfirstcloner)
src.scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(dir in list(NORTH,EAST,SOUTH,WEST))
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
for(dir in list(NORTH,EAST,SOUTH,WEST))
podf = locate(/obj/machinery/clonepod, get_step(src, dir))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/cloning/proc/DetachCloner(obj/machinery/clonepod/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
if (!user.transferItemToLoc(W,src))
return
src.diskette = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
else if(istype(W, /obj/item/device/multitool))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=\ref[src];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level > 2)
if(!autoprocess)
dat += "<a href='byond://?src=\ref[src];task=autoprocess'>Autoprocess</a>"
else
dat += "<a href='byond://?src=\ref[src];task=stopautoprocess'>Stop autoprocess</a>"
else
dat += "<span class='linkOff'>Autoprocess</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
switch(src.menu)
if(1)
// Modules
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=\ref[src];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=\ref[src];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=\ref[src];disk=eject'>Eject Disk</a><br>"
if(2)
dat += "<h3>Current records</h3>"
dat += "<a href='byond://?src=\ref[src];menu=1'><< Back</a><br><br>"
for(var/datum/data/record/R in records)
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=\ref[src];view_rec=[R.fields["id"]]'>View Record</a>"
if(3)
dat += "<h3>Selected Record</h3>"
dat += "<a href='byond://?src=\ref[src];menu=2'><< Back</a><br>"
if (!src.active_record)
dat += "<font class='bad'>Record not found.</font>"
else
dat += "<h4>[src.active_record.fields["name"]]</h4>"
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=\ref[src];clone=[active_record.fields["id"]]'>Clone</a><br>"
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
else
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
if(diskette && diskette.fields)
dat += "<div class='block'>"
dat += "<h4>Inserted Disk</h4>"
dat += "<b>Contents:</b> "
var/list/L = list()
if(diskette.fields["UI"])
L += "Unique Identifier"
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
dat += "<br /><a href='byond://?src=\ref[src];disk=load'>Load from Disk</a>"
dat += "<br /><a href='byond://?src=\ref[src];disk=save'>Save to Disk</a>"
dat += "</div>"
dat += "<font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font>"
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h3>Confirm Record Deletion</h3>"
dat += "<b><a href='byond://?src=\ref[src];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=\ref[src];menu=3'>Cancel</a></b>"
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
autoprocess = 1
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("stopautoprocess")
autoprocess = 0
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=\ref[src];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level > 2)
if(!autoprocess)
dat += "<a href='byond://?src=\ref[src];task=autoprocess'>Autoprocess</a>"
else
dat += "<a href='byond://?src=\ref[src];task=stopautoprocess'>Stop autoprocess</a>"
else
dat += "<span class='linkOff'>Autoprocess</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
switch(src.menu)
if(1)
// Modules
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=\ref[src];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=\ref[src];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=\ref[src];disk=eject'>Eject Disk</a><br>"
if(2)
dat += "<h3>Current records</h3>"
dat += "<a href='byond://?src=\ref[src];menu=1'><< Back</a><br><br>"
for(var/datum/data/record/R in records)
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=\ref[src];view_rec=[R.fields["id"]]'>View Record</a>"
if(3)
dat += "<h3>Selected Record</h3>"
dat += "<a href='byond://?src=\ref[src];menu=2'><< Back</a><br>"
if (!src.active_record)
dat += "<font class='bad'>Record not found.</font>"
else
dat += "<h4>[src.active_record.fields["name"]]</h4>"
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=\ref[src];clone=[active_record.fields["id"]]'>Clone</a><br>"
var/obj/item/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
else
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
if(diskette && diskette.fields)
dat += "<div class='block'>"
dat += "<h4>Inserted Disk</h4>"
dat += "<b>Contents:</b> "
var/list/L = list()
if(diskette.fields["UI"])
L += "Unique Identifier"
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
dat += "<br /><a href='byond://?src=\ref[src];disk=load'>Load from Disk</a>"
dat += "<br /><a href='byond://?src=\ref[src];disk=save'>Save to Disk</a>"
dat += "</div>"
dat += "<font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font>"
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h3>Confirm Record Deletion</h3>"
dat += "<b><a href='byond://?src=\ref[src];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=\ref[src];menu=3'>Cancel</a></b>"
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
autoprocess = 1
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("stopautoprocess")
autoprocess = 0
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
if(!active_record.fields["ckey"])
records -= active_record
active_record = null
src.temp = "<font class='bad'>Record Corrupt</font>"
else
src.menu = 3
else
src.temp = "Record missing."
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/device/pda))
if(src.check_access(C))
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
src.temp = "<font class='bad'>Load error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (!src.active_record)
src.temp = "<font class='bad'>Record error.</font>"
src.menu = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/key in diskette.fields)
src.active_record.fields[key] = diskette.fields[key]
src.temp = "Load successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("eject")
if(src.diskette)
src.diskette.loc = src.loc
src.diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
if("save")
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
src.temp = "<font class='bad'>Save error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = active_record.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!config.revival_cloning)
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
if(active_record == C)
active_record = null
menu = 1
else
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(iscarbon(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
// species (abductors, slimepeople) store state in their
// species datums
R.fields["mrace"] = dna.species
else
var/datum/species/rando_race = pick(config.roundstart_races)
R.fields["mrace"] = rando_race.type
R.fields["ckey"] = mob_occupant.ckey
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
R.fields["UE"] = dna.unique_enzymes
R.fields["UI"] = dna.uni_identity
R.fields["SE"] = dna.struc_enzymes
R.fields["blood_type"] = dna.blood_type
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "\ref[mob_occupant.mind]"
//Add an implant if needed
var/obj/item/implant/health/imp
for(var/obj/item/implant/health/HI in mob_occupant.implants)
imp = HI
break
if(!imp)
imp = new /obj/item/implant/health(mob_occupant)
imp.implant(mob_occupant)
R.fields["imp"] = "\ref[imp]"
src.records += R
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
if(!active_record.fields["ckey"])
records -= active_record
active_record = null
src.temp = "<font class='bad'>Record Corrupt</font>"
else
src.menu = 3
else
src.temp = "Record missing."
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/device/pda))
if(src.check_access(C))
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
src.temp = "<font class='bad'>Load error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (!src.active_record)
src.temp = "<font class='bad'>Record error.</font>"
src.menu = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/key in diskette.fields)
src.active_record.fields[key] = diskette.fields[key]
src.temp = "Load successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("eject")
if(src.diskette)
src.diskette.forceMove(drop_location())
src.diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
if("save")
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
src.temp = "<font class='bad'>Save error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = active_record.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!CONFIG_GET(flag/revival_cloning))
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
if(active_record == C)
active_record = null
menu = 1
else
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(iscarbon(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
// species (abductors, slimepeople) store state in their
// species datums
R.fields["mrace"] = dna.species
else
var/datum/species/rando_race = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
R.fields["mrace"] = rando_race.type
R.fields["ckey"] = mob_occupant.ckey
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext(md5(mob_occupant.real_name), 2, 6)
R.fields["UE"] = dna.unique_enzymes
R.fields["UI"] = dna.uni_identity
R.fields["SE"] = dna.struc_enzymes
R.fields["blood_type"] = dna.blood_type
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "\ref[mob_occupant.mind]"
//Add an implant if needed
var/obj/item/implant/health/imp
for(var/obj/item/implant/health/HI in mob_occupant.implants)
imp = HI
break
if(!imp)
imp = new /obj/item/implant/health(mob_occupant)
imp.implant(mob_occupant)
R.fields["imp"] = "\ref[imp]"
src.records += R
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
@@ -454,7 +454,7 @@
if (src.authenticated==2)
dat += "<BR><BR><B>Captain Functions</B>"
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=announce'>Make a Captain's Announcement</A> \]"
if(config.cross_allowed)
if(CONFIG_GET(string/cross_server_address))
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=crossserver'>Send a message to an allied station</A> \]"
if(SSmapping.config.allow_custom_shuttles == "yes")
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=purchase_menu'>Purchase Shuttle</A> \]"
+2 -3
View File
@@ -43,9 +43,8 @@
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
if (istype(I, /obj/item/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
if(!user.drop_item())
if (!user.transferItemToLoc(I,src))
return
I.loc = src
src.diskette = I
to_chat(user, "<span class='notice'>You insert [I].</span>")
src.updateUsrDialog()
@@ -448,7 +447,7 @@
diskette.fields = buffer_slot.Copy()
if("ejectdisk")
if(diskette)
diskette.loc = get_turf(src)
diskette.forceMove(drop_location())
diskette = null
if("setdelayed")
if(num)
@@ -27,9 +27,8 @@
/obj/machinery/computer/gulag_teleporter_computer/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/card/id/prisoner))
if(!id)
if(!user.drop_item())
if (!user.transferItemToLoc(W,src))
return
W.forceMove(src)
id = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
return
+2 -2
View File
@@ -124,7 +124,7 @@
dat += "<tr><td>ID:</td><td>[active1.fields["id"]]</td></tr>"
dat += "<tr><td>Sex:</td><td><A href='?src=\ref[src];field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Age:</td><td><A href='?src=\ref[src];field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
dat += "<tr><td>Species:</td><td><A href='?src=\ref[src];field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Fingerprint:</td><td><A href='?src=\ref[src];field=fingerprint'>&nbsp;[active1.fields["fingerprint"]]&nbsp;</A></td></tr>"
dat += "<tr><td>Physical Status:</td><td><A href='?src=\ref[src];field=p_stat'>&nbsp;[active1.fields["p_stat"]]&nbsp;</A></td></tr>"
@@ -543,7 +543,7 @@
P.info = "<CENTER><B>Medical Record - (MR-[GLOB.data_core.medicalPrintCount])</B></CENTER><BR>"
if(active1 in GLOB.data_core.general)
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"])
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"])
else
+5 -5
View File
@@ -186,7 +186,7 @@
<tr><td>ID:</td><td><A href='?src=\ref[src];choice=Edit Field;field=id'>&nbsp;[active1.fields["id"]]&nbsp;</A></td></tr>
<tr><td>Sex:</td><td><A href='?src=\ref[src];choice=Edit Field;field=sex'>&nbsp;[active1.fields["sex"]]&nbsp;</A></td></tr>
<tr><td>Age:</td><td><A href='?src=\ref[src];choice=Edit Field;field=age'>&nbsp;[active1.fields["age"]]&nbsp;</A></td></tr>"}
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
dat += "<tr><td>Species:</td><td><A href ='?src=\ref[src];choice=Edit Field;field=species'>&nbsp;[active1.fields["species"]]&nbsp;</A></td></tr>"
dat += {"<tr><td>Rank:</td><td><A href='?src=\ref[src];choice=Edit Field;field=rank'>&nbsp;[active1.fields["rank"]]&nbsp;</A></td></tr>
<tr><td>Fingerprint:</td><td><A href='?src=\ref[src];choice=Edit Field;field=fingerprint'>&nbsp;[active1.fields["fingerprint"]]&nbsp;</A></td></tr>
@@ -373,7 +373,7 @@ What a mess.*/
P.info = "<CENTER><B>Security Record - (SR-[GLOB.data_core.securityPrintCount])</B></CENTER><BR>"
if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))
P.info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"])
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
P.info += "\nSpecies: [active1.fields["species"]]<BR>"
P.info += text("\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"])
else
@@ -519,7 +519,7 @@ What a mess.*/
G.fields["rank"] = "Unassigned"
G.fields["sex"] = "Male"
G.fields["age"] = "Unknown"
if(config.mutant_races)
if(CONFIG_GET(flag/join_with_mutant_race))
G.fields["species"] = "Human"
G.fields["photo_front"] = new /icon()
G.fields["photo_side"] = new /icon()
@@ -604,7 +604,7 @@ What a mess.*/
active1.fields["age"] = t1
if("species")
if(istype(active1, /datum/data/record))
var/t1 = input("Select a species", "Species Selection") as null|anything in GLOB.roundstart_species
var/t1 = input("Select a species", "Species Selection") as null|anything in CONFIG_GET(keyed_flag_list/roundstart_races)
if(!canUseSecurityRecordsConsole(usr, t1, a1))
return
active1.fields["species"] = t1
@@ -772,7 +772,7 @@ What a mess.*/
if(6)
R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable")
if(7)
R.fields["species"] = pick(GLOB.roundstart_species)
R.fields["species"] = pick(CONFIG_GET(keyed_flag_list/roundstart_races))
if(8)
var/datum/data/record/G = pick(GLOB.data_core.general)
R.fields["photo_front"] = G.fields["photo_front"]
@@ -196,6 +196,7 @@
equip_cooldown = 10
energy_drain = 250
range = MELEE|RANGED
flags_2 = NO_MAT_REDEMPTION_2
var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock.
/obj/item/mecha_parts/mecha_equipment/rcd/New()
+1 -1
View File
@@ -54,7 +54,7 @@ AI MODULES
for(var/mylaw in lawlist)
if(mylaw != "")
tot_laws++
if(tot_laws > config.silicon_max_law_amount && !bypass_law_amt_check)//allows certain boards to avoid this check, eg: reset
if(tot_laws > CONFIG_GET(number/silicon_max_law_amount) && !bypass_law_amt_check)//allows certain boards to avoid this check, eg: reset
to_chat(user, "<span class='caution'>Not enough memory allocated to [law_datum.owner ? law_datum.owner : "the AI core"]'s law processor to handle this amount of laws.</span>")
message_admins("[key_name_admin(user)] tried to upload laws to [law_datum.owner ? key_name_admin(law_datum.owner) : "an AI core"] that would exceed the law cap.")
overflow = TRUE
+1
View File
@@ -123,6 +123,7 @@ obj/item/construction
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
max_matter = 160
flags_2 = NO_MAT_REDEMPTION_2
var/mode = 1
var/canRturf = 0
var/ranged = FALSE
+71 -70
View File
@@ -1,70 +1,71 @@
/obj/item/bodybag
name = "body bag"
desc = "A folded bag designed for the storage and transportation of cadavers."
icon = 'icons/obj/bodybag.dmi'
icon_state = "bodybag_folded"
var/unfoldedbag_path = /obj/structure/closet/body_bag
w_class = WEIGHT_CLASS_SMALL
/obj/item/bodybag/attack_self(mob/user)
deploy_bodybag(user, user.loc)
/obj/item/bodybag/afterattack(atom/target, mob/user, proximity)
if(proximity)
if(isopenturf(target))
deploy_bodybag(user, target)
/obj/item/bodybag/proc/deploy_bodybag(mob/user, atom/location)
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
R.open(user)
R.add_fingerprint(user)
qdel(src)
// Bluespace bodybag
/obj/item/bodybag/bluespace
name = "bluespace body bag"
desc = "A folded bluespace body bag designed for the storage and transportation of cadavers."
icon = 'icons/obj/bodybag.dmi'
icon_state = "bluebodybag_folded"
unfoldedbag_path = /obj/structure/closet/body_bag/bluespace
w_class = WEIGHT_CLASS_SMALL
origin_tech = "bluespace=4;materials=4;plasmatech=4"
/obj/item/bodybag/bluespace/examine(mob/user)
..()
if(contents.len)
to_chat(user, "<span class='notice'>You can make out the shapes of [contents.len] objects through the fabric.</span>")
/obj/item/bodybag/bluespace/Destroy()
for(var/atom/movable/A in contents)
A.forceMove(get_turf(src))
if(isliving(A))
to_chat(A, "<span class='notice'>You suddenly feel the space around you torn apart! You're free!</span>")
return ..()
/obj/item/bodybag/bluespace/deploy_bodybag(mob/user, atom/location)
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
for(var/atom/movable/A in contents)
A.forceMove(R)
if(isliving(A))
to_chat(A, "<span class='notice'>You suddenly feel air around you! You're free!</span>")
R.open(user)
R.add_fingerprint(user)
qdel(src)
/obj/item/bodybag/bluespace/container_resist(mob/living/user)
if(user.incapacitated())
to_chat(user, "<span class='warning'>You can't get out while you're restrained like this!</span>")
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
to_chat(user, "<span class='notice'>You claw at the fabric of [src], trying to tear it open...</span>")
to_chat(loc, "<span class='warning'>Someone starts trying to break free of [src]!</span>")
if(!do_after(user, 200, target = src))
to_chat(loc, "<span class='warning'>The pressure subsides. It seems that they've stopped resisting...</span>")
return
loc.visible_message("<span class='warning'>[user] suddenly appears in front of [loc]!</span>", "<span class='userdanger'>[user] breaks free of [src]!</span>")
qdel(src)
/obj/item/bodybag
name = "body bag"
desc = "A folded bag designed for the storage and transportation of cadavers."
icon = 'icons/obj/bodybag.dmi'
icon_state = "bodybag_folded"
var/unfoldedbag_path = /obj/structure/closet/body_bag
w_class = WEIGHT_CLASS_SMALL
/obj/item/bodybag/attack_self(mob/user)
deploy_bodybag(user, user.loc)
/obj/item/bodybag/afterattack(atom/target, mob/user, proximity)
if(proximity)
if(isopenturf(target))
deploy_bodybag(user, target)
/obj/item/bodybag/proc/deploy_bodybag(mob/user, atom/location)
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
R.open(user)
R.add_fingerprint(user)
qdel(src)
// Bluespace bodybag
/obj/item/bodybag/bluespace
name = "bluespace body bag"
desc = "A folded bluespace body bag designed for the storage and transportation of cadavers."
icon = 'icons/obj/bodybag.dmi'
icon_state = "bluebodybag_folded"
unfoldedbag_path = /obj/structure/closet/body_bag/bluespace
w_class = WEIGHT_CLASS_SMALL
flags_2 = NO_MAT_REDEMPTION_2
origin_tech = "bluespace=4;materials=4;plasmatech=4"
/obj/item/bodybag/bluespace/examine(mob/user)
..()
if(contents.len)
to_chat(user, "<span class='notice'>You can make out the shapes of [contents.len] objects through the fabric.</span>")
/obj/item/bodybag/bluespace/Destroy()
for(var/atom/movable/A in contents)
A.forceMove(get_turf(src))
if(isliving(A))
to_chat(A, "<span class='notice'>You suddenly feel the space around you torn apart! You're free!</span>")
return ..()
/obj/item/bodybag/bluespace/deploy_bodybag(mob/user, atom/location)
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
for(var/atom/movable/A in contents)
A.forceMove(R)
if(isliving(A))
to_chat(A, "<span class='notice'>You suddenly feel air around you! You're free!</span>")
R.open(user)
R.add_fingerprint(user)
qdel(src)
/obj/item/bodybag/bluespace/container_resist(mob/living/user)
if(user.incapacitated())
to_chat(user, "<span class='warning'>You can't get out while you're restrained like this!</span>")
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
to_chat(user, "<span class='notice'>You claw at the fabric of [src], trying to tear it open...</span>")
to_chat(loc, "<span class='warning'>Someone starts trying to break free of [src]!</span>")
if(!do_after(user, 200, target = src))
to_chat(loc, "<span class='warning'>The pressure subsides. It seems that they've stopped resisting...</span>")
return
loc.visible_message("<span class='warning'>[user] suddenly appears in front of [loc]!</span>", "<span class='userdanger'>[user] breaks free of [src]!</span>")
qdel(src)
+5 -6
View File
@@ -72,16 +72,15 @@
user.visible_message("<span class='suicide'>[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!</span>")
return (BRUTELOSS|OXYLOSS)
/obj/item/toy/crayon/New()
..()
/obj/item/toy/crayon/Initialize()
. = ..()
// Makes crayons identifiable in things like grinders
if(name == "crayon")
name = "[item_color] crayon"
if(config)
if(config.mutant_races == 1)
graffiti |= "antilizard"
graffiti |= "prolizard"
if(CONFIG_GET(flag/join_with_mutant_race))
graffiti |= "antilizard"
graffiti |= "prolizard"
all_drawables = graffiti + letters + numerals + oriented + runes + graffiti_large_h
drawtype = pick(all_drawables)
+3 -2
View File
@@ -882,7 +882,8 @@
..()
/obj/item/book/manual/wiki/proc/initialize_wikibook()
if(config.wikiurl)
var/wikiurl = CONFIG_GET(string/wikiurl)
if(wikiurl)
dat = {"
<html><head>
@@ -900,7 +901,7 @@
}
</script>
<p id='loading'>You start skimming through the manual...</p>
<iframe width='100%' height='97%' onload="pageloaded(this)" src="[config.wikiurl]/[page_link]?printable=yes&remove_links=1" frameborder="0" id="main_frame"></iframe>
<iframe width='100%' height='97%' onload="pageloaded(this)" src="[wikiurl]/[page_link]?printable=yes&remove_links=1" frameborder="0" id="main_frame"></iframe>
</body>
</html>
@@ -40,6 +40,7 @@
max_w_class = WEIGHT_CLASS_GIGANTIC
max_combined_w_class = 35
resistance_flags = FIRE_PROOF
flags_2 = NO_MAT_REDEMPTION_2
var/pshoom = 'sound/items/pshoom.ogg'
var/alt_sound = 'sound/items/pshoom_2.ogg'
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 60, acid = 50)
+382 -381
View File
@@ -1,381 +1,382 @@
/*
* These absorb the functionality of the plant bag, ore satchel, etc.
* They use the use_to_pickup, quick_gather, and quick_empty functions
* that were already defined in weapon/storage, but which had been
* re-implemented in other classes.
*
* Contains:
* Trash Bag
* Mining Satchel
* Plant Bag
* Sheet Snatcher
* Book Bag
* Biowaste Bag
*
* -Sayu
*/
// Generic non-item
/obj/item/storage/bag
allow_quick_gather = 1
allow_quick_empty = 1
display_contents_with_number = 1 // should work fine now
use_to_pickup = 1
slot_flags = SLOT_BELT
// -----------------------------
// Trash bag
// -----------------------------
/obj/item/storage/bag/trash
name = "trash bag"
desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
icon = 'icons/obj/janitor.dmi'
icon_state = "trashbag"
item_state = "trashbag"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
max_w_class = WEIGHT_CLASS_SMALL
max_combined_w_class = 30
storage_slots = 30
can_hold = list() // any
cant_hold = list(/obj/item/disk/nuclear)
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!</span>")
playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
return (TOXLOSS)
/obj/item/storage/bag/trash/update_icon()
if(contents.len == 0)
icon_state = "[initial(icon_state)]"
else if(contents.len < 12)
icon_state = "[initial(icon_state)]1"
else if(contents.len < 21)
icon_state = "[initial(icon_state)]2"
else icon_state = "[initial(icon_state)]3"
/obj/item/storage/bag/trash/cyborg
/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
J.put_in_cart(src, user)
J.mybag=src
J.update_icon()
/obj/item/storage/bag/trash/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
return
/obj/item/storage/bag/trash/bluespace
name = "trash bag of holding"
desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
icon_state = "bluetrashbag"
origin_tech = "materials=4;bluespace=4;engineering=4;plasmatech=3"
max_combined_w_class = 60
storage_slots = 60
// -----------------------------
// Mining Satchel
// -----------------------------
/obj/item/storage/bag/ore
name = "mining satchel"
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
origin_tech = "engineering=2"
slot_flags = SLOT_BELT | SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
storage_slots = 50
max_combined_w_class = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class
max_w_class = WEIGHT_CLASS_NORMAL
can_hold = list(/obj/item/ore)
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
/obj/item/storage/bag/ore/cyborg
name = "cyborg mining satchel"
/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
name = "mining satchel of holding"
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
storage_slots = INFINITY
max_combined_w_class = INFINITY
origin_tech = "bluespace=4;materials=3;engineering=3"
icon_state = "satchel_bspace"
// -----------------------------
// Plant bag
// -----------------------------
/obj/item/storage/bag/plants
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
storage_slots = 100; //the number of plant pieces it can carry.
max_combined_w_class = 100 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class
max_w_class = WEIGHT_CLASS_NORMAL
w_class = WEIGHT_CLASS_TINY
can_hold = list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)
resistance_flags = FLAMMABLE
////////
/obj/item/storage/bag/plants/portaseeder
name = "portable seed extractor"
desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
icon_state = "portaseeder"
origin_tech = "biotech=3;engineering=2"
/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
set name = "Activate Seed Extraction"
set category = "Object"
set desc = "Activate to convert your plants into plantable seeds."
if(usr.stat || !usr.canmove || usr.restrained())
return
for(var/obj/item/O in contents)
seedify(O, 1)
close_all()
// -----------------------------
// Sheet Snatcher
// -----------------------------
// Because it stacks stacks, this doesn't operate normally.
// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
desc = "A patented Nanotrasen storage system designed for any kind of mineral sheet."
icon = 'icons/obj/mining.dmi'
icon_state = "sheetsnatcher"
var/capacity = 300; //the number of sheets it can carry.
w_class = WEIGHT_CLASS_NORMAL
allow_quick_empty = 1 // this function is superceded
/obj/item/storage/bag/sheetsnatcher/can_be_inserted(obj/item/W, stop_messages = 0)
if(!istype(W, /obj/item/stack/sheet) || istype(W, /obj/item/stack/sheet/mineral/sandstone) || istype(W, /obj/item/stack/sheet/mineral/wood))
if(!stop_messages)
to_chat(usr, "The snatcher does not accept [W].")
return 0 //I don't care, but the existing code rejects them for not being "sheets" *shrug* -Sayu
var/current = 0
for(var/obj/item/stack/sheet/S in contents)
current += S.amount
if(capacity == current)//If it's full, you're done
if(!stop_messages)
to_chat(usr, "<span class='danger'>The snatcher is full.</span>")
return 0
return 1
// Modified handle_item_insertion. Would prefer not to, but...
/obj/item/storage/bag/sheetsnatcher/handle_item_insertion(obj/item/W, prevent_warning = 0)
var/obj/item/stack/sheet/S = W
if(!istype(S)) return 0
var/amount
var/inserted = 0
var/current = 0
for(var/obj/item/stack/sheet/S2 in contents)
current += S2.amount
if(capacity < current + S.amount)//If the stack will fill it up
amount = capacity - current
else
amount = S.amount
for(var/obj/item/stack/sheet/sheet in contents)
if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects
sheet.amount += amount // they should only be removed through procs in this file, which split them up.
S.amount -= amount
inserted = 1
break
if(!inserted || !S.amount)
usr.dropItemToGround(S)
if (usr.client && usr.s_active != src)
usr.client.screen -= S
S.dropped(usr)
if(!S.amount)
qdel(S)
else
if(S.pulledby)
S.pulledby.stop_pulling()
S.loc = src
orient2hud(usr)
if(usr.s_active)
usr.s_active.show_to(usr)
update_icon()
return 1
// Sets up numbered display to show the stack size of each stored mineral
// NOTE: numbered display is turned off currently because it's broken
/obj/item/storage/bag/sheetsnatcher/orient2hud(mob/user)
var/adjusted_contents = contents.len
//Numbered contents display
var/list/datum/numbered_display/numbered_contents
if(display_contents_with_number)
numbered_contents = list()
adjusted_contents = 0
for(var/obj/item/stack/sheet/I in contents)
adjusted_contents++
var/datum/numbered_display/D = new/datum/numbered_display(I)
D.number = I.amount
numbered_contents.Add( D )
var/row_num = 0
var/col_count = min(7,storage_slots) -1
if (adjusted_contents > 7)
row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width.
src.standard_orient_objs(row_num, col_count, numbered_contents)
return
// Modified quick_empty verb drops appropriate sized stacks
/obj/item/storage/bag/sheetsnatcher/quick_empty()
var/location = get_turf(src)
for(var/obj/item/stack/sheet/S in contents)
while(S.amount)
var/obj/item/stack/sheet/N = new S.type(location)
var/stacksize = min(S.amount,N.max_amount)
N.amount = stacksize
S.amount -= stacksize
if(!S.amount)
qdel(S)// todo: there's probably something missing here
orient2hud(usr)
if(usr.s_active)
usr.s_active.show_to(usr)
update_icon()
// Instead of removing
/obj/item/storage/bag/sheetsnatcher/remove_from_storage(obj/item/W, atom/new_location)
var/obj/item/stack/sheet/S = W
if(!istype(S)) return 0
//I would prefer to drop a new stack, but the item/attack_hand code
// that calls this can't recieve a different object than you clicked on.
//Therefore, make a new stack internally that has the remainder.
// -Sayu
if(S.amount > S.max_amount)
var/obj/item/stack/sheet/temp = new S.type(src)
temp.amount = S.amount - S.max_amount
S.amount = S.max_amount
return ..(S,new_location)
// -----------------------------
// Sheet Snatcher (Cyborg)
// -----------------------------
/obj/item/storage/bag/sheetsnatcher/borg
name = "sheet snatcher 9000"
desc = ""
capacity = 500//Borgs get more because >specialization
// -----------------------------
// Book bag
// -----------------------------
/obj/item/storage/bag/books
name = "book bag"
desc = "A bag for books."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
display_contents_with_number = 0 //This would look really stupid otherwise
storage_slots = 7
max_combined_w_class = 21
max_w_class = WEIGHT_CLASS_NORMAL
w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
can_hold = list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook)
resistance_flags = FLAMMABLE
/*
* Trays - Agouri
*/
/obj/item/storage/bag/tray
name = "tray"
icon = 'icons/obj/food/containers.dmi'
icon_state = "tray"
desc = "A metal tray to lay food on."
force = 5
throwforce = 10
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
materials = list(MAT_METAL=3000)
preposition = "on"
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
quick_empty()
// Make each item scatter a bit
for(var/obj/item/I in oldContents)
spawn()
for(var/i = 1, i <= rand(1,2), i++)
if(I)
step(I, pick(NORTH,SOUTH,EAST,WEST))
sleep(rand(2,4))
if(prob(50))
playsound(M, 'sound/items/trayhit1.ogg', 50, 1)
else
playsound(M, 'sound/items/trayhit2.ogg', 50, 1)
if(ishuman(M) || ismonkey(M))
if(prob(10))
M.Knockdown(40)
/obj/item/storage/bag/tray/proc/rebuild_overlays()
cut_overlays()
for(var/obj/item/I in contents)
add_overlay(mutable_appearance(I.icon, I.icon_state))
/obj/item/storage/bag/tray/remove_from_storage(obj/item/W as obj, atom/new_location)
..()
rebuild_overlays()
/obj/item/storage/bag/tray/handle_item_insertion(obj/item/I, prevent_warning = 0)
add_overlay(mutable_appearance(I.icon, I.icon_state))
. = ..()
/*
* Chemistry bag
*/
/obj/item/storage/bag/chemistry
name = "chemistry bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
desc = "A bag for storing pills, patches, and bottles."
storage_slots = 50
max_combined_w_class = 200
w_class = WEIGHT_CLASS_TINY
preposition = "in"
can_hold = list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)
resistance_flags = FLAMMABLE
/*
* Biowaste bag (mostly for xenobiologists)
*/
/obj/item/storage/bag/bio
name = "bio bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
storage_slots = 25
max_combined_w_class = 200
w_class = WEIGHT_CLASS_TINY
preposition = "in"
can_hold = list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)
resistance_flags = FLAMMABLE
/*
* These absorb the functionality of the plant bag, ore satchel, etc.
* They use the use_to_pickup, quick_gather, and quick_empty functions
* that were already defined in weapon/storage, but which had been
* re-implemented in other classes.
*
* Contains:
* Trash Bag
* Mining Satchel
* Plant Bag
* Sheet Snatcher
* Book Bag
* Biowaste Bag
*
* -Sayu
*/
// Generic non-item
/obj/item/storage/bag
allow_quick_gather = 1
allow_quick_empty = 1
display_contents_with_number = 1 // should work fine now
use_to_pickup = 1
slot_flags = SLOT_BELT
// -----------------------------
// Trash bag
// -----------------------------
/obj/item/storage/bag/trash
name = "trash bag"
desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
icon = 'icons/obj/janitor.dmi'
icon_state = "trashbag"
item_state = "trashbag"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
max_w_class = WEIGHT_CLASS_SMALL
max_combined_w_class = 30
storage_slots = 30
can_hold = list() // any
cant_hold = list(/obj/item/disk/nuclear)
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!</span>")
playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
return (TOXLOSS)
/obj/item/storage/bag/trash/update_icon()
if(contents.len == 0)
icon_state = "[initial(icon_state)]"
else if(contents.len < 12)
icon_state = "[initial(icon_state)]1"
else if(contents.len < 21)
icon_state = "[initial(icon_state)]2"
else icon_state = "[initial(icon_state)]3"
/obj/item/storage/bag/trash/cyborg
/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
J.put_in_cart(src, user)
J.mybag=src
J.update_icon()
/obj/item/storage/bag/trash/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
return
/obj/item/storage/bag/trash/bluespace
name = "trash bag of holding"
desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
icon_state = "bluetrashbag"
origin_tech = "materials=4;bluespace=4;engineering=4;plasmatech=3"
max_combined_w_class = 60
storage_slots = 60
flags_2 = NO_MAT_REDEMPTION_2
// -----------------------------
// Mining Satchel
// -----------------------------
/obj/item/storage/bag/ore
name = "mining satchel"
desc = "This little bugger can be used to store and transport ores."
icon = 'icons/obj/mining.dmi'
icon_state = "satchel"
origin_tech = "engineering=2"
slot_flags = SLOT_BELT | SLOT_POCKET
w_class = WEIGHT_CLASS_NORMAL
storage_slots = 50
max_combined_w_class = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class
max_w_class = WEIGHT_CLASS_NORMAL
can_hold = list(/obj/item/ore)
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
/obj/item/storage/bag/ore/cyborg
name = "cyborg mining satchel"
/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
name = "mining satchel of holding"
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
storage_slots = INFINITY
max_combined_w_class = INFINITY
origin_tech = "bluespace=4;materials=3;engineering=3"
icon_state = "satchel_bspace"
// -----------------------------
// Plant bag
// -----------------------------
/obj/item/storage/bag/plants
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
storage_slots = 100; //the number of plant pieces it can carry.
max_combined_w_class = 100 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class
max_w_class = WEIGHT_CLASS_NORMAL
w_class = WEIGHT_CLASS_TINY
can_hold = list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)
resistance_flags = FLAMMABLE
////////
/obj/item/storage/bag/plants/portaseeder
name = "portable seed extractor"
desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
icon_state = "portaseeder"
origin_tech = "biotech=3;engineering=2"
/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
set name = "Activate Seed Extraction"
set category = "Object"
set desc = "Activate to convert your plants into plantable seeds."
if(usr.stat || !usr.canmove || usr.restrained())
return
for(var/obj/item/O in contents)
seedify(O, 1)
close_all()
// -----------------------------
// Sheet Snatcher
// -----------------------------
// Because it stacks stacks, this doesn't operate normally.
// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
desc = "A patented Nanotrasen storage system designed for any kind of mineral sheet."
icon = 'icons/obj/mining.dmi'
icon_state = "sheetsnatcher"
var/capacity = 300; //the number of sheets it can carry.
w_class = WEIGHT_CLASS_NORMAL
allow_quick_empty = 1 // this function is superceded
/obj/item/storage/bag/sheetsnatcher/can_be_inserted(obj/item/W, stop_messages = 0)
if(!istype(W, /obj/item/stack/sheet) || istype(W, /obj/item/stack/sheet/mineral/sandstone) || istype(W, /obj/item/stack/sheet/mineral/wood))
if(!stop_messages)
to_chat(usr, "The snatcher does not accept [W].")
return 0 //I don't care, but the existing code rejects them for not being "sheets" *shrug* -Sayu
var/current = 0
for(var/obj/item/stack/sheet/S in contents)
current += S.amount
if(capacity == current)//If it's full, you're done
if(!stop_messages)
to_chat(usr, "<span class='danger'>The snatcher is full.</span>")
return 0
return 1
// Modified handle_item_insertion. Would prefer not to, but...
/obj/item/storage/bag/sheetsnatcher/handle_item_insertion(obj/item/W, prevent_warning = 0)
var/obj/item/stack/sheet/S = W
if(!istype(S)) return 0
var/amount
var/inserted = 0
var/current = 0
for(var/obj/item/stack/sheet/S2 in contents)
current += S2.amount
if(capacity < current + S.amount)//If the stack will fill it up
amount = capacity - current
else
amount = S.amount
for(var/obj/item/stack/sheet/sheet in contents)
if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects
sheet.amount += amount // they should only be removed through procs in this file, which split them up.
S.amount -= amount
inserted = 1
break
if(!inserted || !S.amount)
usr.dropItemToGround(S)
if (usr.client && usr.s_active != src)
usr.client.screen -= S
S.dropped(usr)
if(!S.amount)
qdel(S)
else
if(S.pulledby)
S.pulledby.stop_pulling()
S.loc = src
orient2hud(usr)
if(usr.s_active)
usr.s_active.show_to(usr)
update_icon()
return 1
// Sets up numbered display to show the stack size of each stored mineral
// NOTE: numbered display is turned off currently because it's broken
/obj/item/storage/bag/sheetsnatcher/orient2hud(mob/user)
var/adjusted_contents = contents.len
//Numbered contents display
var/list/datum/numbered_display/numbered_contents
if(display_contents_with_number)
numbered_contents = list()
adjusted_contents = 0
for(var/obj/item/stack/sheet/I in contents)
adjusted_contents++
var/datum/numbered_display/D = new/datum/numbered_display(I)
D.number = I.amount
numbered_contents.Add( D )
var/row_num = 0
var/col_count = min(7,storage_slots) -1
if (adjusted_contents > 7)
row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width.
src.standard_orient_objs(row_num, col_count, numbered_contents)
return
// Modified quick_empty verb drops appropriate sized stacks
/obj/item/storage/bag/sheetsnatcher/quick_empty()
var/location = get_turf(src)
for(var/obj/item/stack/sheet/S in contents)
while(S.amount)
var/obj/item/stack/sheet/N = new S.type(location)
var/stacksize = min(S.amount,N.max_amount)
N.amount = stacksize
S.amount -= stacksize
if(!S.amount)
qdel(S)// todo: there's probably something missing here
orient2hud(usr)
if(usr.s_active)
usr.s_active.show_to(usr)
update_icon()
// Instead of removing
/obj/item/storage/bag/sheetsnatcher/remove_from_storage(obj/item/W, atom/new_location)
var/obj/item/stack/sheet/S = W
if(!istype(S)) return 0
//I would prefer to drop a new stack, but the item/attack_hand code
// that calls this can't recieve a different object than you clicked on.
//Therefore, make a new stack internally that has the remainder.
// -Sayu
if(S.amount > S.max_amount)
var/obj/item/stack/sheet/temp = new S.type(src)
temp.amount = S.amount - S.max_amount
S.amount = S.max_amount
return ..(S,new_location)
// -----------------------------
// Sheet Snatcher (Cyborg)
// -----------------------------
/obj/item/storage/bag/sheetsnatcher/borg
name = "sheet snatcher 9000"
desc = ""
capacity = 500//Borgs get more because >specialization
// -----------------------------
// Book bag
// -----------------------------
/obj/item/storage/bag/books
name = "book bag"
desc = "A bag for books."
icon = 'icons/obj/library.dmi'
icon_state = "bookbag"
display_contents_with_number = 0 //This would look really stupid otherwise
storage_slots = 7
max_combined_w_class = 21
max_w_class = WEIGHT_CLASS_NORMAL
w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
can_hold = list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook)
resistance_flags = FLAMMABLE
/*
* Trays - Agouri
*/
/obj/item/storage/bag/tray
name = "tray"
icon = 'icons/obj/food/containers.dmi'
icon_state = "tray"
desc = "A metal tray to lay food on."
force = 5
throwforce = 10
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
materials = list(MAT_METAL=3000)
preposition = "on"
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
quick_empty()
// Make each item scatter a bit
for(var/obj/item/I in oldContents)
spawn()
for(var/i = 1, i <= rand(1,2), i++)
if(I)
step(I, pick(NORTH,SOUTH,EAST,WEST))
sleep(rand(2,4))
if(prob(50))
playsound(M, 'sound/items/trayhit1.ogg', 50, 1)
else
playsound(M, 'sound/items/trayhit2.ogg', 50, 1)
if(ishuman(M) || ismonkey(M))
if(prob(10))
M.Knockdown(40)
/obj/item/storage/bag/tray/proc/rebuild_overlays()
cut_overlays()
for(var/obj/item/I in contents)
add_overlay(mutable_appearance(I.icon, I.icon_state))
/obj/item/storage/bag/tray/remove_from_storage(obj/item/W as obj, atom/new_location)
..()
rebuild_overlays()
/obj/item/storage/bag/tray/handle_item_insertion(obj/item/I, prevent_warning = 0)
add_overlay(mutable_appearance(I.icon, I.icon_state))
. = ..()
/*
* Chemistry bag
*/
/obj/item/storage/bag/chemistry
name = "chemistry bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
desc = "A bag for storing pills, patches, and bottles."
storage_slots = 50
max_combined_w_class = 200
w_class = WEIGHT_CLASS_TINY
preposition = "in"
can_hold = list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)
resistance_flags = FLAMMABLE
/*
* Biowaste bag (mostly for xenobiologists)
*/
/obj/item/storage/bag/bio
name = "bio bag"
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
storage_slots = 25
max_combined_w_class = 200
w_class = WEIGHT_CLASS_TINY
preposition = "in"
can_hold = list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)
resistance_flags = FLAMMABLE
+1 -1
View File
@@ -134,7 +134,7 @@
to_chat(user, "<span class='warning'>Sticking an inactive [M.name] into the frame would sort of defeat the purpose.</span>")
return
if((config) && (!config.allow_ai) || jobban_isbanned(M.brainmob, "AI"))
if(!CONFIG_GET(flag/allow_ai) || jobban_isbanned(M.brainmob, "AI"))
to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>")
return
@@ -98,7 +98,7 @@
set category = "Object"
set src in oview(1)
if(config.ghost_interaction)
if(CONFIG_GET(flag/ghost_interaction))
spin()
else
if(!usr || !isturf(usr.loc))
@@ -23,7 +23,7 @@
return
move_delay = 1
if(step(src, direction))
spawn(config.walk_speed*move_speed_multiplier)
spawn(CONFIG_GET(number/walk_delay) * move_speed_multiplier)
move_delay = 0
else
move_delay = 0
+35 -19
View File
@@ -26,12 +26,11 @@
return
/obj/structure/lattice/ratvar_act()
if(IsEven(x + y))
new /obj/structure/lattice/clockwork(loc)
else
new /obj/structure/lattice/clockwork/large(loc)
new /obj/structure/lattice/clockwork(loc)
/obj/structure/lattice/attackby(obj/item/C, mob/user, params)
if(resistance_flags & INDESTRUCTIBLE)
return
if(istype(C, /obj/item/wirecutters))
to_chat(user, "<span class='notice'>Slicing [name] joints ...</span>")
deconstruct()
@@ -45,7 +44,6 @@
qdel(src)
/obj/structure/lattice/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_FOUR)
deconstruct()
@@ -55,22 +53,22 @@
icon = 'icons/obj/smooth_structures/lattice_clockwork.dmi'
/obj/structure/lattice/clockwork/Initialize(mapload)
canSmoothWith += /turf/open/indestructible/clock_spawn_room //list overrides are a terrible thing
. = ..()
ratvar_act()
if(z == ZLEVEL_CITYOFCOGS)
resistance_flags |= INDESTRUCTIBLE
/obj/structure/lattice/clockwork/ratvar_act()
if(IsOdd(x+y))
new /obj/structure/lattice/clockwork/large(loc) // deletes old one
/obj/structure/lattice/clockwork/large/Initialize(mapload)
. = ..()
icon = 'icons/obj/smooth_structures/lattice_clockwork_large.dmi'
pixel_x = -9
pixel_y = -9
/obj/structure/lattice/clockwork/large/ratvar_act()
if(IsEven(x + y))
new /obj/structure/lattice/clockwork(loc)
icon = 'icons/obj/smooth_structures/lattice_clockwork_large.dmi'
pixel_x = -9
pixel_y = -9
else
icon = 'icons/obj/smooth_structures/lattice_clockwork.dmi'
pixel_x = 0
pixel_y = 0
return TRUE
/obj/structure/lattice/catwalk
name = "catwalk"
@@ -99,11 +97,29 @@
/obj/structure/lattice/catwalk/clockwork
name = "clockwork catwalk"
icon = 'icons/obj/smooth_structures/catwalk_clockwork.dmi'
canSmoothWith = list(/obj/structure/lattice,
/turf/open/floor,
/turf/open/indestructible/clock_spawn_room,
/turf/closed/wall,
/obj/structure/falsewall)
smooth = SMOOTH_MORE
/obj/structure/lattice/catwalk/clockwork/Initialize(mapload)
. = ..()
new /obj/effect/temp_visual/ratvar/floor/catwalk(loc)
new /obj/effect/temp_visual/ratvar/beam/catwalk(loc)
ratvar_act()
if(!mapload)
new /obj/effect/temp_visual/ratvar/floor/catwalk(loc)
new /obj/effect/temp_visual/ratvar/beam/catwalk(loc)
if(z == ZLEVEL_CITYOFCOGS)
resistance_flags |= INDESTRUCTIBLE
/obj/structure/lattice/catwalk/clockwork/ratvar_act()
return
if(IsOdd(x+y))
icon = 'icons/obj/smooth_structures/catwalk_clockwork_large.dmi'
pixel_x = -9
pixel_y = -9
else
icon = 'icons/obj/smooth_structures/catwalk_clockwork.dmi'
pixel_x = 0
pixel_y = 0
return TRUE
+226 -225
View File
@@ -1,225 +1,226 @@
//wip wip wup
/obj/structure/mirror
name = "mirror"
desc = "Mirror mirror on the wall, who's the most robust of them all?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mirror"
density = FALSE
anchored = TRUE
max_integrity = 200
integrity_failure = 100
/obj/structure/mirror/attack_hand(mob/user)
if(broken || !Adjacent(user))
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/userloc = H.loc
//see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
//handle facial hair (if necessary)
if(H.gender == MALE)
var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.facial_hair_style = new_style
else
H.facial_hair_style = "Shaved"
//handle normal hair
var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.hair_style = new_style
H.update_hair()
/obj/structure/mirror/examine_status(mob/user)
if(broken)
return // no message spam
..()
/obj/structure/mirror/obj_break(damage_flag)
if(!broken && !(flags_1 & NODECONSTRUCT_1))
icon_state = "mirror_broke"
playsound(src, "shatter", 70, 1)
desc = "Oh no, seven years of bad luck!"
broken = 1
/obj/structure/mirror/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!disassembled)
new /obj/item/shard( src.loc )
qdel(src)
/obj/structure/mirror/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
var/obj/item/weldingtool/WT = I
if(broken)
user.changeNext_move(CLICK_CD_MELEE)
if(WT.remove_fuel(0, user))
to_chat(user, "<span class='notice'>You begin repairing [src]...</span>")
playsound(src, 'sound/items/welder.ogg', 100, 1)
if(do_after(user, 10*I.toolspeed, target = src))
if(!user || !WT || !WT.isOn())
return
to_chat(user, "<span class='notice'>You repair [src].</span>")
broken = 0
icon_state = initial(icon_state)
desc = initial(desc)
else
return ..()
/obj/structure/mirror/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
if(BURN)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
/obj/structure/mirror/magic
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
if(!choosable_races.len)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
if(!(S.id in races_blacklist))
choosable_races += S.id
..()
/obj/structure/mirror/magic/lesser/New()
choosable_races = GLOB.roundstart_species
..()
/obj/structure/mirror/magic/badmin/New()
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
choosable_races += S.id
..()
/obj/structure/mirror/magic/attack_hand(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
var/choice = input(user, "Something to change?", "Magical Grooming") as null|anything in list("name", "race", "gender", "hair", "eyes")
if(!Adjacent(user))
return
switch(choice)
if("name")
var/newname = copytext(sanitize(input(H, "Who are we again?", "Name change", H.name) as null|text),1,MAX_NAME_LEN)
if(!newname)
return
if(!Adjacent(user))
return
H.real_name = newname
H.name = newname
if(H.dna)
H.dna.real_name = newname
if(H.mind)
H.mind.name = newname
if("race")
var/newrace
var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races
newrace = GLOB.species_list[racechoice]
if(!newrace)
return
if(!Adjacent(user))
return
H.set_species(newrace, icon_update=0)
if(H.dna.species.use_skintones)
var/new_s_tone = input(user, "Choose your skin tone:", "Race change") as null|anything in GLOB.skin_tones
if(new_s_tone)
H.skin_tone = new_s_tone
H.dna.update_ui_block(DNA_SKIN_TONE_BLOCK)
if(MUTCOLORS in H.dna.species.species_traits)
var/new_mutantcolor = input(user, "Choose your skin color:", "Race change") as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
H.update_body()
H.update_hair()
H.update_body_parts()
H.update_mutations_overlay() // no hulk lizard
if("gender")
if(!(H.gender in list("male", "female"))) //blame the patriarchy
return
if(!Adjacent(user))
return
if(H.gender == "male")
if(alert(H, "Become a Witch?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "female"
to_chat(H, "<span class='notice'>Man, you feel like a woman!</span>")
else
return
else
if(alert(H, "Become a Warlock?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "male"
to_chat(H, "<span class='notice'>Whoa man, you feel like a man!</span>")
else
return
H.dna.update_ui_block(DNA_GENDER_BLOCK)
H.update_body()
H.update_mutations_overlay() //(hulk male/female)
if("hair")
var/hairchoice = alert(H, "Hair style or hair color?", "Change Hair", "Style", "Color")
if(!Adjacent(user))
return
if(hairchoice == "Style") //So you just want to use a mirror then?
..()
else
var/new_hair_color = input(H, "Choose your hair color", "Hair Color") as null|color
if(new_hair_color)
H.hair_color = sanitize_hexcolor(new_hair_color)
H.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK)
if(H.gender == "male")
var/new_face_color = input(H, "Choose your facial hair color", "Hair Color") as null|color
if(new_face_color)
H.facial_hair_color = sanitize_hexcolor(new_face_color)
H.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK)
H.update_hair()
if("eyes")
var/new_eye_color = input(H, "Choose your eye color", "Eye Color") as null|color
if(!Adjacent(user))
return
if(new_eye_color)
H.eye_color = sanitize_hexcolor(new_eye_color)
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.update_body()
if(choice)
curse(user)
/obj/structure/mirror/magic/proc/curse(mob/living/user)
return
//wip wip wup
/obj/structure/mirror
name = "mirror"
desc = "Mirror mirror on the wall, who's the most robust of them all?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mirror"
density = FALSE
anchored = TRUE
max_integrity = 200
integrity_failure = 100
/obj/structure/mirror/attack_hand(mob/user)
if(broken || !Adjacent(user))
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
var/userloc = H.loc
//see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
//handle facial hair (if necessary)
if(H.gender == MALE)
var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.facial_hair_style = new_style
else
H.facial_hair_style = "Shaved"
//handle normal hair
var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list
if(userloc != H.loc)
return //no tele-grooming
if(new_style)
H.hair_style = new_style
H.update_hair()
/obj/structure/mirror/examine_status(mob/user)
if(broken)
return // no message spam
..()
/obj/structure/mirror/obj_break(damage_flag)
if(!broken && !(flags_1 & NODECONSTRUCT_1))
icon_state = "mirror_broke"
playsound(src, "shatter", 70, 1)
desc = "Oh no, seven years of bad luck!"
broken = 1
/obj/structure/mirror/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!disassembled)
new /obj/item/shard( src.loc )
qdel(src)
/obj/structure/mirror/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
var/obj/item/weldingtool/WT = I
if(broken)
user.changeNext_move(CLICK_CD_MELEE)
if(WT.remove_fuel(0, user))
to_chat(user, "<span class='notice'>You begin repairing [src]...</span>")
playsound(src, 'sound/items/welder.ogg', 100, 1)
if(do_after(user, 10*I.toolspeed, target = src))
if(!user || !WT || !WT.isOn())
return
to_chat(user, "<span class='notice'>You repair [src].</span>")
broken = 0
icon_state = initial(icon_state)
desc = initial(desc)
else
return ..()
/obj/structure/mirror/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
if(BURN)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
/obj/structure/mirror/magic
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
if(!choosable_races.len)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
if(!(S.id in races_blacklist))
choosable_races += S.id
..()
/obj/structure/mirror/magic/lesser/New()
var/list/L = CONFIG_GET(keyed_flag_list/roundstart_races)
choosable_races = L.Copy()
..()
/obj/structure/mirror/magic/badmin/New()
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
choosable_races += S.id
..()
/obj/structure/mirror/magic/attack_hand(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
var/choice = input(user, "Something to change?", "Magical Grooming") as null|anything in list("name", "race", "gender", "hair", "eyes")
if(!Adjacent(user))
return
switch(choice)
if("name")
var/newname = copytext(sanitize(input(H, "Who are we again?", "Name change", H.name) as null|text),1,MAX_NAME_LEN)
if(!newname)
return
if(!Adjacent(user))
return
H.real_name = newname
H.name = newname
if(H.dna)
H.dna.real_name = newname
if(H.mind)
H.mind.name = newname
if("race")
var/newrace
var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races
newrace = GLOB.species_list[racechoice]
if(!newrace)
return
if(!Adjacent(user))
return
H.set_species(newrace, icon_update=0)
if(H.dna.species.use_skintones)
var/new_s_tone = input(user, "Choose your skin tone:", "Race change") as null|anything in GLOB.skin_tones
if(new_s_tone)
H.skin_tone = new_s_tone
H.dna.update_ui_block(DNA_SKIN_TONE_BLOCK)
if(MUTCOLORS in H.dna.species.species_traits)
var/new_mutantcolor = input(user, "Choose your skin color:", "Race change") as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
else
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
H.update_body()
H.update_hair()
H.update_body_parts()
H.update_mutations_overlay() // no hulk lizard
if("gender")
if(!(H.gender in list("male", "female"))) //blame the patriarchy
return
if(!Adjacent(user))
return
if(H.gender == "male")
if(alert(H, "Become a Witch?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "female"
to_chat(H, "<span class='notice'>Man, you feel like a woman!</span>")
else
return
else
if(alert(H, "Become a Warlock?", "Confirmation", "Yes", "No") == "Yes")
H.gender = "male"
to_chat(H, "<span class='notice'>Whoa man, you feel like a man!</span>")
else
return
H.dna.update_ui_block(DNA_GENDER_BLOCK)
H.update_body()
H.update_mutations_overlay() //(hulk male/female)
if("hair")
var/hairchoice = alert(H, "Hair style or hair color?", "Change Hair", "Style", "Color")
if(!Adjacent(user))
return
if(hairchoice == "Style") //So you just want to use a mirror then?
..()
else
var/new_hair_color = input(H, "Choose your hair color", "Hair Color") as null|color
if(new_hair_color)
H.hair_color = sanitize_hexcolor(new_hair_color)
H.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK)
if(H.gender == "male")
var/new_face_color = input(H, "Choose your facial hair color", "Hair Color") as null|color
if(new_face_color)
H.facial_hair_color = sanitize_hexcolor(new_face_color)
H.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK)
H.update_hair()
if("eyes")
var/new_eye_color = input(H, "Choose your eye color", "Eye Color") as null|color
if(!Adjacent(user))
return
if(new_eye_color)
H.eye_color = sanitize_hexcolor(new_eye_color)
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.update_body()
if(choice)
curse(user)
/obj/structure/mirror/magic/proc/curse(mob/living/user)
return
@@ -142,6 +142,7 @@
name = "clockwork floor"
desc = "Tightly-pressed brass tiles. They emit minute vibration."
icon_state = "plating"
baseturf = /turf/open/floor/clockwork
var/uses_overlay = TRUE
var/obj/effect/clockwork/overlay/floor/realappearence
@@ -152,18 +153,16 @@
new /obj/effect/temp_visual/ratvar/beam(src)
realappearence = new /obj/effect/clockwork/overlay/floor(src)
realappearence.linked = src
change_construction_value(1)
/turf/open/floor/clockwork/Destroy()
STOP_PROCESSING(SSobj, src)
if(uses_overlay)
change_construction_value(-1)
if(realappearence)
qdel(realappearence)
realappearence = null
if(uses_overlay && realappearence)
QDEL_NULL(realappearence)
return ..()
/turf/open/floor/clockwork/ReplaceWithLattice()
if(baseturf == type)
return
..()
for(var/obj/structure/lattice/L in src)
L.ratvar_act()
@@ -197,6 +196,8 @@
L.adjustToxLoss(-3, TRUE, TRUE)
/turf/open/floor/clockwork/attackby(obj/item/I, mob/living/user, params)
if(baseturf == type)
return
if(istype(I, /obj/item/crowbar))
user.visible_message("<span class='notice'>[user] begins slowly prying up [src]...</span>", "<span class='notice'>You begin painstakingly prying up [src]...</span>")
playsound(src, I.usesound, 20, 1)
+47
View File
@@ -0,0 +1,47 @@
/turf/open/indestructible/reebe_void
name = "void"
icon_state = "reebemap"
layer = SPACE_LAYER
baseturf = /turf/open/indestructible/reebe_void
planetary_atmos = TRUE
/turf/open/indestructible/reebe_void/Initialize(mapload)
. = ..()
icon_state = "reebegame"
/turf/open/indestructible/reebe_void/spawning
icon_state = "reebespawn"
/turf/open/indestructible/reebe_void/spawning/Initialize(mapload)
. = ..()
if(mapload)
for(var/i in 1 to 3)
if(prob(1))
new /obj/item/clockwork/alloy_shards/large(src)
if(prob(2))
new /obj/item/clockwork/alloy_shards/medium(src)
if(prob(3))
new /obj/item/clockwork/alloy_shards/small(src)
/turf/open/indestructible/reebe_void/spawning/lattices
icon_state = "reebelattice"
/turf/open/indestructible/reebe_void/spawning/lattices/Initialize(mapload)
. = ..()
if(mapload)
if(prob(2.5))
new /obj/structure/lattice/catwalk/clockwork(src)
else if(prob(5))
new /obj/structure/lattice/clockwork(src)
/turf/open/indestructible/reebe_void/Enter(atom/movable/AM, atom/old_loc)
if(!..())
return FALSE
else
if(istype(AM, /obj/structure/window))
return FALSE
if(istype(AM, /obj/item/projectile))
return TRUE
if((locate(/obj/structure/lattice) in src))
return TRUE
return FALSE
+1 -7
View File
@@ -55,6 +55,7 @@
sheet_type = /obj/item/stack/tile/brass
sheet_amount = 1
girder_type = /obj/structure/destructible/clockwork/wall_gear
baseturf = /turf/open/floor/clockwork/reebe
var/obj/effect/clockwork/overlay/wall/realappearence
/turf/closed/wall/clockwork/Initialize()
@@ -63,15 +64,8 @@
new /obj/effect/temp_visual/ratvar/beam(src)
realappearence = new /obj/effect/clockwork/overlay/wall(src)
realappearence.linked = src
change_construction_value(5)
/turf/closed/wall/clockwork/examine(mob/user)
..()
if((is_servant_of_ratvar(user) || isobserver(user)))
to_chat(user, "<span class='brass'>It is linked to a Tinkerer's Cache, generating components!</span>")
/turf/closed/wall/clockwork/Destroy()
change_construction_value(-5)
if(realappearence)
qdel(realappearence)
realappearence = null
+2 -1
View File
@@ -14,6 +14,7 @@
var/global/datum/gas_mixture/immutable/space/space_gas = new
plane = PLANE_SPACE
layer = SPACE_LAYER
light_power = 0.25
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
@@ -66,7 +67,7 @@
return
/turf/open/space/proc/update_starlight()
if(config.starlight)
if(CONFIG_GET(flag/starlight))
for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm
if(isspaceturf(t))
//let's NOT update this that much pls
+38 -64
View File
@@ -1,3 +1,6 @@
#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round
//This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
GLOBAL_VAR(security_mode)
GLOBAL_PROTECT(security_mode)
@@ -12,29 +15,27 @@ GLOBAL_PROTECT(security_mode)
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
config = new
new /datum/controller/configuration
CheckSchemaVersion()
SetRoundID()
SetupLogs()
if(!RunningService()) //tgs2 support
GLOB.revdata.DownloadPRDetails()
SERVER_TOOLS_ON_NEW
load_motd()
load_admins()
LoadVerbs(/datum/verbs/menu)
if(config.usewhitelist)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
reload_custom_roundstart_items_list()
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
Master.Initialize(10, FALSE)
if(config.irc_announce_new_game)
IRCBroadcast("New round starting on [SSmapping.config.map_name]!")
/world/proc/SetupExternalRSC()
#if (PRELOAD_RSC == 0)
@@ -48,7 +49,7 @@ GLOBAL_PROTECT(security_mode)
#endif
/world/proc/CheckSchemaVersion()
if(config.sql_enabled)
if(CONFIG_GET(flag/sql_enabled))
if(SSdbcore.Connect())
log_world("Database connection established.")
var/datum/DBQuery/query_db_version = SSdbcore.NewQuery("SELECT major, minor FROM [format_table_name("schema_revision")] ORDER BY date DESC LIMIT 1")
@@ -68,7 +69,7 @@ GLOBAL_PROTECT(security_mode)
log_world("Your server failed to establish a connection with the database.")
/world/proc/SetRoundID()
if(config.sql_enabled)
if(CONFIG_GET(flag/sql_enabled))
if(SSdbcore.Connect())
var/datum/DBQuery/query_round_start = SSdbcore.NewQuery("INSERT INTO [format_table_name("round")] (start_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
query_round_start.Execute()
@@ -122,12 +123,13 @@ GLOBAL_PROTECT(security_mode)
var/pinging = ("ping" in input)
var/playing = ("players" in input)
if(!pinging && !playing && config && config.log_world_topic)
if(!pinging && !playing && config && CONFIG_GET(flag/log_world_topic))
WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
if(input[SERVICE_CMD_PARAM_KEY])
return ServiceCommand(input)
var/key_valid = (global.comms_allowed && input["key"] == global.comms_key)
SERVER_TOOLS_ON_TOPIC //redirect to server tools if necessary
var/comms_key = CONFIG_GET(string/comms_key)
var/key_valid = (comms_key && input["key"] == comms_key)
if(pinging)
var/x = 1
@@ -142,25 +144,14 @@ GLOBAL_PROTECT(security_mode)
n++
return n
else if("ircstatus" in input) //tgs2 support
var/static/last_irc_status = 0
if(world.time - last_irc_status < 50)
return
var/list/adm = get_admin_counts()
var/list/allmins = adm["total"]
var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). "
status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode.name]."
send2irc("Status", status)
last_irc_status = world.time
else if("status" in input)
var/list/s = list()
s["version"] = GLOB.game_version
s["mode"] = GLOB.master_mode
s["respawn"] = config ? GLOB.abandon_allowed : 0
s["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
s["enter"] = GLOB.enter_allowed
s["vote"] = config.allow_vote_mode
s["ai"] = config.allow_ai
s["vote"] = CONFIG_GET(flag/allow_vote_mode)
s["ai"] = CONFIG_GET(flag/allow_ai)
s["host"] = host ? host : null
s["active_players"] = get_active_player_count()
s["players"] = GLOB.clients.len
@@ -210,24 +201,6 @@ GLOBAL_PROTECT(security_mode)
if(input["crossmessage"] == "News_Report")
minor_announce(input["message"], "Breaking Update From [input["message_sender"]]")
else if("adminmsg" in input) //tgs2 support
if(!key_valid)
return "Bad Key"
else
return IrcPm(input["adminmsg"],input["msg"],input["sender"])
else if("namecheck" in input) //tgs2 support
if(!key_valid)
return "Bad Key"
else
log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]")
message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]")
return keywords_lookup(input["namecheck"],1)
else if("adminwho" in input) //tgs2 support
if(!key_valid)
return "Bad Key"
else
return ircadminwho()
else if("server_hop" in input)
show_server_hop_transfer_screen(input["server_hop"])
@@ -246,7 +219,7 @@ GLOBAL_PROTECT(security_mode)
C.AnnouncePR(final_composed)
/world/Reboot(reason = 0, fast_track = FALSE)
ServiceReboot() //handles alternative actions if necessary
SERVER_TOOLS_ON_REBOOT
if (reason || fast_track) //special reboot, do none of the normal stuff
if (usr)
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
@@ -262,17 +235,6 @@ GLOBAL_PROTECT(security_mode)
GLOB.join_motd = file2text("config/motd.txt") + "<br>" + GLOB.revdata.GetTestMergeInfo()
/world/proc/update_status()
var/s = ""
if (config && config.server_name)
s += "<b>[config.server_name]</b> &#8212; "
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"http://\">" //Change this to wherever you want the hub to link to.
s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
s += "</a>"
s += ")"
var/list/features = list()
@@ -282,13 +244,25 @@ GLOBAL_PROTECT(security_mode)
if (!GLOB.enter_allowed)
features += "closed"
features += GLOB.abandon_allowed ? "respawn" : "no respawn"
var/s = ""
var/hostedby
if(config)
var/server_name = CONFIG_GET(string/servername)
if (server_name)
s += "<b>[server_name]</b> &#8212; "
features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn"
if(CONFIG_GET(flag/allow_vote_mode))
features += "vote"
if(CONFIG_GET(flag/allow_ai))
features += "AI allowed"
hostedby = CONFIG_GET(string/hostedby)
if (config && config.allow_vote_mode)
features += "vote"
if (config && config.allow_ai)
features += "AI allowed"
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"http://\">" //Change this to wherever you want the hub to link to.
s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
s += "</a>"
s += ")"
var/n = 0
for (var/mob/M in GLOB.player_list)
@@ -300,8 +274,8 @@ GLOBAL_PROTECT(security_mode)
else if (n > 0)
features += "~[n] player"
if (!host && config && config.hostedby)
features += "hosted by <b>[config.hostedby]</b>"
if (!host && hostedby)
features += "hosted by <b>[hostedby]</b>"
if (features)
s += ": [jointext(features, ", ")]"