Merge branch 'master' into donut

This commit is contained in:
Trilbyspaceclone
2019-12-17 15:12:51 -05:00
committed by GitHub
700 changed files with 12811 additions and 3750 deletions
+3 -3
View File
@@ -327,7 +327,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
for(var/obj/machinery/light/L in src)
L.update()
/area/proc/updateicon()
/area/proc/update_icon()
var/weather_icon
for(var/V in SSweather.processing)
var/datum/weather/W = V
@@ -337,7 +337,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!weather_icon)
icon_state = null
/area/space/updateicon()
/area/space/update_icon()
icon_state = null
/*
@@ -370,7 +370,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
/area/proc/power_change()
for(var/obj/machinery/M in src) // for each machine in the area
M.power_change() // reverify power status (to update icons etc.)
updateicon()
update_icon()
/area/proc/usage(chan)
var/used = 0
+2 -3
View File
@@ -809,8 +809,7 @@ Proc for attack log creation, because really why not
// Filter stuff
/atom/movable/proc/add_filter(name,priority,list/params)
if(!filter_data)
filter_data = list()
LAZYINITLIST(filter_data)
var/list/p = params.Copy()
p["priority"] = priority
filter_data[name] = p
@@ -818,7 +817,7 @@ Proc for attack log creation, because really why not
/atom/movable/proc/update_filters()
filters = null
sortTim(filter_data,associative = TRUE)
filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
for(var/f in filter_data)
var/list/data = filter_data[f]
var/list/arguments = data.Copy()
@@ -0,0 +1,292 @@
/datum/game_mode
var/list/datum/mind/bloodsuckers = list() // List of minds belonging to this game mode.
var/list/datum/mind/vassals = list() // List of minds that have been turned into Vassals.
//var/list/datum/mind/vamphunters = list() // List of minds hunting vampires. Disabled at the moment
var/obj/effect/sunlight/bloodsucker_sunlight // Sunlight Timer. Created on first Bloodsucker assign. Destroyed on last removed Bloodsucker.
// LISTS //
var/list/vassal_allowed_antags = list(/datum/antagonist/brother, /datum/antagonist/traitor, /datum/antagonist/traitor/internal_affairs, /datum/antagonist/survivalist, \
/datum/antagonist/rev, /datum/antagonist/nukeop, /datum/antagonist/pirate, /datum/antagonist/cult, /datum/antagonist/abductee)
// The antags you're allowed to be if turning Vassal.
/datum/game_mode/bloodsucker
name = "bloodsucker"
config_tag = "bloodsucker"
traitor_name = "Bloodsucker"
antag_flag = ROLE_BLOODSUCKER
false_report_weight = 1
restricted_jobs = list("AI","Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20
required_enemies = 2
recommended_enemies = 4
reroll_friendly = FALSE
enemy_minimum_age = 7
round_ends_with_antag_death = FALSE
announce_span = "danger"
announce_text = "Filthy, bloodsucking vampires are crawling around disguised as crewmembers!\n\
<span class='danger'>Bloodsuckers</span>: The crew are cattle, while you are both shepherd and slaughterhouse.\n\
<span class='notice'>Crew</span>: Put an end to the undead infestation before the station is overcome!"
/datum/game_mode/bloodsucker/generate_report()
return "Reports indicate that some of your crew may have toppled statues in the past week, angering the gods and becoming cursed with undeath and a desire for blood. Watch out for crewmembers that seem to shun the light or are found pale and delirious."
// Seems to be run by game ONCE, and finds all potential players to be antag.
/datum/game_mode/bloodsucker/pre_setup()
// Set Restricted Jobs
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
// Set number of Vamps
recommended_enemies = CLAMP(round(num_players()/10), 1, 6);
// Select Antags
for(var/i = 0, i < recommended_enemies, i++)
if (!antag_candidates.len)
break
var/datum/mind/bloodsucker = pick(antag_candidates)
// Can we even BE a bloodsucker?
//if (can_make_bloodsucker(bloodsucker, display_warning=FALSE))
bloodsuckers += bloodsucker
bloodsucker.restricted_roles = restricted_jobs
log_game("[bloodsucker.key] (ckey) has been selected as a Bloodsucker.")
antag_candidates.Remove(bloodsucker) // Apparently you can also write antag_candidates -= bloodsucker
// Assign Hunters (as many as monsters, plus one)
//assign_monster_hunters(bloodsuckers.len, TRUE, bloodsuckers) // Disabled for now
// Do we have enough vamps to continue?
return bloodsuckers.len >= required_enemies
// Gamemode is all done being set up. We have all our Vamps. We now pick objectives and let them know what's happening.
/datum/game_mode/bloodsucker/post_setup()
// Sunlight (Creating Bloodsuckers manually will check to create this, too)
check_start_sunlight()
// Vamps
for(var/datum/mind/bloodsucker in bloodsuckers)
// spawn() --> Run block of code but game continues on past it.
// sleep() --> Run block of code and freeze code there (including whoever called us) until it's resolved.
//Clean Bloodsucker Species (racist?)
//clean_invalid_species(bloodsucker)
// TO-DO !!!
// Add Bloodsucker Antag Datum (or remove from list on Fail)
if (!make_bloodsucker(bloodsucker))
bloodsuckers -= bloodsucker
// NOTE: Hunters are done in ..() parent proc
return ..()
// Checking for ACTUALLY Dead Vamps
/datum/game_mode/bloodsucker/are_special_antags_dead()
// Bloodsucker not Final Dead
for(var/datum/mind/bloodsucker in bloodsuckers)
if(!bloodsucker.AmFinalDeath())
return FALSE
return TRUE
// Init Sunlight (called from datum_bloodsucker.on_gain(), in case game mode isn't even Bloodsucker
/datum/game_mode/proc/check_start_sunlight()
// Already Sunlight (and not about to cancel)
if (istype(bloodsucker_sunlight) && !bloodsucker_sunlight.cancel_me)
return
bloodsucker_sunlight = new ()
// End Sun (last bloodsucker removed)
/datum/game_mode/proc/check_cancel_sunlight()
// No Sunlight
if (!istype(bloodsucker_sunlight))
return
if (bloodsuckers.len <= 0)
bloodsucker_sunlight.cancel_me = TRUE
qdel(bloodsucker_sunlight)
bloodsucker_sunlight = null
/datum/game_mode/proc/is_daylight()
return istype(bloodsucker_sunlight) && bloodsucker_sunlight.amDay
//////////////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/can_make_bloodsucker(datum/mind/bloodsucker, datum/mind/creator, display_warning=TRUE) // Creator is just here so we can display fail messages to whoever is turning us.
// No Mind
if(!bloodsucker || !bloodsucker.key) // KEY is client login?
//if(creator) // REMOVED. You wouldn't see their name if there is no mind, so why say anything?
// to_chat(creator, "<span class='danger'>[bloodsucker] isn't self-aware enough to be raised as a Bloodsucker!</span>")
return FALSE
// Current body is invalid
if(!ishuman(bloodsucker.current))// && !ismonkey(bloodsucker.current))
if(display_warning && creator)
to_chat(creator, "<span class='danger'>[bloodsucker] isn't evolved enough to be raised as a Bloodsucker!</span>")
return FALSE
// Species Must have a HEART (Sorry Plasmabois)
var/mob/living/carbon/human/H = bloodsucker.current
if(NOBLOOD in H.dna.species.species_traits)
if(display_warning && creator)
to_chat(creator, "<span class='danger'>[bloodsucker]'s DNA isn't compatible!</span>")
return FALSE
// Already a Non-Human Antag
if(bloodsucker.has_antag_datum(/datum/antagonist/abductor) || bloodsucker.has_antag_datum(/datum/antagonist/devil) || bloodsucker.has_antag_datum(/datum/antagonist/changeling))
return FALSE
// Already a vamp
if(bloodsucker.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
if(display_warning && creator)
to_chat(creator, "<span class='danger'>[bloodsucker] is already a Bloodsucker!</span>")
return FALSE
// Not High Enough
if(creator)
var/datum/antagonist/bloodsucker/creator_bloodsucker = creator.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
if(!istype(creator_bloodsucker) || creator_bloodsucker.vamplevel < BLOODSUCKER_LEVEL_TO_EMBRACE)
to_chat(creator, "<span class='danger'>Your blood is too thin to turn this corpse!</span>")
return FALSE
return TRUE
/datum/game_mode/proc/make_bloodsucker(datum/mind/bloodsucker, datum/mind/creator = null) // NOTE: This is a game_mode/proc, NOT a game_mode/bloodsucker/proc! We need to access this function despite the game mode.
if (!can_make_bloodsucker(bloodsucker))
return FALSE
// Create Datum: Fledgling
var/datum/antagonist/bloodsucker/A
// [FLEDGLING]
if (creator)
A = new (bloodsucker)
A.creator = creator
bloodsucker.add_antag_datum(A)
// Log
message_admins("[bloodsucker] has become a Bloodsucker, and was created by [creator].")
log_admin("[bloodsucker] has become a Bloodsucker, and was created by [creator].")
// [MASTER]
else
A = bloodsucker.add_antag_datum(ANTAG_DATUM_BLOODSUCKER)
return TRUE
/datum/game_mode/proc/remove_bloodsucker(datum/mind/bloodsucker)
bloodsucker.remove_antag_datum(ANTAG_DATUM_BLOODSUCKER)
/datum/game_mode/proc/clean_invalid_species(datum/mind/bloodsucker)
// Only checking for Humans here
if (!ishuman(bloodsucker.current) || !bloodsucker.current.client)
return
var/am_valid = TRUE
var/mob/living/carbon/human/H = bloodsucker.current
// Check if PLASMAMAN?
if(NOBLOOD in H.dna.species.species_traits)
am_valid = FALSE
// PROBLEM:
//
// Setting species leaves clothes on. If you were a plasmaman, we need to reassign your entire outfit. Otherwise
// everyone will wonder why you're a human with Plasma clothes (jk they'll know you're antag)
// Convert to HUMAN (along with ID and PDA)
if (!am_valid)
H.set_species(/datum/species/human)
H.real_name = H.client.prefs.custom_names["human"]
var/obj/item/card/id/ID = H.wear_id?.GetID()
if(ID)
ID.registered_name = H.real_name
ID.update_label()
/datum/game_mode/proc/can_make_vassal(mob/living/target, datum/mind/creator, display_warning=TRUE)//, check_antag_or_loyal=FALSE)
// Not Correct Type: Abort
if (!iscarbon(target) || !creator)
return FALSE
if (target.stat > UNCONSCIOUS)
return FALSE
// Check Overdose: Am I even addicted to blood? Do I even have any in me?
//if (!target.reagents.addiction_list || !target.reagents.reagent_list)
//message_admins("DEBUG2: can_make_vassal() Abort: No reagents")
// return 0
// Check Overdose: Did my current volume go over the Overdose threshold?
//var/am_addicted = 0
//for (var/datum/reagent/blood/vampblood/blood in target.reagents.addiction_list) // overdosed is tracked in reagent_list, not addiction_list.
//message_admins("DEBUG3: can_make_vassal() Found Blood! [blood] [blood.overdose]")
//if (blood.overdosed)
// am_addicted = 1 // Blood is present in addiction? That's all we need.
// break
//if (!am_addicted)
//message_admins("DEBUG4: can_make_vassal() Abort: No Blood")
// return 0
// No Mind!
if (!target.mind || !target.mind.key)
if (display_warning)
to_chat(creator, "<span class='danger'>[target] isn't self-aware enough to be made into a Vassal.</span>")
return FALSE
// Already MY Vassal
var/datum/antagonist/vassal/V = target.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if (istype(V) && V.master)
if (V.master.owner == creator)
if (display_warning)
to_chat(creator, "<span class='danger'>[target] is already your loyal Vassal!</span>")
else
if (display_warning)
to_chat(creator, "<span class='danger'>[target] is the loyal Vassal of another Bloodsucker!</span>")
return FALSE
// Already Antag or Loyal (Vamp Hunters count as antags)
if (target.mind.enslaved_to || AmInvalidAntag(target.mind)) //!VassalCheckAntagValid(target.mind, check_antag_or_loyal)) // HAS_TRAIT(target, TRAIT_MINDSHIELD, "implant") ||
if (display_warning)
to_chat(creator, "<span class='danger'>[target] resists the power of your blood to dominate their mind!</span>")
return FALSE
return TRUE
/datum/game_mode/proc/AmValidAntag(datum/mind/M)
// No List?
if(!islist(M.antag_datums) || M.antag_datums.len == 0)
return FALSE
// Am I NOT an invalid Antag? NOTE: We already excluded non-antags above. Don't worry about the "No List?" check in AmInvalidIntag()
return !AmInvalidAntag(M)
/datum/game_mode/proc/AmInvalidAntag(datum/mind/M)
// No List?
if(!islist(M.antag_datums) || M.antag_datums.len == 0)
return FALSE
// Does even ONE antag appear in this mind that isn't in the list? Then FAIL!
for(var/datum/antagonist/antag_datum in M.antag_datums)
if (!(antag_datum.type in vassal_allowed_antags)) // vassal_allowed_antags is a list stored in the game mode, above.
//message_admins("DEBUG VASSAL: Found Invalid: [antag_datum] // [antag_datum.type]")
return TRUE
//message_admins("DEBUG VASSAL: Valid Antags! (total of [M.antag_datums.len])")
// WHEN YOU DELETE THE ABOVE: Remove the 3 second timer on converting the vassal too.
return FALSE
/datum/game_mode/proc/make_vassal(mob/living/target, datum/mind/creator)
if (!can_make_vassal(target,creator))
return FALSE
// Make Vassal
var/datum/antagonist/vassal/V = new (target.mind)
var/datum/antagonist/bloodsucker/B = creator.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
V.master = B
target.mind.add_antag_datum(V, V.master.get_team())
// Update Bloodsucker Title (we're a daddy now)
B.SelectTitle(am_fledgling = FALSE) // Only works if you have no title yet.
// Log
message_admins("[target] has become a Vassal, and is enslaved to [creator].")
log_admin("[target] has become a Vassal, and is enslaved to [creator].")
return TRUE
/datum/game_mode/proc/remove_vassal(datum/mind/vassal)
vassal.remove_antag_datum(ANTAG_DATUM_VASSAL)
+50
View File
@@ -0,0 +1,50 @@
/*
// Called from game mode pre_setup()
/datum/game_mode/proc/assign_monster_hunters(monster_count = 4, guaranteed_hunters = FALSE, list/datum/mind/exclude_from_hunter)
// Not all game modes GUARANTEE a hunter
if (rand(0,2) == 0) // 50% of the time, we get fewer or NO Hunters
if (!guaranteed_hunters)
return
else
monster_count /= 2
var/list/no_hunter_jobs = list("AI","Cyborg")
// Set Restricted Jobs
if(CONFIG_GET(flag/protect_roles_from_antagonist))
no_hunter_jobs += list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
no_hunter_jobs += "Assistant"
// Find Valid Hunters
var/list/datum/mind/hunter_candidates = get_players_for_role(ROLE_MONSTERHUNTER)
// Assign Hunters (as many as vamps, plus one)
for(var/i = 1, i < monster_count, i++) // Start at 1 so we skip Hunters if there's only one sucker.
if (!hunter_candidates.len)
break
// Assign Hunter
var/datum/mind/hunter = pick(hunter_candidates)
hunter_candidates.Remove(hunter) // Remove Either Way
// Already Antag? Skip
if (islist(exclude_from_hunter) && (locate(hunter) in exclude_from_hunter)) //if (islist(hunter.antag_datums) && hunter.antag_datums.len)
i --
continue
// NOTE:
vamphunters += hunter
hunter.restricted_roles = no_hunter_jobs
log_game("[hunter.key] (ckey) has been selected as a Hunter.")
// Called from game mode post_setup()
/datum/game_mode/proc/finalize_monster_hunters(monster_count = 4)
var/amEvil = TRUE // First hunter is always an evil boi
for(var/datum/mind/hunter in vamphunters)
var/datum/antagonist/vamphunter/A = new (hunter)
A.bad_dude = amEvil
hunter.add_antag_datum(A)
amEvil = FALSE // Every other hunter is just a boring greytider
*/
@@ -265,6 +265,7 @@
armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
max_temperature = 35000
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/honker/dark
max_equip = 3
spawn_tracked = FALSE
+3
View File
@@ -236,6 +236,9 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
return rule.round_result()
return ..()
/datum/game_mode/dynamic/generate_report()
return "Mysterious signals that demonstrate strange dynamics have been detected in your sector. Watch out for oddities."
/datum/game_mode/dynamic/send_intercept()
. = "<b><i>Central Command Status Summary</i></b><hr>"
switch(round(threat_level))
@@ -94,11 +94,8 @@
var/list/possible_candidates = list()
possible_candidates.Add(dead_players)
possible_candidates.Add(list_observers)
send_applications(possible_candidates)
if(assigned.len > 0)
return TRUE
else
return FALSE
var/application_successful = send_applications(possible_candidates)
return assigned.len > 0 && application_successful
/// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset.
/datum/dynamic_ruleset/midround/from_ghosts/proc/send_applications(list/possible_volunteers = list())
@@ -113,25 +110,18 @@
if(!candidates || candidates.len <= required_candidates)
message_admins("The ruleset [name] did not receive enough applications.")
log_game("DYNAMIC: The ruleset [name] did not receive enough applications.")
mode.refund_threat(cost)
mode.log_threat("Rule [name] refunded [cost] (not receive enough applications)",verbose=TRUE)
mode.executed_rules -= src
return
return FALSE
message_admins("[candidates.len] players volunteered for the ruleset [name].")
log_game("DYNAMIC: [candidates.len] players volunteered for [name].")
review_applications()
return TRUE
/// Here is where you can check if your ghost applicants are valid for the ruleset.
/// Called by send_applications().
/datum/dynamic_ruleset/midround/from_ghosts/proc/review_applications()
for (var/i = 1, i <= required_candidates, i++)
if(candidates.len <= 0)
if(i == 1)
// We have found no candidates so far and we are out of applicants.
mode.refund_threat(cost)
mode.log_threat("Rule [name] refunded [cost] (all applications invalid)",verbose=TRUE)
mode.executed_rules -= src
break
var/mob/applicant = pick(candidates)
candidates -= applicant
@@ -744,3 +734,31 @@
#undef ABDUCTOR_MAX_TEAMS
#undef REVENANT_SPAWN_THRESHOLD
//////////////////////////////////////////////
// //
// BLOODSUCKERS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/bloodsucker
name = "Bloodsucker Infiltrator"
config_tag = "latejoin_bloodsucker"
antag_datum = ANTAG_DATUM_BLOODSUCKER
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 3
cost = 10
requirements = list(90,80,70,60,55,50,45,40,35,30)
high_population_requirement = 30
repeatable = TRUE
/datum/dynamic_ruleset/latejoin/bloodsucker/execute()
var/mob/M = pick(candidates)
assigned += M.mind
M.mind.special_role = antag_flag
if(mode.make_bloodsucker(M.mind))
mode.bloodsuckers += M
return TRUE
@@ -778,3 +778,42 @@
var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
spawn_meteors(ramp_up_final, wavetype)
//////////////////////////////////////////////
// //
// BLOODSUCKERS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/bloodsucker
name = "Bloodsuckers"
config_tag = "bloodsucker"
persistent = TRUE
antag_flag = ROLE_BLOODSUCKER
antag_datum = ANTAG_DATUM_BLOODSUCKER
minimum_required_age = 0
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
restricted_roles = list("Cyborg", "AI")
required_candidates = 1
weight = 2
cost = 15
scaling_cost = 10
requirements = list(90,80,70,60,50,50,50,50,50,50)
high_population_requirement = 50
antag_cap = list(1,1,1,1,1,2,2,2,2,2)
/datum/dynamic_ruleset/roundstart/bloodsucker/pre_execute()
var/num_bloodsuckers = antag_cap[indice_pop] * (scaled_times + 1)
for (var/i = 1 to num_bloodsuckers)
var/mob/M = pick_n_take(candidates)
assigned += M.mind
M.mind.special_role = ROLE_BLOODSUCKER
M.mind.restricted_roles = restricted_roles
return TRUE
/datum/dynamic_ruleset/roundstart/bloodsucker/execute()
mode.check_start_sunlight()
for(var/datum/mind/M in assigned)
if(mode.make_bloodsucker(M))
mode.bloodsuckers += M
return TRUE
+79 -38
View File
@@ -81,6 +81,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.
//finalize_monster_hunters() Disabled for now
if(!report)
report = !CONFIG_GET(flag/no_intercept_report)
addtimer(CALLBACK(GLOBAL_PROC, .proc/display_roundstart_logout_report), ROUNDSTART_LOGOUT_REPORT_TIME)
@@ -305,48 +306,88 @@
// The odds become:
// Player A: 150 / 250 = 0.6 = 60%
// Player B: 100 / 250 = 0.4 = 40%
/datum/game_mode/proc/antag_pick(list/datum/candidates)
//Use return list if you want a list, with the arg being the number you want returned.
//WARNING: THIS PROC DOES NOT TAKE INTO ACCOUNT WHAT SSPersistence ALREADY HAS FOR "ADJUST ANTAG REP". If this is used more than once
//and the person rolls more than once, they will not get even more deduction!
//More efficient if you use return list instead of calling this multiple times
//fail_default_pick makes it use pick() instead of antag rep if it can't find anyone
//allow_zero_if_insufficient allows it to pick people with zero rep if there isn't enough antags
/datum/game_mode/proc/antag_pick(list/datum/mind/candidates, return_list = FALSE, fail_default_pick = TRUE, allow_zero_if_insufficient = TRUE)
if(!CONFIG_GET(flag/use_antag_rep)) // || candidates.len <= 1)
return pick(candidates)
// Tickets start at 100
var/DEFAULT_ANTAG_TICKETS = CONFIG_GET(number/default_antag_tickets)
//whoever named the config entries is a bad person :(
// You may use up to 100 extra tickets (double your odds)
var/MAX_TICKETS_PER_ROLL = CONFIG_GET(number/max_tickets_per_roll)
var/total_tickets = 0
MAX_TICKETS_PER_ROLL += DEFAULT_ANTAG_TICKETS
var/p_ckey
var/p_rep
for(var/datum/mind/mind in candidates)
p_ckey = ckey(mind.key)
total_tickets += min(SSpersistence.antag_rep[p_ckey] + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
var/antag_select = rand(1,total_tickets)
var/current = 1
for(var/datum/mind/mind in candidates)
p_ckey = ckey(mind.key)
p_rep = SSpersistence.antag_rep[p_ckey]
var/previous = current
var/spend = min(p_rep + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
current += spend
if(antag_select >= previous && antag_select <= (current-1))
SSpersistence.antag_rep_change[p_ckey] = -(spend - DEFAULT_ANTAG_TICKETS)
// WARNING("AR_DEBUG: Player [mind.key] won spending [spend] tickets from starting value [SSpersistence.antag_rep[p_ckey]]")
return mind
WARNING("Something has gone terribly wrong. /datum/game_mode/proc/antag_pick failed to select a candidate. Falling back to pick()")
return pick(candidates)
//Tickets you get for free
var/free_tickets = CONFIG_GET(number/default_antag_tickets)
//Max extra tickets you can use
var/additional_tickets = CONFIG_GET(number/max_tickets_per_roll)
var/list/ckey_to_mind = list() //this is admittedly shitcode but I'm webediting
var/list/prev_tickets = SSpersistence.antag_rep //cache for hyper-speed in theory. how many tickets someone has stored
var/list/curr_tickets = list() //how many tickets someone has for *this* antag roll, so with the free tickets
var/list/datum/mind/insufficient = list() //who got cucked out of an antag roll due to not having *any* tickets
for(var/datum/mind/M in candidates)
var/mind_ckey = ckey(M.key)
var/can_spend = min(prev_tickets[mind_ckey], additional_tickets) //they can only spend up to config/max_tickets_per_roll
var/amount = can_spend + free_tickets //but they get config/default_antag_tickets for free
if(amount <= 0) //if they don't have any
insufficient += M //too bad!
continue
curr_tickets[mind_ckey] = amount
ckey_to_mind[mind_ckey] = M //make sure we can look them up after picking
if(!return_list) //return a single guy
var/ckey
if(length(curr_tickets))
ckey = pickweight(curr_tickets)
SSpersistence.antag_rep_change[ckey] = -(curr_tickets[ckey] - free_tickets) //deduct what they spent
var/mind = ckey_to_mind[ckey] || (allow_zero_if_insufficient? pick(insufficient) : null) //we want their mind
if(!mind) //no mind
var/warning = "WARNING: No antagonists were successfully picked by /datum/gamemode/proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]"
message_admins(warning)
log_game(warning)
if(fail_default_pick)
mind = pick(candidates)
return mind
else //the far more efficient and proper use of this, to get a list
var/list/rolled = list()
var/list/spend_tickets = list()
for(var/i in 1 to return_list)
if(!length(curr_tickets)) //ah heck, we're out of candidates..
break
var/ckey = pickweight(curr_tickets) //pick
rolled += ckey //add
spend_tickets[ckey] = curr_tickets[ckey] - free_tickets
curr_tickets -= ckey //don't roll them again
var/missing = return_list - length(rolled)
var/list/add
if((missing > 0) && allow_zero_if_insufficient) //need more..
for(var/i in 1 to missing)
if(!length(insufficient))
break //still not enough
var/datum/mind/M = pick_n_take(insufficient)
add += M
if(!length(rolled) && !length(add)) //if no one could normally roll AND no one can zero roll
var/warning = "WARNING: No antagonists were successfully picked by /datum/gamemode/proc/antag_pick()![fail_default_pick? " Defaulting to pick()!":""]"
message_admins(warning)
log_game(warning)
var/list/failed = list()
if(fail_default_pick)
var/list/C = candidates.Copy()
for(var/i in 1 to return_list)
if(!length(C))
break
failed += pick_n_take(C)
return failed //Wew, no one qualified!
for(var/i in 1 to length(rolled))
var/ckey = rolled[i]
SSpersistence.antag_rep_change[ckey] = -(spend_tickets[ckey]) //deduct what all of the folks who rolled spent
rolled[i] = ckey_to_mind[ckey] //whoever called us wants minds, not ckeys
if(add)
rolled += add
return rolled
/datum/game_mode/proc/get_players_for_role(role)
var/list/players = list()
+3 -3
View File
@@ -25,10 +25,10 @@
// update the invisibility and icon
/obj/machinery/bluespace_beacon/hide(intact)
invisibility = intact ? INVISIBILITY_MAXIMUM : 0
updateicon()
update_icon()
// update the icon_state
/obj/machinery/bluespace_beacon/proc/updateicon()
/obj/machinery/bluespace_beacon/update_icon()
var/state="floor_beacon"
if(invisibility)
@@ -45,4 +45,4 @@
else if (Beacon.loc != loc)
Beacon.forceMove(loc)
updateicon()
update_icon()
+2
View File
@@ -181,12 +181,14 @@
open_machine()
/obj/machinery/sleeper/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)))
return
if(state_open)
close_machine()
else
open_machine()
return TRUE
/obj/machinery/sleeper/examine(mob/user)
. = ..()
+3 -2
View File
@@ -181,8 +181,9 @@ Class Procs:
if(isliving(A))
var/mob/living/L = A
L.update_canmove()
SEND_SIGNAL(src, COMSIG_MACHINE_EJECT_OCCUPANT, occupant)
occupant = null
if(occupant)
SEND_SIGNAL(src, COMSIG_MACHINE_EJECT_OCCUPANT, occupant)
occupant = null
/obj/machinery/proc/can_be_occupant(atom/movable/am)
return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)
+2 -2
View File
@@ -132,8 +132,8 @@
..()
if(!user.canUseTopic(src))
return
else
eject_part(user)
eject_part(user)
return TRUE
/obj/machinery/aug_manipulator/power_change()
..()
+27 -28
View File
@@ -28,13 +28,6 @@
QDEL_NULL(outbag)
return ..()
/obj/machinery/bloodbankgen/contents_explosion(severity, target)
..()
if(bag)
bag.ex_act(severity, target)
if(outbag)
outbag.ex_act(severity, target)
/obj/machinery/bloodbankgen/handle_atom_del(atom/A)
..()
if(A == bag)
@@ -188,7 +181,7 @@
if(user.a_intent == INTENT_HARM)
return ..()
if(default_deconstruction_screwdriver(user, "bloodbank-off", "bloodbank-off", O))
if(default_deconstruction_screwdriver(user, "bloodbank-off", "bloodbank-off", O) || default_unfasten_wrench(user, O, 20) == SUCCESSFUL_UNFASTEN)
if(bag)
var/obj/item/reagent_containers/blood/B = bag
B.forceMove(drop_location())
@@ -204,31 +197,37 @@
return
if(istype(O, /obj/item/reagent_containers/blood))
. = 1 //no afterattack
. = TRUE //no afterattack
var/msg = ""
if(!panel_open)
if(bag && outbag)
to_chat(user, "<span class='warning'>This machine already has bags attached.</span>")
if(!bag && !outbag)
var/choice = alert(user, "Choose where to place [O]", "", "Input", "Cancel", "Output")
switch(choice)
if("Cancel")
return FALSE
if("Input")
attachinput(O, user)
if("Output")
attachoutput(O, user)
else if(!bag)
attachinput(O, user)
else if(!outbag)
attachoutput(O, user)
else
to_chat(user, "<span class='warning'>Close the maintenance panel first.</span>")
return
. += "Close the maintenance panel"
if(!anchored)
. += "[msg ? " and a" : "A"]nchor its bolts"
if(length(msg))
to_chat(user, "<span class='warning'>[msg] first.</span>")
return
if(bag && outbag)
to_chat(user, "<span class='warning'>This machine already has bags attached.</span>")
if(!bag && !outbag)
var/choice = alert(user, "Choose where to place [O]", "", "Input", "Cancel", "Output")
switch(choice)
if("Cancel")
return FALSE
if("Input")
attachinput(O, user)
if("Output")
attachoutput(O, user)
else if(!bag)
attachinput(O, user)
else if(!outbag)
attachoutput(O, user)
else
to_chat(user, "<span class='warning'>You cannot put this in [src]!</span>")
/obj/machinery/bloodbankgen/is_operational()
return ..() && anchored
/obj/machinery/bloodbankgen/ui_interact(mob/user)
. = ..()
+4 -4
View File
@@ -13,7 +13,7 @@
var/chargelevel = -1
var/charge_rate = 500
/obj/machinery/cell_charger/proc/updateicon()
/obj/machinery/cell_charger/update_icon()
cut_overlays()
if(charging)
add_overlay(image(charging.icon, charging.icon_state))
@@ -53,7 +53,7 @@
charging = W
user.visible_message("[user] inserts a cell into [src].", "<span class='notice'>You insert a cell into [src].</span>")
chargelevel = -1
updateicon()
update_icon()
else
if(!charging && default_deconstruction_screwdriver(user, icon_state, icon_state, W))
return
@@ -76,7 +76,7 @@
charging.update_icon()
charging = null
chargelevel = -1
updateicon()
update_icon()
/obj/machinery/cell_charger/attack_hand(mob/user)
. = ..()
@@ -127,4 +127,4 @@
use_power(charge_rate)
charging.give(charge_rate) //this is 2558, efficient batteries exist
updateicon()
update_icon()
@@ -133,12 +133,13 @@
..()
/obj/structure/frame/computer/AltClick(mob/user)
..()
. = ..()
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(anchored)
to_chat(usr, "<span class='warning'>You must unwrench [src] before rotating it!</span>")
return
return TRUE
setDir(turn(dir, -90))
return TRUE
+3 -3
View File
@@ -170,19 +170,19 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
return TRUE
/obj/machinery/computer/card/AltClick(mob/user)
..()
. = ..()
if(!user.canUseTopic(src, !issilicon(user)) || !is_operational())
return
if(inserted_modify_id)
if(id_eject(user, inserted_modify_id))
inserted_modify_id = null
updateUsrDialog()
return
return TRUE
if(inserted_scan_id)
if(id_eject(user, inserted_scan_id))
inserted_scan_id = null
updateUsrDialog()
return
return TRUE
/obj/machinery/computer/card/ui_interact(mob/user)
. = ..()
@@ -74,8 +74,8 @@
t += "<A href='?src=[REF(src)];lowery=1;raisex=1;pad=[current_pad]'>O</A><BR>"//down-right
t += "<BR>"
t += "<div class='statusDisplay'>Current offset:</div><BR>"
t += "<div class='statusDisplay'>[abs(pad.y_offset)] [pad.y_offset > 0 ? "N":"S"]</div><BR>"
t += "<div class='statusDisplay'>[abs(pad.x_offset)] [pad.x_offset > 0 ? "E":"W"]</div><BR>"
t += "<div class='statusDisplay'>[abs(pad.y_offset)] [pad.y_offset > 0 ? "N":"S"] <a href='?src=[REF(src)];sety=1;pad=[current_pad]'>\[SET\]</a></div><BR>"
t += "<div class='statusDisplay'>[abs(pad.x_offset)] [pad.x_offset > 0 ? "E":"W"] <a href='?src=[REF(src)];setx=1;pad=[current_pad]'>\[SET\]</a></div><BR>"
t += "<BR><A href='?src=[REF(src)];launch=1;pad=[current_pad]'>Launch</A>"
t += " <A href='?src=[REF(src)];pull=1;pad=[current_pad]'>Pull</A>"
@@ -132,6 +132,16 @@
if(!new_name)
return
pad.display_name = new_name
if(href_list["setx"])
var/newx = input(usr, "Input new x offset", pad.display_name, pad.x_offset) as null|num
if(!isnull(newx))
pad.x_offset = CLAMP(newx, -pad.range, pad.range)
if(href_list["sety"])
var/newy = input(usr, "Input new y offset", pad.display_name, pad.y_offset) as null|num
if(!isnull(newy))
pad.y_offset = CLAMP(newy, -pad.range, pad.range)
if(href_list["remove"])
if(usr && alert(usr, "Are you sure?", "Remove Launchpad", "I'm Sure", "Abort") != "Abort")
@@ -145,4 +155,4 @@
sending = FALSE
teleport(usr, pad)
updateDialog()
updateDialog()
@@ -5,7 +5,7 @@
if(contained_id)
contained_id.forceMove(get_turf(src))
return ..()
/obj/machinery/computer/prisoner/examine(mob/user)
. = ..()
@@ -15,8 +15,9 @@
/obj/machinery/computer/prisoner/AltClick(mob/user)
..()
id_eject(user)
return ..()
return TRUE
/obj/machinery/computer/prisoner/proc/id_insert(mob/user, obj/item/card/id/prisoner/P)
if(istype(P))
@@ -115,8 +115,10 @@
return TRUE
/obj/machinery/defibrillator_mount/AltClick(mob/living/carbon/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return
. = TRUE
if(!defib)
to_chat(user, "<span class='warning'>It'd be hard to remove a defib unit from a mount that has none.</span>")
return
+2
View File
@@ -153,9 +153,11 @@
. += "<span class='notice'>Alt-click to toggle modes.</span>"
/obj/item/grenade/barrier/AltClick(mob/living/carbon/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return
toggle_mode(user)
return TRUE
/obj/item/grenade/barrier/proc/toggle_mode(mob/user)
switch(mode)
+2
View File
@@ -97,8 +97,10 @@
do_the_dishes(TRUE)
/obj/machinery/dish_drive/AltClick(mob/living/user)
. = ..()
if(user.canUseTopic(src, !issilicon(user)))
do_the_dishes(TRUE)
return TRUE
/obj/machinery/dish_drive/proc/do_the_dishes(manual)
if(!contents.len)
+2
View File
@@ -164,9 +164,11 @@
toggle_open(user)
/obj/machinery/dna_scannernew/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)))
return
interact(user)
return TRUE
/obj/machinery/dna_scannernew/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
+1 -1
View File
@@ -22,7 +22,7 @@
if(voice_activated)
flags_1 |= HEAR_1
/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/obj/machinery/door/password/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(!density || !voice_activated || radio_freq)
return
+2
View File
@@ -51,10 +51,12 @@
open_machine()
/obj/machinery/harvester/AltClick(mob/user)
. = ..()
if(harvesting || !user || !isliving(user) || state_open)
return
if(can_harvest())
start_harvest()
return TRUE
/obj/machinery/harvester/proc/can_harvest()
if(!powered(EQUIP) || state_open || !occupant || !iscarbon(occupant))
+2 -2
View File
@@ -408,7 +408,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
for(var/mob/living/silicon/ai/master in masters)
@@ -418,7 +418,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src && speaker != HC.hologram)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, source)
if(outgoing_call && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message)
+5 -5
View File
@@ -21,9 +21,9 @@
name = "light switch ([area.name])"
on = area.lightswitch
updateicon()
update_icon()
/obj/machinery/light_switch/proc/updateicon()
/obj/machinery/light_switch/update_icon()
if(stat & NOPOWER)
icon_state = "light-p"
else
@@ -41,11 +41,11 @@
on = !on
area.lightswitch = on
area.updateicon()
area.update_icon()
for(var/obj/machinery/light_switch/L in area)
L.on = on
L.updateicon()
L.update_icon()
area.power_change()
@@ -57,7 +57,7 @@
else
stat |= NOPOWER
updateicon()
update_icon()
/obj/machinery/light_switch/emp_act(severity)
. = ..()
+3 -3
View File
@@ -46,10 +46,10 @@
// update the invisibility and icon
/obj/machinery/magnetic_module/hide(intact)
invisibility = intact ? INVISIBILITY_MAXIMUM : 0
updateicon()
update_icon()
// update the icon_state
/obj/machinery/magnetic_module/proc/updateicon()
/obj/machinery/magnetic_module/update_icon()
var/state="floor_magnet"
var/onstate=""
if(!on)
@@ -161,7 +161,7 @@
else
use_power = NO_POWER_USE
updateicon()
update_icon()
/obj/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the magneting
+3 -3
View File
@@ -72,10 +72,10 @@
// hide the object if turf is intact
/obj/machinery/navbeacon/hide(intact)
invisibility = intact ? INVISIBILITY_MAXIMUM : 0
updateicon()
update_icon()
// update the icon_state
/obj/machinery/navbeacon/proc/updateicon()
/obj/machinery/navbeacon/update_icon()
var/state="navbeacon[open]"
if(invisibility)
@@ -94,7 +94,7 @@
user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "<span class='notice'>You [open ? "open" : "close"] the beacon's cover.</span>")
updateicon()
update_icon()
else if (istype(I, /obj/item/card/id)||istype(I, /obj/item/pda))
if(open)
+4 -2
View File
@@ -16,6 +16,7 @@
. += "<span class='notice'>Alt-click it to start a wash cycle.</span>"
/obj/machinery/washing_machine/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src))
return
@@ -24,11 +25,11 @@
if(state_open)
to_chat(user, "<span class='notice'>Close the door first</span>")
return
return TRUE
if(bloody_mess)
to_chat(user, "<span class='warning'>[src] must be cleaned up first.</span>")
return
return TRUE
if(has_corgi)
bloody_mess = 1
@@ -37,6 +38,7 @@
update_icon()
addtimer(CALLBACK(src, .proc/wash_cycle), 200)
START_PROCESSING(SSfastprocess, src)
return TRUE
/obj/machinery/washing_machine/process()
if (!busy)
+1
View File
@@ -27,6 +27,7 @@
max_temperature = 35000
leg_overload_coeff = 100
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/gygax/dark
max_equip = 4
spawn_tracked = FALSE
+1
View File
@@ -10,6 +10,7 @@
max_temperature = 25000
infra_luminosity = 5
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS)
wreckage = /obj/structure/mecha_wreckage/honker
add_req_access = 0
max_equip = 3
+3
View File
@@ -10,6 +10,7 @@
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
infra_luminosity = 3
operation_req_access = list(ACCESS_CENT_SPECOPS)
internals_req_access = list(ACCESS_CENT_SPECOPS, ACCESS_ROBOTICS)
wreckage = /obj/structure/mecha_wreckage/marauder
add_req_access = 0
internal_damage_threshold = 25
@@ -46,6 +47,7 @@
name = "\improper Seraph"
icon_state = "seraph"
operation_req_access = list(ACCESS_CENT_SPECOPS)
internals_req_access = list(ACCESS_CENT_SPECOPS, ACCESS_ROBOTICS)
step_in = 3
max_integrity = 550
wreckage = /obj/structure/mecha_wreckage/seraph
@@ -72,6 +74,7 @@
name = "\improper Mauler"
icon_state = "mauler"
operation_req_access = list(ACCESS_SYNDICATE)
internals_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/mauler
max_equip = 5
+3 -1
View File
@@ -12,6 +12,8 @@
layer = ABOVE_MOB_LAYER
breach_time = 100 //ten seconds till all goes to shit
recharge_rate = 100
internals_req_access = list()
add_req_access = 0
wreckage = /obj/structure/mecha_wreckage/durand/neovgre
spawn_tracked = FALSE
@@ -47,7 +49,7 @@
for(var/mob/M in src)
to_chat(M, "<span class='brass'>You are consumed by the fires raging within Neovgre...</span>")
M.dust()
playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, 0)
playsound(src, 'sound/effects/neovgre_exploding.ogg', 100, 0)
src.visible_message("<span class = 'userdanger'>The reactor has gone critical, its going to blow!</span>")
addtimer(CALLBACK(src,.proc/go_critical),breach_time)
+1
View File
@@ -10,6 +10,7 @@
max_temperature = 15000
wreckage = /obj/structure/mecha_wreckage/reticence
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS)
add_req_access = 0
internal_damage_threshold = 25
max_equip = 2
+2 -2
View File
@@ -68,7 +68,7 @@
var/internal_damage = 0 //contains bitflags
var/list/operation_req_access = list()//required access level for mecha operation
var/list/internals_req_access = list(ACCESS_ENGINE,ACCESS_ROBOTICS)//REQUIRED ACCESS LEVEL TO OPEN CELL COMPARTMENT
var/list/internals_req_access = list(ACCESS_ROBOTICS)//REQUIRED ACCESS LEVEL TO OPEN CELL COMPARTMENT
var/wreckage
@@ -409,7 +409,7 @@
/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits.
return
/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/obj/mecha/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(speaker == occupant)
if(radio.broadcasting)
+2
View File
@@ -138,8 +138,10 @@
chassis.toggle_strafe()
/obj/mecha/AltClick(mob/living/user)
. = ..()
if((user == occupant) && user.canUseTopic(src))
toggle_strafe()
return TRUE
/obj/mecha/proc/toggle_strafe()
strafe = !strafe
@@ -442,3 +442,10 @@
animate(src, alpha = 0, transform = skew, time = duration)
else
return INITIALIZE_HINT_QDEL
/obj/effect/temp_visual/slugboom
icon = 'icons/effects/96x96.dmi'
icon_state = "slugboom"
randomdir = FALSE
duration = 30
pixel_x = -24
@@ -36,3 +36,7 @@
/obj/effect/projectile/impact/wormhole
icon_state = "wormhole_g"
/obj/effect/projectile/impact/laser/wavemotion
name = "particle impact"
icon_state = "impact_wavemotion"
@@ -28,3 +28,7 @@
/obj/effect/projectile/muzzle/wormhole
icon_state = "wormhole_g"
/obj/effect/projectile/muzzle/laser/wavemotion
name = "particle backblast"
icon_state = "muzzle_wavemotion"
@@ -66,3 +66,7 @@
/obj/effect/projectile/tracer/wormhole
icon_state = "wormhole_g"
/obj/effect/projectile/tracer/laser/wavemotion
name = "particle trail"
icon_state = "tracer_wavemotion"
+14 -19
View File
@@ -133,15 +133,14 @@ RLD
if(!(A in range(custom_range, get_turf(user))))
to_chat(user, "<span class='warning'>The \'Out of Range\' light on [src] blinks red.</span>")
return FALSE
else
return TRUE
/obj/item/construction/proc/prox_check(proximity)
if(proximity)
return TRUE
else
var/view_range = user.client ? user.client.view : world.view
//if user can't be seen from A (only checks surroundings' opaqueness) and can't see A.
//jarring, but it should stop people from targetting atoms they can't see...
//excluding darkness, to allow RLD to be used to light pitch black dark areas.
if(!((user in view(view_range, A)) || (user in viewers(view_range, A))))
to_chat(user, "<span class='warning'>You focus, pointing \the [src] at whatever outside your field of vision in the given direction... to no avail.</span>")
return FALSE
return TRUE
/obj/item/construction/rcd
name = "rapid-construction-device (RCD)"
@@ -523,7 +522,12 @@ RLD
/obj/item/construction/rcd/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!prox_check(proximity))
if(!proximity)
if(!ranged || !range_check(A,user)) //early return not-in-range sanity.
return
if(target_check(A,user))
user.Beam(A,icon_state="rped_upgrade",time=30)
rcd_create(A,user)
return
rcd_create(A, user)
@@ -635,6 +639,7 @@ RLD
max_matter = INFINITY
matter = INFINITY
upgrade = TRUE
ranged = TRUE
// Ranged RCD
@@ -650,20 +655,10 @@ RLD
item_state = "oldrcd"
has_ammobar = FALSE
/obj/item/construction/rcd/arcd/afterattack(atom/A, mob/user)
. = ..()
if(!range_check(A,user))
return
if(target_check(A,user))
user.Beam(A,icon_state="rped_upgrade",time=30)
rcd_create(A,user)
// RAPID LIGHTING DEVICE
/obj/item/construction/rld
name = "rapid-light-device (RLD)"
desc = "A device used to rapidly provide lighting sources to an area. Reload with metal, plasteel, glass or compressed matter cartridges."
+4 -3
View File
@@ -517,16 +517,17 @@ update_label("John Doe", "Clowny")
return
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
return TRUE
if(alert("Are you sure you want to recolor your id?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"","Choose Energy Color",id_color) as color|null
if(!in_range(src, user) || !energy_color_input)
return
return TRUE
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
return TRUE
id_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
return TRUE
/obj/item/card/id/knight/Initialize()
. = ..()
@@ -945,10 +945,12 @@
to_chat(user, "<span class='notice'>You [suction ? "enable" : "disable"] the board's suction function.</span>")
/obj/item/circuitboard/machine/dish_drive/AltClick(mob/living/user)
. = ..()
if(!user.Adjacent(src))
return
transmit = !transmit
to_chat(user, "<span class='notice'>You [transmit ? "enable" : "disable"] the board's automatic disposal transmission.</span>")
return TRUE
/obj/item/circuitboard/machine/stacking_unit_console
name = "Stacking Machine Console (Machine Board)"
+2
View File
@@ -150,11 +150,13 @@
ui.open()
/obj/item/toy/crayon/spraycan/AltClick(mob/user)
. = ..()
if(user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
if(has_cap)
is_capped = !is_capped
to_chat(user, "<span class='notice'>The cap on [src] is now [is_capped ? "on" : "off"].</span>")
update_icon()
return TRUE
/obj/item/toy/crayon/proc/staticDrawables()
+10 -5
View File
@@ -27,6 +27,8 @@
var/pullshocksafely = FALSE //Dose the unit have the healdisk upgrade?
var/primetime = 0 // is the defib faster
var/timedeath = 10
var/disarm_shock_time = 10
var/always_emagged = FALSE
/obj/item/defibrillator/get_cell()
return cell
@@ -140,6 +142,7 @@
/obj/item/defibrillator/emag_act(mob/user)
. = ..()
always_emagged = TRUE
safety = !safety
to_chat(user, "<span class='warning'>You silently [safety ? "enable" : "disable"] [src]'s safety protocols with the cryptographic sequencer.</span>")
return TRUE
@@ -154,7 +157,7 @@
safety = FALSE
visible_message("<span class='notice'>[src] beeps: Safety protocols disabled!</span>")
playsound(src, 'sound/machines/defib_saftyOff.ogg', 50, 0)
else
else if(!always_emagged)
safety = TRUE
visible_message("<span class='notice'>[src] beeps: Safety protocols enabled!</span>")
playsound(src, 'sound/machines/defib_saftyOn.ogg', 50, 0)
@@ -257,6 +260,8 @@
desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
combat = TRUE
safety = FALSE
always_emagged = TRUE
disarm_shock_time = 0
/obj/item/defibrillator/compact/combat/loaded/Initialize()
. = ..()
@@ -293,6 +298,7 @@
var/combat = FALSE //If it penetrates armor and gives additional functionality
var/grab_ghost = FALSE
var/tlimit = DEFIB_TIME_LIMIT * 10
var/disarm_shock_time = 10
var/mob/listeningTo
@@ -467,7 +473,7 @@
M.visible_message("<span class='danger'>[user] hastily places [src] on [M]'s chest!</span>", \
"<span class='userdanger'>[user] hastily places [src] on [M]'s chest!</span>")
busy = TRUE
if(do_after(user, 10, target = M))
if(do_after(user, isnull(defib?.disarm_shock_time)? disarm_shock_time : defib.disarm_shock_time, target = M))
M.visible_message("<span class='danger'>[user] zaps [M] with [src]!</span>", \
"<span class='userdanger'>[user] zaps [M] with [src]!</span>")
M.adjustStaminaLoss(50)
@@ -734,9 +740,8 @@
/obj/item/disk/medical
name = "Defibrillator Upgrade Disk"
desc = "A blank upgrade disk, made for a defibrillator"
icon = 'modular_citadel/icons/obj/defib_disks.dmi'
icon_state = "upgrade_disk"
item_state = "heal_disk"
icon_state = "heal_disk"
item_state = "defib_disk"
w_class = WEIGHT_CLASS_SMALL
/obj/item/disk/medical/defib_heal
+2 -2
View File
@@ -828,14 +828,14 @@ GLOBAL_LIST_EMPTY(PDAs)
send_message(U,list(P))
/obj/item/pda/AltClick()
..()
. = ..()
if(id)
remove_id()
playsound(src, 'sound/machines/terminal_eject_disc.ogg', 50, 1)
else
remove_pen()
playsound(src, 'sound/machines/button4.ogg', 50, 1)
return TRUE
/obj/item/pda/CtrlClick()
..()
@@ -32,6 +32,7 @@
. += "<span class='notice'>Can be used again to interrupt the effect early. The recharge time is the same as the time spent in desync.</span>"
/obj/item/desynchronizer/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
var/new_duration = input(user, "Set the duration (5-300):", "Desynchronizer", duration / 10) as null|num
@@ -40,6 +41,7 @@
new_duration = CLAMP(new_duration, 50, max_duration)
duration = new_duration
to_chat(user, "<span class='notice'>You set the duration to [DisplayTimeText(duration)].</span>")
return TRUE
/obj/item/desynchronizer/proc/desync(mob/living/user)
if(sync_holder)
@@ -153,6 +153,7 @@
playsound(loc, voracious ? 'sound/effects/splat.ogg' : 'sound/effects/bin_close.ogg', 50, 1)
items_preserved.Cut()
cleaning = FALSE
patient = null
if(hound)
update_gut(hound)
@@ -525,5 +526,5 @@
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
/obj/item/dogborg/sleeper/K9/flavour
name = "Mobile Sleeper"
name = "Recreational Sleeper"
desc = "A mounted, underslung sleeper, intended for holding willing occupants for leisurely purposes."
@@ -182,14 +182,16 @@
return ..()
/obj/item/geiger_counter/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return ..()
return
if(!scanning)
to_chat(usr, "<span class='warning'>[src] must be on to reset its radiation level!</span>")
return 0
return TRUE
radiation_count = 0
to_chat(usr, "<span class='notice'>You flush [src]'s radiation counts, resetting it to normal.</span>")
update_icon()
return TRUE
/obj/item/geiger_counter/emag_act(mob/user)
. = ..()
+2
View File
@@ -45,9 +45,11 @@ GLOBAL_LIST_EMPTY(GPS_list)
add_overlay("working")
/obj/item/gps/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE))
return
toggletracking(user)
return TRUE
/obj/item/gps/proc/toggletracking(mob/user)
if(!user.canUseTopic(src, BE_CLOSE))
@@ -69,14 +69,9 @@
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if(HAS_TRAIT(user, TRAIT_NOGUNS))
if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
to_chat(user, "<span class='warning'>Your fingers can't press the button!</span>")
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna.check_mutation(HULK))
to_chat(user, "<span class='warning'>Your fingers can't press the button!</span>")
return
add_fingerprint(user)
@@ -18,12 +18,14 @@
. += "<span class='notice'>Insert [src] into an active quantum pad to link it.</span>"
/obj/item/quantum_keycard/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
to_chat(user, "<span class='notice'>You start pressing [src]'s unlink button...</span>")
if(do_after(user, 40, target = src))
to_chat(user, "<span class='notice'>The keycard beeps twice and disconnects the quantum link.</span>")
qpad = null
return TRUE
/obj/item/quantum_keycard/update_icon()
if(qpad)
@@ -326,8 +326,10 @@ GLOBAL_LIST_INIT(channel_tokens, list(
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
/obj/item/radio/headset/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !Adjacent(user) || user.incapacitated())
return
if (command)
use_command = !use_command
to_chat(user, "<span class='notice'>You toggle high-volume mode [use_command ? "on" : "off"].</span>")
return TRUE
@@ -113,7 +113,7 @@
return TRUE
/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode)
/obj/item/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if (message_mode == MODE_INTERCOM)
return // Avoid hearing the same thing twice
@@ -274,7 +274,7 @@
signal.levels = list(T.z)
signal.broadcast()
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
return
+8 -8
View File
@@ -412,7 +412,7 @@ SLIME SCANNER
if(ishuman(C))
if(H.bleed_rate)
msg += "<span class='danger'>Subject is bleeding!</span>\n"
var/blood_percent = round((C.blood_volume / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
var/blood_percent = round((C.scan_blood_volume() / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
var/blood_type = C.dna.blood_type
if(blood_id != ("blood" || "jellyblood"))//special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
@@ -420,12 +420,12 @@ SLIME SCANNER
blood_type = R.name
else
blood_type = blood_id
if(C.blood_volume <= (BLOOD_VOLUME_SAFE*C.blood_ratio) && C.blood_volume > (BLOOD_VOLUME_OKAY*C.blood_ratio))
msg += "<span class='danger'>LOW blood level [blood_percent] %, [C.blood_volume] cl,</span> <span class='info'>type: [blood_type]</span>\n"
else if(C.blood_volume <= (BLOOD_VOLUME_OKAY*C.blood_ratio))
msg += "<span class='danger'>CRITICAL blood level [blood_percent] %, [C.blood_volume] cl,</span> <span class='info'>type: [blood_type]</span>\n"
if(C.scan_blood_volume() <= (BLOOD_VOLUME_SAFE*C.blood_ratio) && C.scan_blood_volume() > (BLOOD_VOLUME_OKAY*C.blood_ratio))
msg += "<span class='danger'>LOW blood level [blood_percent] %, [C.scan_blood_volume()] cl,</span> <span class='info'>type: [blood_type]</span>\n"
else if(C.scan_blood_volume() <= (BLOOD_VOLUME_OKAY*C.blood_ratio))
msg += "<span class='danger'>CRITICAL blood level [blood_percent] %, [C.scan_blood_volume()] cl,</span> <span class='info'>type: [blood_type]</span>\n"
else
msg += "<span class='info'>Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]</span>\n"
msg += "<span class='info'>Blood level [blood_percent] %, [C.scan_blood_volume()] cl, type: [blood_type]</span>\n"
var/cyberimp_detect
for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
@@ -590,10 +590,10 @@ SLIME SCANNER
to_chat(user, "<span class='info'>Temperature: [round(environment.temperature-T0C, 0.01)] &deg;C ([round(environment.temperature, 0.01)] K)</span>")
/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
..()
. = ..()
if(user.canUseTopic(src))
. = TRUE
if(cooldown)
to_chat(user, "<span class='warning'>[src]'s barometer function is preparing itself.</span>")
return
@@ -94,7 +94,7 @@
icon_state = "taperecorder_idle"
/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
/obj/item/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
. = ..()
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
+1 -1
View File
@@ -122,7 +122,7 @@
interact(user)
return ..()
/obj/item/toy/eightball/haunted/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode)
/obj/item/toy/eightball/haunted/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, message_mode, atom/movable/source)
. = ..()
last_message = raw_message
+2
View File
@@ -138,11 +138,13 @@
toggle_igniter(user)
/obj/item/flamethrower/AltClick(mob/user)
. = ..()
if(ptank && isliving(user) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
user.put_in_hands(ptank)
ptank = null
to_chat(user, "<span class='notice'>You remove the plasma tank from [src]!</span>")
update_icon()
return TRUE
/obj/item/flamethrower/examine(mob/user)
. = ..()
+17
View File
@@ -183,6 +183,23 @@
explosion(user.loc, 1, 0, 2, 3, FALSE, FALSE, 2)
qdel(src)
/obj/item/book/granter/spell/nuclearfist
spell = /obj/effect/proc_holder/spell/targeted/touch/nuclear_fist
spellname = "nuclear fist"
icon_state ="booknuclearfist"
desc = "This book radiates confidence."
remarks = list("Line them up....", ".. knock em' down...", "Dress in yellow for maximum effect... why?", "The energy comes from spinach... huh", "Work out for three years? No way!", "Oh I'll cast you a spell allright...", "What ho mighty wizard... ho ho ho...")
/obj/item/book/granter/spell/nuclearfist/recoil(mob/living/carbon/user)
..()
to_chat(user, "<span class='danger'>Your arm spontaneously detonates!</span>")
explosion(user.loc, -1, 0, 2, -1, FALSE, FALSE, 2)
var/obj/item/bodypart/part = user.get_holding_bodypart_of_item(src)
if(part)
part.dismember()
qdel(part)
/obj/item/book/granter/spell/sacredflame
spell = /obj/effect/proc_holder/spell/targeted/sacred_flame
spellname = "sacred flame"
@@ -26,6 +26,9 @@
if(target.mind.has_antag_datum(/datum/antagonist/brainwashed))
target.mind.remove_antag_datum(/datum/antagonist/brainwashed)
if(target.mind.has_antag_datum(ANTAG_DATUM_VASSAL))
SSticker.mode.remove_vassal(target.mind)
if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.unconvertable || target.mind.has_antag_datum(/datum/antagonist/gang/boss))
if(!silent)
target.visible_message("<span class='warning'>[target] seems to resist the implant!</span>", "<span class='warning'>You feel something interfering with your mental conditioning, but you resist it!</span>")
+3 -1
View File
@@ -320,11 +320,12 @@
M.update_inv_hands()
/obj/item/melee/transforming/energy/sword/cx/AltClick(mob/living/user)
. = ..()
if(!in_range(src, user)) //Basic checks to prevent abuse
return
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
return TRUE
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"","Choose Energy Color",light_color) as color|null
@@ -332,6 +333,7 @@
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
return TRUE
/obj/item/melee/transforming/energy/sword/cx/examine(mob/user)
. = ..()
+6 -6
View File
@@ -79,17 +79,17 @@
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
/obj/item/melee/sabre/on_exit_storage(obj/item/storage/S)
..()
var/obj/item/storage/belt/sabre/B = S
/obj/item/melee/sabre/on_exit_storage(datum/component/storage/S)
var/obj/item/storage/belt/sabre/B = S.parent
if(istype(B))
playsound(B, 'sound/items/unsheath.ogg', 25, 1)
/obj/item/melee/sabre/on_enter_storage(obj/item/storage/S)
..()
var/obj/item/storage/belt/sabre/B = S
/obj/item/melee/sabre/on_enter_storage(datum/component/storage/S)
var/obj/item/storage/belt/sabre/B = S.parent
if(istype(B))
playsound(B, 'sound/items/sheath.ogg', 25, 1)
..()
/obj/item/melee/sabre/get_belt_overlay()
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "sabre")
+2
View File
@@ -70,6 +70,7 @@
update_icon()
/obj/item/pet_carrier/AltClick(mob/living/user)
. = ..()
if(open || !user.canUseTopic(src, BE_CLOSE))
return
locked = !locked
@@ -79,6 +80,7 @@
else
playsound(user, 'sound/machines/boltsup.ogg', 30, TRUE)
update_icon()
return TRUE
/obj/item/pet_carrier/attack(mob/living/target, mob/living/user)
if(user.a_intent == INTENT_HARM)
+3 -4
View File
@@ -213,7 +213,7 @@
loadedWeightClass -= I.w_class
else if (A == tank)
tank = null
update_icons()
update_icon()
/obj/item/pneumatic_cannon/ghetto //Obtainable by improvised methods; more gas per use, less capacity, but smaller
name = "improvised pneumatic cannon"
@@ -239,14 +239,13 @@
return
to_chat(user, "<span class='notice'>You hook \the [thetank] up to \the [src].</span>")
tank = thetank
update_icons()
update_icon()
/obj/item/pneumatic_cannon/proc/update_icons()
/obj/item/pneumatic_cannon/update_icon()
cut_overlays()
if(!tank)
return
add_overlay(tank.icon_state)
update_icon()
/obj/item/pneumatic_cannon/proc/fill_with_type(type, amount)
if(!ispath(type, /obj) && !ispath(type, /mob))
+9 -9
View File
@@ -24,7 +24,7 @@
/obj/item/robot_suit/New()
..()
updateicon()
update_icon()
/obj/item/robot_suit/prebuilt/New()
l_arm = new(src)
@@ -39,7 +39,7 @@
chest.cell = new /obj/item/stock_parts/cell/high/plus(chest)
..()
/obj/item/robot_suit/proc/updateicon()
/obj/item/robot_suit/update_icon()
cut_overlays()
if(l_arm)
add_overlay("[l_arm.icon_state]+o")
@@ -96,7 +96,7 @@
to_chat(user, "<span class='notice'>You disassemble the cyborg shell.</span>")
else
to_chat(user, "<span class='notice'>There is nothing to remove from the endoskeleton.</span>")
updateicon()
update_icon()
/obj/item/robot_suit/proc/put_in_hand_or_drop(mob/living/user, obj/item/I) //normal put_in_hands() drops the item ontop of the player, this drops it at the suit's loc
if(!user.put_in_hands(I))
@@ -160,7 +160,7 @@
W.icon_state = initial(W.icon_state)
W.cut_overlays()
src.l_leg = W
src.updateicon()
update_icon()
else if(istype(W, /obj/item/bodypart/r_leg/robot))
if(src.r_leg)
@@ -170,7 +170,7 @@
W.icon_state = initial(W.icon_state)
W.cut_overlays()
src.r_leg = W
src.updateicon()
update_icon()
else if(istype(W, /obj/item/bodypart/l_arm/robot))
if(src.l_arm)
@@ -180,7 +180,7 @@
W.icon_state = initial(W.icon_state)
W.cut_overlays()
src.l_arm = W
src.updateicon()
update_icon()
else if(istype(W, /obj/item/bodypart/r_arm/robot))
if(src.r_arm)
@@ -190,7 +190,7 @@
W.icon_state = initial(W.icon_state)//in case it is a dismembered robotic limb
W.cut_overlays()
src.r_arm = W
src.updateicon()
update_icon()
else if(istype(W, /obj/item/bodypart/chest/robot))
var/obj/item/bodypart/chest/robot/CH = W
@@ -202,7 +202,7 @@
CH.icon_state = initial(CH.icon_state) //in case it is a dismembered robotic limb
CH.cut_overlays()
src.chest = CH
src.updateicon()
update_icon()
else if(!CH.wired)
to_chat(user, "<span class='warning'>You need to attach wires to it first!</span>")
else
@@ -222,7 +222,7 @@
HD.icon_state = initial(HD.icon_state)//in case it is a dismembered robotic limb
HD.cut_overlays()
src.head = HD
src.updateicon()
update_icon()
else
to_chat(user, "<span class='warning'>You need to attach a flash to it first!</span>")
@@ -74,7 +74,7 @@
/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R, user = usr)
. = ..()
if(.)
if(R.speed < 0)
if(!R.cansprint)
to_chat(R, "<span class='notice'>A VTEC unit is already installed!</span>")
to_chat(user, "<span class='notice'>There's no room for another VTEC unit!</span>")
return FALSE
@@ -82,11 +82,13 @@
//R.speed = -2 // Gotta go fast.
//Citadel change - makes vtecs give an ability rather than reducing the borg's speed instantly
R.AddAbility(new/obj/effect/proc_holder/silicon/cyborg/vtecControl)
R.cansprint = 0
/obj/item/borg/upgrade/vtec/deactivate(mob/living/silicon/robot/R, user = usr)
. = ..()
if (.)
R.speed = initial(R.speed)
R.cansprint = 1
/obj/item/borg/upgrade/disablercooler
name = "cyborg rapid energy blaster cooling module"
@@ -409,8 +411,7 @@
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical,
/obj/item/robot_module/medihound)
/obj/item/robot_module/syndicate_medical)
var/list/additional_reagents = list()
/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr)
@@ -466,23 +467,6 @@
for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
H.bypass_protection = initial(H.bypass_protection)
/obj/item/borg/upgrade/defib
name = "medical cyborg defibrillator"
desc = "An upgrade to the Medical module, installing a built-in \
defibrillator, for on the scene revival."
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical,
/obj/item/robot_module/medihound)
/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr)
. = ..()
if(.)
var/obj/item/twohanded/shockpaddles/cyborg/S = new(R.module)
R.module.basic_modules += S
R.module.add_module(S, FALSE, TRUE)
/obj/item/borg/upgrade/defib/deactivate(mob/living/silicon/robot/R, user = usr)
. = ..()
if (.)
@@ -497,8 +481,7 @@
icon_state = "cyborg_upgrade3"
require_module = 1
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical,
/obj/item/robot_module/medihound)
/obj/item/robot_module/syndicate_medical)
/obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -521,8 +504,7 @@
require_module = 1
module_type = list(
/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical,
/obj/item/robot_module/medihound)
/obj/item/robot_module/syndicate_medical)
/obj/item/borg/upgrade/advhealth/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -642,8 +624,7 @@
icon_state = "pinpointer_crew"
require_module = TRUE
module_type = list(/obj/item/robot_module/medical,
/obj/item/robot_module/syndicate_medical,
/obj/item/robot_module/medihound)
/obj/item/robot_module/syndicate_medical)
/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr)
. = ..()
@@ -39,6 +39,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
/obj/item/stack/sheet/glass/fifty
amount = 50
/obj/item/stack/sheet/glass/five
amount = 5
/obj/item/stack/sheet/glass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.glass_recipes
return ..()
@@ -55,6 +55,9 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
/obj/item/stack/sheet/mineral/sandstone/thirty
amount = 30
/obj/item/stack/sheet/mineral/sandstone/twelve
amount = 12
/*
* Sandbags
*/
@@ -228,7 +228,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
/obj/item/stack/sheet/mineral/wood
name = "wooden plank"
desc = "One can only guess that this is a bunch of wood."
desc = "One can only guess that this is a bunch of wood. You might be able to make a stake with this if you use something sharp on it"
singular_name = "wood plank"
icon_state = "sheet-wood"
item_state = "sheet-wood"
@@ -240,6 +240,35 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
novariants = TRUE
grind_results = list("carbon" = 20)
/obj/item/stack/sheet/mineral/wood/attackby(obj/item/W, mob/user, params) // NOTE: sheet_types.dm is where the WOOD stack lives. Maybe move this over there.
// Taken from /obj/item/stack/rods/attackby in [rods.dm]
if(W.get_sharpness())
user.visible_message("[user] begins whittling [src] into a pointy object.", \
"<span class='notice'>You begin whittling [src] into a sharp point at one end.</span>", \
"<span class='italics'>You hear wood carving.</span>")
// 8 Second Timer
if(!do_after(user, 80, TRUE, src))
return
// Make Stake
var/obj/item/stake/basic/new_item = new(user.loc)
user.visible_message("[user] finishes carving a stake out of [src].", \
"<span class='notice'>You finish carving a stake out of [src].</span>")
// Prepare to Put in Hands (if holding wood)
var/obj/item/stack/sheet/mineral/wood/N = src
var/replace = (user.get_inactive_held_item() == N)
// Use Wood
N.use(1)
// If stack depleted, put item in that hand (if it had one)
if (!N && replace)
user.put_in_hands(new_item)
if(istype(W, merge_type))
var/obj/item/stack/S = W
if(merge(S))
to_chat(user, "<span class='notice'>Your [S.name] stack now contains [S.get_amount()] [S.singular_name]\s.</span>")
else
. = ..()
/obj/item/stack/sheet/mineral/wood/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.wood_recipes
return ..()
@@ -247,6 +276,33 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
/obj/item/stack/sheet/mineral/wood/fifty
amount = 50
/*
* Bamboo
*/
GLOBAL_LIST_INIT(bamboo_recipes, list ( \
new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 30, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 70), \
))
/obj/item/stack/sheet/mineral/bamboo
name = "bamboo cuttings"
desc = "Finely cut bamboo sticks."
singular_name = "cut bamboo"
icon_state = "sheet-bamboo"
item_state = "sheet-bamboo"
icon = 'icons/obj/stack_objects.dmi'
throwforce = 15
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/mineral/bamboo
grind_results = list("carbon" = 5)
/obj/item/stack/sheet/mineral/bamboo/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.bamboo_recipes
return ..()
/*
* Cloth
*/
@@ -696,5 +752,3 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
merge_type = /obj/item/stack/sheet/cotton/durathread
pull_effort = 70
loom_result = /obj/item/stack/sheet/durathread
+3 -1
View File
@@ -350,6 +350,7 @@
. = ..()
/obj/item/stack/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(is_cyborg)
@@ -363,10 +364,11 @@
max = get_amount()
stackmaterial = min(max, stackmaterial)
if(stackmaterial == null || stackmaterial <= 0 || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
return TRUE
else
change_stack(user, stackmaterial)
to_chat(user, "<span class='notice'>You take [stackmaterial] sheets out of the stack</span>")
return TRUE
/obj/item/stack/proc/change_stack(mob/user, amount)
if(!use(amount, TRUE, FALSE))
+1 -11
View File
@@ -757,23 +757,13 @@
STR.rustle_sound = FALSE
STR.max_w_class = WEIGHT_CLASS_BULKY
STR.can_hold = typecacheof(fitting_swords)
STR.quickdraw = TRUE
/obj/item/storage/belt/sabre/examine(mob/user)
. = ..()
if(length(contents))
. += "<span class='notice'>Alt-click it to quickly draw the blade.</span>"
/obj/item/storage/belt/sabre/AltClick(mob/user)
if(!iscarbon(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(length(contents))
var/obj/item/I = contents[1]
user.visible_message("[user] takes [I] out of [src].", "<span class='notice'>You take [I] out of [src].</span>")
user.put_in_hands(I)
update_icon()
else
to_chat(user, "[src] is empty.")
/obj/item/storage/belt/sabre/update_icon()
. = ..()
if(isliving(loc))
+1 -1
View File
@@ -901,7 +901,7 @@
#undef HEART
#undef SMILEY
/obj/item/storage/box/ingredients //This box is for the randomely chosen version the chef spawns with, it shouldn't actually exist.
/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist.
name = "ingredients box"
illustration = "fruit"
var/theme_name
+1
View File
@@ -157,6 +157,7 @@
to_chat(user, "<span class='notice'>You take \a [W] out of the pack.</span>")
else
to_chat(user, "<span class='notice'>There are no [icon_type]s left in the pack.</span>")
return TRUE
/obj/item/storage/fancy/cigarettes/update_icon()
if(fancy_open || !contents.len)
+2 -1
View File
@@ -114,11 +114,12 @@
. += "<span class='notice'>Alt-click to [open ? "close":"open"] it.</span>"
/obj/item/storage/lockbox/medal/AltClick(mob/user)
. = ..()
if(user.canUseTopic(src, BE_CLOSE))
if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
open = (open ? FALSE : TRUE)
update_icon()
..()
return TRUE
/obj/item/storage/lockbox/medal/PopulateContents()
new /obj/item/clothing/accessory/medal/gold/captain(src)
+27 -5
View File
@@ -338,11 +338,12 @@
M.update_inv_hands()
/obj/item/toy/sword/cx/AltClick(mob/living/user)
. = ..()
if(!in_range(src, user)) //Basic checks to prevent abuse
return
if(user.incapacitated() || !istype(user))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
return TRUE
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"","Choose Energy Color",light_color) as color|null
@@ -350,6 +351,7 @@
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
return TRUE
/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file)
. = ..()
@@ -401,6 +403,7 @@
righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi'
var/active = FALSE
icon = 'icons/obj/items_and_weapons.dmi'
hitsound = 'sound/weapons/smash.ogg'
attack_verb = list("robusted")
/obj/item/toy/windupToolbox/attack_self(mob/user)
@@ -408,13 +411,33 @@
icon_state = "his_grace_awakened"
to_chat(user, "<span class='warning'>You wind up [src], it begins to rumble.</span>")
active = TRUE
playsound(src, 'sound/effects/pope_entry.ogg', 100)
Rumble()
addtimer(CALLBACK(src, .proc/stopRumble), 600)
else
to_chat(user, "[src] is already active.")
/obj/item/toy/windupToolbox/proc/Rumble()
var/static/list/transforms
if(!transforms)
var/matrix/M1 = matrix()
var/matrix/M2 = matrix()
var/matrix/M3 = matrix()
var/matrix/M4 = matrix()
M1.Translate(-1, 0)
M2.Translate(0, 1)
M3.Translate(1, 0)
M4.Translate(0, -1)
transforms = list(M1, M2, M3, M4)
animate(src, transform=transforms[1], time=0.2, loop=-1)
animate(transform=transforms[2], time=0.1)
animate(transform=transforms[3], time=0.2)
animate(transform=transforms[4], time=0.3)
/obj/item/toy/windupToolbox/proc/stopRumble()
icon_state = initial(icon_state)
active = FALSE
animate(src, transform=matrix())
/*
* Subtype of Double-Bladed Energy Swords
@@ -864,9 +887,10 @@
return ..()
/obj/item/toy/cards/deck/MouseDrop(atom/over_object)
. = ..()
var/mob/living/M = usr
if(!istype(M) || usr.incapacitated() || usr.lying)
return ..()
return
if(Adjacent(usr))
if(over_object == M && loc != M)
M.put_in_hands(src)
@@ -878,9 +902,7 @@
to_chat(usr, "<span class='notice'>You pick up the deck.</span>")
else
. = ..()
if(!.)
to_chat(usr, "<span class='warning'>You can't reach it from here!</span>")
to_chat(usr, "<span class='warning'>You can't reach it from here!</span>")
+4
View File
@@ -541,6 +541,7 @@
clean_blood()
/obj/item/twohanded/dualsaber/hypereutactic/AltClick(mob/living/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE, FALSE) || hacked)
return
if(user.incapacitated() || !istype(user))
@@ -553,6 +554,7 @@
light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
return TRUE
/obj/item/twohanded/dualsaber/hypereutactic/worn_overlays(isinhands, icon_file)
. = ..()
@@ -659,6 +661,7 @@
qdel(src)
/obj/item/twohanded/spear/AltClick(mob/user)
. = ..()
if(user.canUseTopic(src, BE_CLOSE))
..()
if(!explosive)
@@ -667,6 +670,7 @@
var/input = stripped_input(user,"What do you want your war cry to be? You will shout it when you hit someone in melee.", ,"", 50)
if(input)
src.war_cry = input
return TRUE
/obj/item/twohanded/spear/CheckParts(list/parts_list)
var/obj/item/shard/tip = locate() in parts_list
+1
View File
@@ -234,6 +234,7 @@
. = ..()
if(unique_reskin && (!current_skin || always_reskinnable) && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
reskin_obj(user)
return TRUE
/obj/proc/reskin_obj(mob/M)
if(!LAZYLEN(unique_reskin))
@@ -449,6 +449,9 @@
item_chair = null
var/turns = 0
/obj/structure/chair/brass/ComponentInitialize()
return //it spins with the power of ratvar, not components.
/obj/structure/chair/brass/Destroy()
STOP_PROCESSING(SSfastprocess, src)
. = ..()
@@ -464,6 +467,7 @@
return
/obj/structure/chair/brass/AltClick(mob/living/user)
. = ..()
turns = 0
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
@@ -475,6 +479,7 @@
user.visible_message("<span class='notice'>[user] stops [src]'s uncontrollable spinning.</span>", \
"<span class='notice'>You grab [src] and stop its wild spinning.</span>")
STOP_PROCESSING(SSfastprocess, src)
return TRUE
/obj/structure/chair/bronze
name = "brass chair"
@@ -342,25 +342,21 @@
. = TRUE
if(opened)
if(istype(W, cutting_tool))
var/welder = FALSE
if(istype(W, /obj/item/weldingtool))
if(!W.tool_start_check(user, amount=0))
return
to_chat(user, "<span class='notice'>You begin cutting \the [src] apart...</span>")
if(W.use_tool(src, user, 40, volume=50))
if(eigen_teleport)
to_chat(user, "<span class='notice'>The unstable nature of \the [src] makes it impossible to cut!</span>")
return
if(!opened)
return
user.visible_message("<span class='notice'>[user] slices apart \the [src].</span>",
"<span class='notice'>You cut \the [src] apart with \the [W].</span>",
"<span class='italics'>You hear welding.</span>")
deconstruct(TRUE)
return
else // for example cardboard box is cut with wirecutters
user.visible_message("<span class='notice'>[user] cut apart \the [src].</span>", \
"<span class='notice'>You cut \the [src] apart with \the [W].</span>")
to_chat(user, "<span class='notice'>You begin [welder ? "slicing" : "deconstructing"] \the [src] apart...</span>")
welder = TRUE
if(W.use_tool(src, user, 40, volume=50))
if(eigen_teleport)
to_chat(user, "<span class='notice'>The unstable nature of \the [src] makes it impossible to [welder ? "slice" : "deconstruct"]!</span>")
return
if(!opened)
return
user.visible_message("<span class='notice'>[user] [welder ? "slice" : "deconstruct"]s apart \the [src].</span>",
"<span class='notice'>You [welder ? "slice" : "deconstruct"] \the [src] apart with \the [W].</span>",
"<span class='italics'>You hear [welder ? "welding" : "rustling of screws and metal"].</span>")
deconstruct(TRUE)
return
if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
@@ -526,11 +522,12 @@
to_chat(user, "<span class='warning'>You fail to break out of [src]!</span>")
/obj/structure/closet/AltClick(mob/user)
..()
. = ..()
if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc))
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
return TRUE
togglelock(user)
return TRUE
/obj/structure/closet/CtrlShiftClick(mob/living/user)
if(!HAS_TRAIT(user, TRAIT_SKITTISH))
@@ -4,6 +4,8 @@
icon_state = "cabinet"
resistance_flags = FLAMMABLE
max_integrity = 70
material_drop = /obj/item/stack/sheet/mineral/wood
cutting_tool = /obj/item/screwdriver
/obj/structure/closet/acloset
name = "strange closet"
@@ -4,6 +4,8 @@
icon_state = "cabinet"
resistance_flags = FLAMMABLE
max_integrity = 70
material_drop = /obj/item/stack/sheet/mineral/wood
cutting_tool = /obj/item/screwdriver
/obj/structure/closet/secure_closet/bar/PopulateContents()
..()
@@ -44,6 +44,8 @@
icon_state = "cabinet"
resistance_flags = FLAMMABLE
max_integrity = 70
material_drop = /obj/item/stack/sheet/mineral/wood
cutting_tool = /obj/item/screwdriver
/obj/structure/closet/secure_closet/personal/cabinet/PopulateContents()
new /obj/item/storage/backpack/satchel/leather/withwallet( src )
@@ -161,12 +161,16 @@
..()
new /obj/item/clothing/accessory/armband/medblue(src)
new /obj/item/encryptionkey/headset_med(src)
/obj/structure/closet/secure_closet/detective
name = "\improper detective's cabinet"
req_access = list(ACCESS_FORENSICS_LOCKERS)
icon_state = "cabinet"
resistance_flags = FLAMMABLE
max_integrity = 70
material_drop = /obj/item/stack/sheet/mineral/wood
cutting_tool = /obj/item/screwdriver
/obj/structure/closet/secure_closet/detective/PopulateContents()
..()
new /obj/item/clothing/under/rank/det(src)
@@ -79,6 +79,15 @@
material_drop = /obj/item/stack/sheet/mineral/wood
material_drop_amount = 5
/obj/structure/closet/crate/coffin/examine(mob/user)
. = ..()
if(user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
. += {"<span class='cult'>This is a coffin which you can use to regenerate your burns and other wounds faster.</span>"}
. += {"<span class='cult'>You can also thicken your blood if you survive the day, and hide from the sun safely while inside.</span>"}
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
. += {"<span class='cult'>This is a coffin which your master can use to shield himself from the unforgiving sun.\n
You yourself are still human and dont need it. Yet.</span>"} */
/obj/structure/closet/crate/internals
desc = "An internals crate."
name = "internals crate"
+3 -3
View File
@@ -40,11 +40,11 @@
last_process = world.time
to_chat(user, "<span class='notice'>The water feels warm and soothing as you touch it. The fountain immediately dries up shortly afterwards.</span>")
user.reagents.add_reagent("godblood",20)
update_icons()
addtimer(CALLBACK(src, .proc/update_icons), time_between_uses)
update_icon()
addtimer(CALLBACK(src, .proc/update_icon), time_between_uses)
/obj/structure/healingfountain/proc/update_icons()
/obj/structure/healingfountain/update_icon()
if(last_process + time_between_uses > world.time)
icon_state = "fountain"
else
@@ -102,9 +102,11 @@
return attack_hand(user)
/obj/structure/extinguisher_cabinet/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
toggle_cabinet(user)
return TRUE
/obj/structure/extinguisher_cabinet/proc/toggle_cabinet(mob/user)
if(opened && broken)
+1 -1
View File
@@ -14,8 +14,8 @@
if(source_projector)
projector = source_projector
projector.signs += src
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, alpha, RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
alpha = 0
SSvis_overlays.add_vis_overlay(src, icon, icon_state, ABOVE_MOB_LAYER, plane, dir, add_appearance_flags = RESET_ALPHA) //you see mobs under it, but you hit them like they are above it
/obj/structure/holosign/Destroy()
if(projector)
+7 -4
View File
@@ -20,10 +20,9 @@
return
if(broken || !Adjacent(user))
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
//see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments!
//this is largely copypasted from there.
@@ -226,9 +225,13 @@
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
if(new_eye_color)
H.eye_color = sanitize_hexcolor(new_eye_color)
var/n_color = sanitize_hexcolor(new_eye_color)
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.eye_color = n_color
H.eye_color = n_color
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.update_body()
H.dna.species.handle_body()
if(choice)
curse(user)
+2 -1
View File
@@ -167,11 +167,12 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
. += "<span class='notice'>The speaker is [beeper ? "enabled" : "disabled"]. Alt-click to toggle it.</span>"
/obj/structure/bodycontainer/morgue/AltClick(mob/user)
..()
. = ..()
if(!user.canUseTopic(src, !issilicon(user)))
return
beeper = !beeper
to_chat(user, "<span class='notice'>You turn the speaker function [beeper ? "on" : "off"].</span>")
return TRUE
/obj/structure/bodycontainer/morgue/update_icon()
if (!connected || connected.loc != src) // Open or tray is gone.
@@ -167,10 +167,12 @@
return TRUE
/obj/structure/reflector/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
else if(finished)
rotate(user)
return TRUE
//TYPES OF REFLECTORS, SINGLE, DOUBLE, BOX
+7
View File
@@ -285,6 +285,13 @@
. += new /obj/item/shard(location)
/obj/structure/window/proc/can_be_rotated(mob/user,rotation_type)
if (get_dist(src,user) > 1)
if (iscarbon(user))
var/mob/living/carbon/H = user
if (!(H.dna && H.dna.check_mutation(TK) && tkMaxRangeCheck(src,H)))
return FALSE
else
return FALSE
if(anchored)
to_chat(user, "<span class='warning'>[src] cannot be rotated while it is fastened to the floor!</span>")
return FALSE
+7 -5
View File
@@ -28,19 +28,21 @@ GLOBAL_LIST_INIT(freqtospan, list(
language = get_default_language()
send_speech(message, 7, src, , spans, message_language=language)
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
/atom/movable/proc/can_speak()
return 1
/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode)
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
/atom/movable/proc/send_speech(message, range = 7, atom/movable/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode)
var/rendered = compose_message(src, message_language, message, , spans, message_mode, source)
for(var/_AM in get_hearers_in_view(range, source))
var/atom/movable/AM = _AM
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
AM.Hear(rendered, src, message_language, message, , spans, message_mode, source)
/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE)
/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE, atom/movable/source)
if(!source)
source = speaker
//This proc uses text() because it is faster than appending strings. Thanks BYOND.
//Basic span
var/spanpart1 = "<span class='[radio_freq ? get_radio_span(radio_freq) : "game say"]'>"
+87
View File
@@ -176,6 +176,12 @@
/turf/closed/mineral/uranium/volcanic = 35, /turf/closed/mineral/diamond/volcanic = 30, /turf/closed/mineral/gold/volcanic = 45, /turf/closed/mineral/titanium/volcanic = 45,
/turf/closed/mineral/silver/volcanic = 50, /turf/closed/mineral/plasma/volcanic = 50, /turf/closed/mineral/bscrystal/volcanic = 20)
/turf/closed/mineral/random/high_chance/earth_like
icon_state = "rock_highchance_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/random/low_chance
@@ -186,6 +192,12 @@
/turf/closed/mineral/silver = 6, /turf/closed/mineral/plasma = 15, /turf/closed/mineral/iron = 40,
/turf/closed/mineral/gibtonite = 2, /turf/closed/mineral/bscrystal = 1)
/turf/closed/mineral/random/low_chance/earth_like
icon_state = "rock_lowchance_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/random/volcanic
environment_type = "basalt"
@@ -220,6 +232,12 @@
/turf/closed/mineral/silver/volcanic = 20, /turf/closed/mineral/plasma/volcanic = 30, /turf/closed/mineral/bscrystal/volcanic = 1, /turf/closed/mineral/gibtonite/volcanic = 2,
/turf/closed/mineral/iron/volcanic = 95)
/turf/closed/mineral/random/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/iron
@@ -235,6 +253,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/iron/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/iron/ice
environment_type = "snow_cavern"
icon_state = "icerock_iron"
@@ -258,6 +283,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/uranium/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/diamond
mineralType = /obj/item/stack/ore/diamond
@@ -272,6 +304,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/diamond/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/diamond/ice
environment_type = "snow_cavern"
icon_state = "icerock_diamond"
@@ -295,6 +334,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/gold/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/silver
mineralType = /obj/item/stack/ore/silver
@@ -309,6 +355,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/silver/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/titanium
mineralType = /obj/item/stack/ore/titanium
@@ -323,6 +376,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/titanium/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/plasma
mineralType = /obj/item/stack/ore/plasma
@@ -337,6 +397,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/plasma/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/plasma/ice
environment_type = "snow_cavern"
icon_state = "icerock_plasma"
@@ -355,6 +422,12 @@
spread = 0
scan_state = "rock_Bananium"
/turf/closed/mineral/bananium/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/bscrystal
mineralType = /obj/item/stack/ore/bluespace_crystal
@@ -370,6 +443,13 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
/turf/closed/mineral/bscrystal/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/volcanic
environment_type = "basalt"
@@ -383,6 +463,13 @@
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
defer_change = 1
/turf/closed/mineral/earth_like
icon_state = "rock_oxy"
turf_type = /turf/open/floor/plating/asteroid
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/ash_rock //wall piece
name = "rock"
icon = 'icons/turf/mining.dmi'