Merge branch 'master' into familyport
This commit is contained in:
@@ -115,9 +115,9 @@ GLOBAL_PROTECT(LastAdminCalledProc)
|
||||
//adv proc call this, ya nerds
|
||||
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
|
||||
if(target == GLOBAL_PROC)
|
||||
return call("/proc/[procname]")(arglist(arguments))
|
||||
else if(target != world)
|
||||
return call(target, procname)(arglist(arguments))
|
||||
return text2path("/proc/[procname]")? call("/proc/[procname]")(arglist(arguments)) : null
|
||||
else if(target != world && istype(target, /datum)) // isdatum check incase someone manages to call WrapAdminProcCall(global) which would otherwise crash the process entirely
|
||||
return hascall(target, procname)? call(target, procname)(arglist(arguments)) : null
|
||||
else
|
||||
log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"name" = initial(item.name),
|
||||
"desc" = initial(item.desc),
|
||||
// at this point initializing the item is probably faster tbh
|
||||
"sprite" = icon2base64(icon(initial(item.icon), initial(item.icon_state))),
|
||||
"sprite" = icon2base64(icon(initial(item.icon), initial(item.icon_state), SOUTH, 1)),
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
@@ -2038,6 +2038,12 @@
|
||||
var/obj/item/station_charter/charter = locate(href_list["reject_custom_name"])
|
||||
if(istype(charter))
|
||||
charter.reject_proposed(usr)
|
||||
else if(href_list["approve_custom_name"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/obj/item/station_charter/charter = locate(href_list["approve_custom_name"])
|
||||
if(istype(charter))
|
||||
charter.allow_pass(usr)
|
||||
else if(href_list["jumpto"])
|
||||
if(!isobserver(usr) && !check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
var/selectors_used = FALSE
|
||||
var/list/combined_refs = list()
|
||||
do
|
||||
CHECK_TICK
|
||||
stoplag(2)
|
||||
finished = TRUE
|
||||
for(var/i in running)
|
||||
var/datum/SDQL2_query/query = i
|
||||
|
||||
@@ -3,11 +3,19 @@
|
||||
/proc/_abs(A)
|
||||
return abs(A)
|
||||
|
||||
/proc/_animate(atom/A, set_vars, time = 10, loop = 1, easing = LINEAR_EASING, flags = null)
|
||||
var/mutable_appearance/MA = new()
|
||||
for(var/v in set_vars)
|
||||
MA.vars[v] = set_vars[v]
|
||||
animate(A, appearance = MA, time, loop, easing, flags)
|
||||
/proc/_animate(atom/A, list/data, time = 10, loop = 1, easing = LINEAR_EASING, flags = null)
|
||||
if(!istype(A))
|
||||
return
|
||||
animate(A, appearance = data, time = time, loop = loop, easing = easing, flags = flags)
|
||||
|
||||
/proc/_animate_adv(atom/A, list/data, loop = 1, easing = LINEAR_EASING, flags = NONE)
|
||||
if(!A || !islist(data) || data.len < 1)
|
||||
return
|
||||
animate(A, appearance = (data[1] - "time"), time = data[1]["time"], loop = loop, easing = easing, flags = flags)
|
||||
if(data.len < 2)
|
||||
return
|
||||
for(var/i in 2 to data.len)
|
||||
animate(appearance = (data[i] - "time"), time = data[i]["time"])
|
||||
|
||||
/proc/_acrccos(A)
|
||||
return arccos(A)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set category = "Object"
|
||||
|
||||
if((O.obj_flags & DANGEROUS_POSSESSION) && CONFIG_GET(flag/forbid_singulo_possession))
|
||||
to_chat(usr, "[O] is too powerful for you to possess.")
|
||||
to_chat(usr, "[O] is too powerful for you to possess.", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(O)
|
||||
@@ -18,19 +18,22 @@
|
||||
if(!usr.control_object) //If you're not already possessing something...
|
||||
usr.name_archive = usr.real_name
|
||||
|
||||
usr.loc = O
|
||||
usr.forceMove(O)
|
||||
usr.real_name = O.name
|
||||
usr.name = O.name
|
||||
usr.reset_perspective(O)
|
||||
usr.control_object = O
|
||||
O.AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Possess Object") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/proc/release()
|
||||
set name = "Release Obj"
|
||||
set category = "Object"
|
||||
//usr.loc = get_turf(usr)
|
||||
|
||||
if(usr.control_object && usr.name_archive) //if you have a name archived and if you are actually relassing an object
|
||||
if(!usr.control_object) //lest we are banished to the nullspace realm.
|
||||
return
|
||||
|
||||
if(usr.name_archive) //if you have a name archived
|
||||
usr.real_name = usr.name_archive
|
||||
usr.name_archive = ""
|
||||
usr.name = usr.real_name
|
||||
@@ -38,8 +41,8 @@
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.name = H.get_visible_name()
|
||||
|
||||
|
||||
usr.loc = get_turf(usr.control_object)
|
||||
usr.control_object.RemoveElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
usr.forceMove(get_turf(usr.control_object))
|
||||
usr.reset_perspective()
|
||||
usr.control_object = null
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Release Object") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -1592,7 +1592,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
light_range = 2
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
/obj/effect/temp_visual/target/ex_act(severity, target, origin)
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
. = TRUE
|
||||
if("mass_apply")
|
||||
if(!check_rights_for(usr.client, R_FUN))
|
||||
to_chat(usr, "<span class='userdanger>Stay in your lane, jannie.</span>'")
|
||||
to_chat(usr, span_userdanger("Stay in your lane, jannie."))
|
||||
return
|
||||
var/target_path = text2path(params["path"])
|
||||
if(!target_path)
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
/datum/antagonist
|
||||
///Public name for this antagonist. Appears for player prompts and round-end reports.
|
||||
var/name = "Antagonist"
|
||||
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
|
||||
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
|
||||
var/datum/mind/owner //Mind that owns this datum
|
||||
var/silent = FALSE //Silent will prevent the gain/lose texts to show
|
||||
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
|
||||
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
|
||||
var/delete_on_mind_deletion = TRUE
|
||||
///Section of roundend report, datums with same category will be displayed together, also default header for the section
|
||||
var/roundend_category = "other antagonists"
|
||||
///Set to false to hide the antagonists from roundend report
|
||||
var/show_in_roundend = TRUE
|
||||
///If false, the roundtype will still convert with this antag active
|
||||
var/prevent_roundtype_conversion = TRUE
|
||||
///Mind that owns this datum
|
||||
var/datum/mind/owner
|
||||
///Silent will prevent the gain/lose texts to show
|
||||
var/silent = FALSE
|
||||
///Whether or not the person will be able to have more than one datum
|
||||
var/can_coexist_with_others = TRUE
|
||||
///List of datums this type can't coexist with
|
||||
var/list/typecache_datum_blacklist = list()
|
||||
///The define string we use to identify the role for bans/player polls to spawn a random new one in.
|
||||
var/job_rank
|
||||
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
|
||||
///Should replace jobbanned player with ghosts if granted.
|
||||
var/replace_banned = TRUE
|
||||
///List of the objective datums that this role currently has, completing all objectives at round-end will cause this antagonist to greentext.
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
|
||||
///String dialogue that is added to the player's in-round notes and memories regarding specifics of that antagonist, eg. the nuke code for nuke ops, or your unlock code for traitors.
|
||||
var/antag_memory = ""
|
||||
///typepath of moodlet that the mob will gain when granted this antagonist type.
|
||||
var/antag_moodlet
|
||||
|
||||
///What is the configuration of this antagonist's hud icon, such as it's screen position and style, so thatit doesn't break other in-game hud icons.
|
||||
var/antag_hud_type
|
||||
///Name of the antag hud we provide to this mob.
|
||||
var/antag_hud_name
|
||||
/// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed().
|
||||
var/hijack_speed = 0
|
||||
@@ -22,25 +38,36 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/suicide_cry = ""
|
||||
/// The typepath for the outfit to show in the preview for the preferences menu.
|
||||
var/preview_outfit
|
||||
/// If set to true, the antag will not be added to the living antag list.
|
||||
var/soft_antag = FALSE
|
||||
|
||||
//Antag panel properties
|
||||
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
|
||||
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
|
||||
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
|
||||
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
|
||||
var/show_to_ghosts = FALSE // Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors
|
||||
///This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
var/show_in_antagpanel = TRUE
|
||||
///Antagpanel will display these together, REQUIRED
|
||||
var/antagpanel_category = "Uncategorized"
|
||||
///Will append antagonist name in admin listings - use for categories that share more than one antag type
|
||||
var/show_name_in_check_antagonists = FALSE
|
||||
/// Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors
|
||||
var/show_to_ghosts = FALSE
|
||||
|
||||
/* CIT SPECIFIC */
|
||||
/// Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
|
||||
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute)
|
||||
/// Amount of threat this antag poses, for dynamic mode
|
||||
var/threat = 0
|
||||
|
||||
var/delete_on_mind_deletion = TRUE
|
||||
|
||||
var/list/skill_modifiers
|
||||
/* CIT SPECIFIC end */
|
||||
|
||||
//ANTAG UI
|
||||
|
||||
///name of the UI that will try to open, right now using a generic ui
|
||||
var/ui_name = "AntagInfoGeneric"
|
||||
///name of the UI that will try to open, right now having nothing means this won't exist but in the future all should.
|
||||
var/ui_name
|
||||
///button to access antag interface
|
||||
var/datum/action/antag_info/info_button
|
||||
//temporarily disable it for all antagonists other than families
|
||||
var/ui_enable
|
||||
|
||||
/datum/antagonist/New()
|
||||
GLOB.antagonists += src
|
||||
@@ -48,7 +75,9 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
/datum/antagonist/Destroy()
|
||||
GLOB.antagonists -= src
|
||||
if(owner)
|
||||
if(!owner)
|
||||
stack_trace("Destroy()ing antagonist datum when it has no owner.")
|
||||
else
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
owner = null
|
||||
return ..()
|
||||
@@ -68,14 +97,14 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/specialization(datum/mind/new_owner)
|
||||
return src
|
||||
|
||||
///Called by the transfer_to() mind proc after the mind (mind.current and new_character.mind) has moved but before the player (key and client) is transfered.
|
||||
///Called by the transfer_to() mind proc after the mind (mind.current and new_character.mind) has moved but before the player (key and client) is transfered.
|
||||
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
remove_innate_effects(old_body)
|
||||
if(old_body.stat != DEAD && !LAZYLEN(old_body.mind?.antag_datums))
|
||||
if(!soft_antag && old_body && old_body.stat != DEAD && !length(old_body.mind?.antag_datums))
|
||||
old_body.remove_from_current_living_antags()
|
||||
apply_innate_effects(new_body)
|
||||
if(new_body.stat != DEAD)
|
||||
if(!soft_antag && new_body.stat != DEAD)
|
||||
new_body.add_to_current_living_antags()
|
||||
|
||||
//This handles the application of antag huds/special abilities
|
||||
@@ -86,55 +115,76 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
/// This is called when the antagonist is being mindshielded.
|
||||
/datum/antagonist/proc/pre_mindshield(mob/implanter, mob/living/mob_override)
|
||||
SIGNAL_HANDLER
|
||||
// return COMPONENT_MINDSHIELD_PASSED
|
||||
|
||||
/// This is called when the antagonist is successfully mindshielded.
|
||||
/datum/antagonist/proc/on_mindshield(mob/implanter, mob/living/mob_override)
|
||||
SIGNAL_HANDLER
|
||||
return
|
||||
|
||||
// Adds the specified antag hud to the player. Usually called in an antag datum file
|
||||
/datum/antagonist/proc/add_antag_hud(antag_hud_type, antag_hud_name, mob/living/mob_override)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.join_hud(mob_override)
|
||||
set_antag_hud(mob_override, antag_hud_name)
|
||||
|
||||
|
||||
// Removes the specified antag hud from the player. Usually called in an antag datum file
|
||||
/datum/antagonist/proc/remove_antag_hud(antag_hud_type, mob/living/mob_override)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.leave_hud(mob_override)
|
||||
set_antag_hud(mob_override, null)
|
||||
|
||||
// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects
|
||||
|
||||
/// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects
|
||||
/datum/antagonist/proc/handle_clown_mutation(mob/living/mob_override, message, removing = TRUE)
|
||||
var/mob/living/carbon/human/H = mob_override
|
||||
if(H && istype(H) && owner.assigned_role == "Clown")
|
||||
if(removing) // They're a clown becoming an antag, remove clumsy
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
if(!silent && message)
|
||||
to_chat(H, "<span class='boldnotice'>[message]</span>")
|
||||
else
|
||||
H.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy
|
||||
if(!ishuman(mob_override) || owner.assigned_role != "Clown")
|
||||
return
|
||||
var/mob/living/carbon/human/human_override = mob_override
|
||||
if(removing) // They're a clown becoming an antag, remove clumsy
|
||||
human_override.dna.remove_mutation(CLOWNMUT)
|
||||
if(!silent && message)
|
||||
to_chat(human_override, span_boldnotice("[message]"))
|
||||
else
|
||||
human_override.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy
|
||||
|
||||
|
||||
//Assign default team and creates one for one of a kind team antagonists
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
|
||||
///Called by the add_antag_datum() mind proc after the instanced datum is added to the mind's antag_datums list.
|
||||
///Called by the add_antag_datum() mind proc after the instanced datum is added to the mind's antag_datums list.
|
||||
/datum/antagonist/proc/on_gain()
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
set waitfor = FALSE
|
||||
if(!(owner?.current))
|
||||
return
|
||||
if(!owner)
|
||||
CRASH("[src] ran on_gain() without a mind")
|
||||
if(!owner.current)
|
||||
CRASH("[src] ran on_gain() on a mind without a mob")
|
||||
if(ui_name)//in the future, this should entirely replace greet.
|
||||
if(ui_enable == TRUE)
|
||||
info_button = new(owner.current, src)
|
||||
info_button.Grant(owner.current)
|
||||
info_button = new(owner.current, src)
|
||||
info_button.Grant(owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
if(ui_name)
|
||||
if(ui_enable == TRUE)
|
||||
to_chat(owner.current, span_big("You are \a [src]."))
|
||||
to_chat(owner.current, span_boldnotice("For more info, read the panel. you can always come back to it using the button in the top left."))
|
||||
info_button.Trigger()
|
||||
to_chat(owner.current, span_big("You are \a [src]."))
|
||||
to_chat(owner.current, span_boldnotice("For more info, read the panel. you can always come back to it using the button in the top left."))
|
||||
info_button.Trigger()
|
||||
apply_innate_effects()
|
||||
give_antag_moodies()
|
||||
remove_blacklisted_quirks()
|
||||
// RegisterSignal(owner, COMSIG_PRE_MINDSHIELD_IMPLANT, .proc/pre_mindshield)
|
||||
// RegisterSignal(owner, COMSIG_MINDSHIELD_IMPLANTED, .proc/on_mindshield)
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
// else if(owner.current.client?.holder && (CONFIG_GET(flag/auto_deadmin_antagonists) || owner.current.client.prefs?.toggles & DEADMIN_ANTAGONIST))
|
||||
// owner.current.client.holder.auto_deadmin()
|
||||
if(!soft_antag && owner.current.stat != DEAD)
|
||||
owner.current.add_to_current_living_antags()
|
||||
|
||||
// cit skill
|
||||
if(skill_modifiers)
|
||||
for(var/A in skill_modifiers)
|
||||
ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
|
||||
@@ -142,63 +192,95 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
if(istype(M))
|
||||
M.name = "[name] Training"
|
||||
owner.current.AddComponent(/datum/component/activity)
|
||||
if(owner.current.stat != DEAD)
|
||||
owner.current.add_to_current_living_antags()
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
|
||||
|
||||
|
||||
/**
|
||||
* Proc that checks the sent mob aganst the banlistfor this antagonist.
|
||||
* Returns FALSE if no mob is sent, or the mob is not found to be banned.
|
||||
*
|
||||
* * mob/M: The mob that you are looking for on the banlist.
|
||||
*/
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
return FALSE
|
||||
. = (jobban_isbanned(M, ROLE_SYNDICATE) || QDELETED(M) || (job_rank && (jobban_isbanned(M,job_rank) || QDELETED(M))))
|
||||
|
||||
/**
|
||||
* Proc that replaces a player who cannot play a specific antagonist due to being banned via a poll, and alerts the player of their being on the banlist.
|
||||
*/
|
||||
/datum/antagonist/proc/replace_banned_player()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/mob/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", null, job_rank, 50, owner.current)
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", job_rank, 50, owner.current)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/C = pick(candidates)
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
|
||||
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
|
||||
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.")
|
||||
owner.current.ghostize(0)
|
||||
C.transfer_ckey(owner.current, FALSE)
|
||||
|
||||
///Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion.
|
||||
/**
|
||||
* Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion.
|
||||
*/
|
||||
/datum/antagonist/proc/on_removal()
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
|
||||
remove_innate_effects()
|
||||
clear_antag_moodies()
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
for(var/A in skill_modifiers)
|
||||
owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type))
|
||||
if(!LAZYLEN(owner.antag_datums))
|
||||
owner.current.remove_from_current_living_antags()
|
||||
if(info_button)
|
||||
QDEL_NULL(info_button)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
// cit skill
|
||||
for(var/A in skill_modifiers)
|
||||
owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type))
|
||||
// end
|
||||
if(!LAZYLEN(owner.antag_datums) && !soft_antag)
|
||||
owner.current.remove_from_current_living_antags()
|
||||
if(info_button)
|
||||
QDEL_NULL(info_button)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
// UnregisterSignal(owner, COMSIG_PRE_MINDSHIELD_IMPLANT)
|
||||
// UnregisterSignal(owner, COMSIG_MINDSHIELD_IMPLANTED)
|
||||
var/datum/team/team = get_team()
|
||||
if(team)
|
||||
team.remove_member(owner)
|
||||
// we don't remove the activity component on purpose--no real point to it
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Proc that sends fluff or instructional messages to the player when they are given this antag datum.
|
||||
* Use this proc for playing sounds, sending alerts, or helping to setup non-gameplay influencing aspects of the antagonist type.
|
||||
*/
|
||||
/datum/antagonist/proc/greet()
|
||||
return
|
||||
|
||||
/**
|
||||
* Proc that sends fluff or instructional messages to the player when they lose this antag datum.
|
||||
* Use this proc for playing sounds, sending alerts, or otherwise informing the player that they're no longer a specific antagonist type.
|
||||
*/
|
||||
/datum/antagonist/proc/farewell()
|
||||
return
|
||||
|
||||
/**
|
||||
* Proc that assigns this antagonist's ascribed moodlet to the player.
|
||||
*/
|
||||
/datum/antagonist/proc/give_antag_moodies()
|
||||
if(!antag_moodlet)
|
||||
return
|
||||
SEND_SIGNAL(owner.current, COMSIG_ADD_MOOD_EVENT, "antag_moodlet", antag_moodlet)
|
||||
|
||||
/**
|
||||
* Proc that removes this antagonist's ascribed moodlet from the player.
|
||||
*/
|
||||
/datum/antagonist/proc/clear_antag_moodies()
|
||||
if(!antag_moodlet)
|
||||
return
|
||||
SEND_SIGNAL(owner.current, COMSIG_CLEAR_MOOD_EVENT, "antag_moodlet")
|
||||
|
||||
/**
|
||||
* Removes invalid quirks.
|
||||
*/
|
||||
/datum/antagonist/proc/remove_blacklisted_quirks()
|
||||
var/mob/living/L = owner.current
|
||||
if(istype(L))
|
||||
@@ -209,16 +291,22 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
to_chat(L, "<span class='boldannounce'>[initial(Q.antag_removal_text)]</span>")
|
||||
qdel(Q)
|
||||
|
||||
//Returns the team antagonist belongs to if any.
|
||||
/**
|
||||
* Proc that will return the team this antagonist belongs to, when called. Helpful with antagonists that may belong to multiple potential teams in a single round, like families.
|
||||
*/
|
||||
/datum/antagonist/proc/get_team()
|
||||
return
|
||||
|
||||
//Individual roundend report
|
||||
/**
|
||||
* Proc that sends string information for the end-round report window to the server.
|
||||
* This runs on every instance of every antagonist that exists at the end of the round.
|
||||
* This is the body of the message, sandwiched between roundend_report_header and roundend_report_footer.
|
||||
*/
|
||||
/datum/antagonist/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
if(!owner)
|
||||
CRASH("antagonist datum without owner")
|
||||
CRASH("Antagonist datum without owner")
|
||||
|
||||
report += printplayer(owner)
|
||||
|
||||
@@ -237,11 +325,19 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
return report.Join("<br>")
|
||||
|
||||
//Displayed at the start of roundend_category section, default to roundend_category header
|
||||
/**
|
||||
* Proc that sends string data for the round-end report.
|
||||
* Displayed before roundend_report and roundend_report_footer.
|
||||
* Appears at start of roundend_catagory section.
|
||||
*/
|
||||
/datum/antagonist/proc/roundend_report_header()
|
||||
return "<span class='header'>The [roundend_category] were:</span><br>"
|
||||
return "<span class='header'>The [roundend_category] were:</span><br>"
|
||||
|
||||
//Displayed at the end of roundend_category section
|
||||
/**
|
||||
* Proc that sends string data for the round-end report.
|
||||
* Displayed after roundend_report and roundend_report_footer.
|
||||
* Appears at the end of the roundend_catagory section.
|
||||
*/
|
||||
/datum/antagonist/proc/roundend_report_footer()
|
||||
return
|
||||
|
||||
@@ -250,22 +346,24 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
//Called when using admin tools to give antag status
|
||||
/datum/antagonist/proc/admin_add(datum/mind/new_owner,mob/admin)
|
||||
message_admins("[key_name_admin(admin)] made [new_owner.current] into [name].")
|
||||
log_admin("[key_name(admin)] made [new_owner.current] into [name].")
|
||||
message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner)] into [name].")
|
||||
log_admin("[key_name(admin)] made [key_name(new_owner)] into [name].")
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
//Called when removing antagonist using admin tools
|
||||
/datum/antagonist/proc/admin_remove(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
message_admins("[key_name_admin(user)] has removed [name] antagonist status from [owner.current].")
|
||||
log_admin("[key_name(user)] has removed [name] antagonist status from [owner.current].")
|
||||
message_admins("[key_name_admin(user)] has removed [name] antagonist status from [key_name_admin(owner)].")
|
||||
log_admin("[key_name(user)] has removed [name] antagonist status from [key_name(owner)].")
|
||||
on_removal()
|
||||
|
||||
//gamemode/proc/is_mode_antag(antagonist/A) => TRUE/FALSE
|
||||
|
||||
//Additional data to display in antagonist panel section
|
||||
//nuke disk code, genome count, etc
|
||||
/**
|
||||
* Additional data to display in the antagonist panel section.
|
||||
* For example, nuke disk code, genome count, etc
|
||||
*/
|
||||
/datum/antagonist/proc/antag_panel_data()
|
||||
return ""
|
||||
|
||||
@@ -277,7 +375,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// List if ["Command"] = CALLBACK(), user will be appeneded to callback arguments on execution
|
||||
/// List of ["Command"] = CALLBACK(), user will be appeneded to callback arguments on execution
|
||||
/datum/antagonist/proc/get_admin_commands()
|
||||
. = list()
|
||||
|
||||
@@ -344,14 +442,19 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
antag_memory = new_memo
|
||||
|
||||
/// Gets how fast we can hijack the shuttle, return 0 for can not hijack. Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something.
|
||||
/**
|
||||
* Gets how fast we can hijack the shuttle, return 0 for can not hijack.
|
||||
* Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something.
|
||||
*/
|
||||
/datum/antagonist/proc/hijack_speed()
|
||||
var/datum/objective/hijack/H = locate() in objectives
|
||||
if(!isnull(H?.hijack_speed_override))
|
||||
return H.hijack_speed_override
|
||||
return hijack_speed
|
||||
|
||||
/// Gets our threat level. Defaults to threat var, override for custom stuff like different traitor goals having different threats.
|
||||
/**
|
||||
* Gets our threat level. Override this proc for custom functionality/dynamic threat level.
|
||||
*/
|
||||
/datum/antagonist/proc/threat()
|
||||
. = CONFIG_GET(keyed_list/antag_threat)[lowertext(name)]
|
||||
if(. == null)
|
||||
@@ -361,6 +464,13 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/custom
|
||||
antagpanel_category = "Custom"
|
||||
show_name_in_check_antagonists = TRUE //They're all different
|
||||
var/datum/team/custom_team
|
||||
|
||||
/datum/antagonist/custom/create_team(datum/team/team)
|
||||
custom_team = team
|
||||
|
||||
/datum/antagonist/custom/get_team()
|
||||
return custom_team
|
||||
|
||||
/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin)
|
||||
var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist")
|
||||
@@ -389,7 +499,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
for(var/datum/objective/objective in objectives)
|
||||
objective_data += list(list(
|
||||
"count" = objective_count,
|
||||
"name" = objective.objective_name,
|
||||
"name" = objective.name,
|
||||
"explanation" = objective.explanation_text,
|
||||
"complete" = objective.completed,
|
||||
))
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
return
|
||||
|
||||
var/obj/item/organ/lungs/lungs = owner.getorganslot(ORGAN_SLOT_LUNGS)
|
||||
if((!lungs && !HAS_TRAIT(owner, TRAIT_NOBREATH)) || (lungs && (istype(lungs, /obj/item/organ/lungs/cybernetic))))
|
||||
if((!lungs && (HAS_TRAIT_FROM(owner, TRAIT_AUXILIARY_LUNGS, SPECIES_TRAIT) || !HAS_TRAIT(owner, TRAIT_NOBREATH))) || (lungs && (istype(lungs, /obj/item/organ/lungs/cybernetic))))
|
||||
replace_lungs(lungs)
|
||||
return
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/team/ashwalkers
|
||||
name = "Ashwalkers"
|
||||
show_roundend_report = FALSE
|
||||
var/list/players_spawned = new
|
||||
|
||||
/datum/antagonist/ashwalker
|
||||
name = "\improper Ash Walker"
|
||||
job_rank = ROLE_LAVALAND
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
antagpanel_category = "Ash Walkers"
|
||||
var/datum/team/ashwalkers/ashie_team
|
||||
|
||||
/datum/antagonist/ashwalker/create_team(datum/team/team)
|
||||
if(team)
|
||||
ashie_team = team
|
||||
objectives |= ashie_team.objectives
|
||||
else
|
||||
ashie_team = new
|
||||
|
||||
/datum/antagonist/ashwalker/get_team()
|
||||
return ashie_team
|
||||
|
||||
/datum/antagonist/ashwalker/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
. = ..()
|
||||
RegisterSignal(new_body, COMSIG_MOB_EXAMINATE, .proc/on_examinate)
|
||||
|
||||
/datum/antagonist/ashwalker/on_gain()
|
||||
. = ..()
|
||||
RegisterSignal(owner.current, COMSIG_MOB_EXAMINATE, .proc/on_examinate)
|
||||
|
||||
/datum/antagonist/ashwalker/on_removal()
|
||||
. = ..()
|
||||
UnregisterSignal(owner.current, COMSIG_MOB_EXAMINATE)
|
||||
|
||||
/datum/antagonist/ashwalker/proc/on_examinate(datum/source, atom/A)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(A, /obj/structure/headpike))
|
||||
SEND_SIGNAL(owner.current, COMSIG_ADD_MOOD_EVENT, "headspear", /datum/mood_event/sacrifice_good)
|
||||
@@ -45,7 +45,7 @@
|
||||
GLOB.poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/core/ex_act(severity, target)
|
||||
/obj/structure/blob/core/ex_act(severity, target, origin)
|
||||
var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
B.objectives += objective
|
||||
M.add_antag_datum(B)
|
||||
|
||||
var/begin_message = "<span class='deadsay'><b>[L]</b> has been brainwashed with the following objectives: "
|
||||
var/begin_message = " has been brainwashed with the following objectives: "
|
||||
var/obj_message = english_list(directives)
|
||||
var/end_message = "</b>.</span>"
|
||||
var/end_message = "."
|
||||
var/rendered = begin_message + obj_message + end_message
|
||||
deadchat_broadcast(rendered, follow_target = L, turf_target = get_turf(L), message_type=DEADCHAT_REGULAR)
|
||||
deadchat_broadcast(rendered, "<b>[L]</b>", follow_target = L, turf_target = get_turf(L), message_type=DEADCHAT_ANNOUNCEMENT)
|
||||
if(prob(1) || SSevents.holidays && SSevents.holidays[APRIL_FOOLS])
|
||||
L.say("You son of a bitch! I'm in.", forced = "That son of a bitch! They're in.")
|
||||
|
||||
/datum/antagonist/brainwashed
|
||||
name = "Brainwashed Victim"
|
||||
@@ -30,19 +32,21 @@
|
||||
show_in_antagpanel = TRUE
|
||||
antagpanel_category = "Other"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
ui_name = "AntagInfoBrainwashed"
|
||||
suicide_cry = "FOR... SOMEONE!!"
|
||||
|
||||
/datum/antagonist/brainwashed/greet()
|
||||
to_chat(owner, "<span class='warning'>Your mind reels as it begins focusing on a single purpose...</span>")
|
||||
to_chat(owner, "<big><span class='warning'><b>Follow the Directives, at any cost!</b></span></big>")
|
||||
var/i = 1
|
||||
for(var/X in objectives)
|
||||
var/datum/objective/O = X
|
||||
to_chat(owner, "<b>[i].</b> [O.explanation_text]")
|
||||
i++
|
||||
/datum/antagonist/brainwashed/ui_static_data(mob/user)
|
||||
. = ..()
|
||||
var/list/data = list()
|
||||
data["objectives"] = get_objectives()
|
||||
return data
|
||||
|
||||
/datum/antagonist/brainwashed/farewell()
|
||||
to_chat(owner, "<span class='warning'>Your mind suddenly clears...</span>")
|
||||
to_chat(owner, "<big><span class='warning'><b>You feel the weight of the Directives disappear! You no longer have to obey them.</b></span></big>")
|
||||
to_chat(owner, span_warning("Your mind suddenly clears..."))
|
||||
to_chat(owner, "<big>[span_warning("<b>You feel the weight of the Directives disappear! You no longer have to obey them.</b>")]</big>")
|
||||
if(owner.current)
|
||||
var/mob/living/owner_mob = owner.current
|
||||
owner_mob.log_message("is no longer brainwashed with the objectives: [english_list(objectives)].", LOG_ATTACK)
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/brainwashed/admin_add(datum/mind/new_owner,mob/admin)
|
||||
@@ -54,9 +58,9 @@
|
||||
var/objective = stripped_input(admin, "Add an objective, or leave empty to finish.", "Brainwashing", null, MAX_MESSAGE_LEN)
|
||||
if(objective)
|
||||
objectives += objective
|
||||
while(alert(admin,"Add another objective?","More Brainwashing","Yes","No") == "Yes")
|
||||
while(tgui_alert(admin,"Add another objective?","More Brainwashing",list("Yes","No")) == "Yes")
|
||||
|
||||
if(alert(admin,"Confirm Brainwashing?","Are you sure?","Yes","No") == "No")
|
||||
if(tgui_alert(admin,"Confirm Brainwashing?","Are you sure?",list("Yes","No")) == "No")
|
||||
return
|
||||
|
||||
if(!LAZYLEN(objectives))
|
||||
@@ -69,6 +73,7 @@
|
||||
brainwash(C, objectives)
|
||||
var/obj_list = english_list(objectives)
|
||||
message_admins("[key_name_admin(admin)] has brainwashed [key_name_admin(C)] with the following objectives: [obj_list].")
|
||||
C.log_message("has been force-brainwashed with the objective '[obj_list]' by admin [key_name(admin)]", LOG_ATTACK, log_globally = FALSE)
|
||||
log_admin("[key_name(admin)] has brainwashed [key_name(C)] with the following objectives: [obj_list].")
|
||||
|
||||
/datum/objective/brainwashing
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
do_sparks(5, TRUE, AM)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/static)
|
||||
L.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
|
||||
L.clear_fullscreen("flash", 5)
|
||||
var/obj/item/transfer_valve/TTV = locate() in L.GetAllContents()
|
||||
if(TTV)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
linked.examine(user)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/overlay/ex_act()
|
||||
/obj/effect/clockwork/overlay/ex_act(severity, target, origin)
|
||||
return FALSE
|
||||
|
||||
/obj/effect/clockwork/overlay/singularity_act()
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
return TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/ex_act(severity)
|
||||
/obj/effect/clockwork/sigil/ex_act(severity, target, origin)
|
||||
visible_message("<span class='warning'>[src] scatters into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
|
||||
/obj/effect/clockwork/sigil/transmission/ex_act(severity, target, origin)
|
||||
if(severity == 3)
|
||||
adjust_clockwork_power(500) //Light explosions charge the network!
|
||||
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
/obj/effect/clockwork/servant_blocker/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/ex_act(severity, target)
|
||||
/obj/effect/clockwork/servant_blocker/ex_act(severity, target, origin)
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/safe_throw_at()
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/ex_act(severity)
|
||||
/obj/effect/clockwork/spatial_gateway/ex_act(severity, target, origin)
|
||||
if(severity == 1 && uses)
|
||||
uses = 0
|
||||
visible_message("<span class='warning'>[src] is disrupted!</span>")
|
||||
@@ -251,7 +251,7 @@
|
||||
name = "stable gateway"
|
||||
is_stable = TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/ex_act(severity)
|
||||
/obj/effect/clockwork/spatial_gateway/stable/ex_act(severity, target, origin)
|
||||
if(severity == 1)
|
||||
start_shutdown() //Yes, you can chain devastation-level explosions to delay a gateway shutdown, if you somehow manage to do it without breaking the obelisk. Is it worth it? Probably not.
|
||||
return TRUE
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 30)
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off.
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
/obj/item/clothing/head/helmet/clockwork/mob_can_equip(M, equipper, slot, disable_warning, bypass_equip_delay_self)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
@@ -98,7 +98,7 @@
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(M, equipper, slot, disable_warning, bypass_equip_delay_self)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
@@ -158,7 +158,7 @@
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
/obj/item/clothing/gloves/clockwork/mob_can_equip(M, equipper, slot, disable_warning, bypass_equip_delay_self)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
@@ -208,7 +208,7 @@
|
||||
else
|
||||
clothing_flags &= ~NOSLIP
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
/obj/item/clothing/shoes/clockwork/mob_can_equip(M, equipper, slot, disable_warning, bypass_equip_delay_self)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
@@ -264,7 +264,9 @@
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
|
||||
. = list()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
.["recollection"] = recollecting
|
||||
.["power"] = DisplayPower(get_clockwork_power())
|
||||
.["power_unformatted"] = get_clockwork_power()
|
||||
@@ -275,6 +277,7 @@
|
||||
if(S.tier == SCRIPTURE_PERIPHERAL) // This tier is skiped because this contains basetype stuff
|
||||
continue
|
||||
|
||||
// FUTURE IMPL: cache these perhaps?
|
||||
var/list/data = list()
|
||||
data["name"] = S.name
|
||||
data["descname"] = S.descname
|
||||
|
||||
@@ -214,5 +214,5 @@
|
||||
sleep(3) //so the animation completes properly
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/ex_act(severity)
|
||||
/obj/effect/clockwork/judicial_marker/ex_act(severity, target, origin)
|
||||
return
|
||||
|
||||
@@ -231,3 +231,31 @@
|
||||
to_chat(invoker, "<span class='nezbere'>\"Only one of my weapons may exist in this temporal stream!\"</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/cogscarab
|
||||
descname = "Building Construct"
|
||||
name = "Cogscarab"
|
||||
desc = "Creates a shell for a cogscarab, a drone that helps build your base!"
|
||||
invocations = list("Arise, drone!", "Create defenses for the true light!")
|
||||
channel_time = 80
|
||||
power_cost = 8000
|
||||
creator_message = "<span class='brass'>Your slab disgorges several chunks of replicant alloy that form into a spiderlike shell.</span>"
|
||||
usage_tip = "These machines will help you get a base built up while you go out to look for more followers."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a cogscarab, good for the backline."
|
||||
object_path = /obj/item/clockwork/construct_chassis/cogscarab/
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab
|
||||
combat_construct = FALSE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/cogscarab/update_construct_limit()
|
||||
var/human_servants = 0
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
var/mob/living/L = M.current
|
||||
if(ishuman(L) && L.stat != DEAD)
|
||||
human_servants++
|
||||
construct_limit = round(clamp((human_servants / 4), 1, 3)) //1 per 4 human servants, maximum of 3
|
||||
|
||||
+3
-3
@@ -141,7 +141,7 @@
|
||||
if(isliving(M.current) && M.current.stat != DEAD)
|
||||
var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
|
||||
do_teleport(M.current, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
|
||||
M.current.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
|
||||
M.current.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
|
||||
M.current.clear_fullscreen("flash", 5)
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
|
||||
recalls_remaining--
|
||||
@@ -197,7 +197,7 @@
|
||||
glow = new /obj/effect/clockwork/overlay/gateway_glow(get_turf(src))
|
||||
glow.linked = src
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/ex_act(severity)
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/ex_act(severity, target, origin)
|
||||
var/damage = max((obj_integrity * 0.7) / severity, 100) //requires multiple bombs to take down
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
var/turf/T = get_turf(M)
|
||||
if(is_servant_of_ratvar(M) && (!T || T.z != z))
|
||||
M.forceMove(get_step(src, SOUTH))
|
||||
M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash)
|
||||
M.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash)
|
||||
M.clear_fullscreen("flash", 5)
|
||||
progress_in_seconds += GATEWAY_SUMMON_RATE
|
||||
switch(progress_in_seconds)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
job_rank = ROLE_SERVANT_OF_RATVAR
|
||||
antag_moodlet = /datum/mood_event/cult
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/level/dwarfy/blacksmithing)
|
||||
ui_name = "AntagInfoClockwork"
|
||||
var/datum/action/innate/hierophant/hierophant_network = new
|
||||
threat = 3
|
||||
var/datum/team/clockcult/clock_team
|
||||
@@ -14,6 +15,12 @@
|
||||
var/ignore_eligibility_check = FALSE
|
||||
var/ignore_holy_water = FALSE
|
||||
|
||||
/datum/antagonist/clockcult/ui_data(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
.["HONOR_RATVAR"] = GLOB.ratvar_awakens
|
||||
|
||||
/datum/antagonist/clockcult/silent
|
||||
name = "Silent Clock Cultist"
|
||||
silent = TRUE
|
||||
@@ -22,6 +29,8 @@
|
||||
/datum/antagonist/clockcult/neutered
|
||||
name = "Neutered Clock Cultist"
|
||||
neutered = TRUE
|
||||
soft_antag = TRUE
|
||||
ui_name = null // no.
|
||||
|
||||
/datum/antagonist/clockcult/neutered/traitor
|
||||
name = "Traitor Clock Cultist"
|
||||
@@ -57,14 +66,6 @@
|
||||
if(. && !ignore_eligibility_check)
|
||||
. = is_eligible_servant(new_owner.current)
|
||||
|
||||
/datum/antagonist/clockcult/greet()
|
||||
if(!owner.current || silent)
|
||||
return
|
||||
owner.current.visible_message("<span class='heavy_brass'>[owner.current]'s eyes glow a blazing yellow!</span>", null, null, 7, owner.current) //don't show the owner this message
|
||||
to_chat(owner.current, "<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \
|
||||
Justiciar above all else. Perform his every whim without hesitation.</span>")
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/clockcult/on_gain()
|
||||
var/mob/living/current = owner.current
|
||||
SSticker.mode.servants_of_ratvar += owner
|
||||
@@ -240,3 +241,18 @@
|
||||
parts += printplayerlist(members - eminence)
|
||||
|
||||
return "<div class='panel clockborder'>[parts.Join("<br>")]</div>"
|
||||
|
||||
//I have no idea where to put this so I'm leaving it here. Loads reebe. Only one reebe can exist, so it's checked via a global var.
|
||||
/proc/load_reebe()
|
||||
if(GLOB.reebe_loaded)
|
||||
return TRUE
|
||||
var/list/errorList = list()
|
||||
var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE)
|
||||
if(errorList.len) // reebe failed to load
|
||||
message_admins("Reebe failed to load!")
|
||||
log_game("Reebe failed to load!")
|
||||
return FALSE
|
||||
for(var/datum/parsed_map/PM in reebes)
|
||||
PM.initTemplateBounds()
|
||||
GLOB.reebe_loaded = TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -387,8 +387,7 @@
|
||||
log_combat(user, M, "used a cult spell on", source.name, "")
|
||||
M.set_last_attacker(user)
|
||||
|
||||
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
|
||||
. = ..()
|
||||
/obj/item/melee/blood_magic/proc/post_cast(atom/target, mob/living/carbon/user, proximity)
|
||||
if(invocation)
|
||||
user.whisper(invocation, language = /datum/language/common)
|
||||
if(health_cost)
|
||||
@@ -467,6 +466,7 @@
|
||||
to_chat(user, "<span class='cultitalic'>In an brilliant flash of red, [L] [is_servant_of_ratvar(L) ? "writhes in pain!" : "falls to the ground!"]</span>")
|
||||
uses--
|
||||
..()
|
||||
post_cast(target, user, proximity)
|
||||
|
||||
//Teleportation
|
||||
/obj/item/melee/blood_magic/teleport
|
||||
@@ -480,40 +480,45 @@
|
||||
to_chat(user, "<span class='warning'>You can only teleport adjacent cultists with this spell!</span>")
|
||||
return
|
||||
if(iscultist(user))
|
||||
var/list/potential_runes = list()
|
||||
var/list/teleportnames = list()
|
||||
for(var/R in GLOB.teleport_runes)
|
||||
var/obj/effect/rune/teleport/T = R
|
||||
potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
|
||||
|
||||
if(!potential_runes.len)
|
||||
to_chat(user, "<span class='warning'>There are no valid runes to teleport to!</span>")
|
||||
log_game("Teleport talisman failed - no other teleport runes")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(is_away_level(T.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
log_game("Teleport spell failed - user in away mission")
|
||||
return
|
||||
|
||||
var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
|
||||
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
|
||||
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
|
||||
return
|
||||
var/turf/dest = get_turf(actual_selected_rune)
|
||||
if(is_blocked_turf(dest, TRUE))
|
||||
to_chat(user, "<span class='warning'>The target rune is blocked. Attempting to teleport to it would be massively unwise.</span>")
|
||||
return
|
||||
uses--
|
||||
var/turf/origin = get_turf(user)
|
||||
var/mob/living/L = target
|
||||
if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
|
||||
origin.visible_message("<span class='warning'>Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!</span>", \
|
||||
"<span class='cultitalic'>You speak the words of the talisman and find yourself somewhere else!</span>", "<i>You hear a sharp crack.</i>")
|
||||
dest.visible_message("<span class='warning'>There is a boom of outrushing air as something appears above the rune!</span>", null, "<i>You hear a boom.</i>")
|
||||
try_teleport(target, user, proximity)
|
||||
..()
|
||||
|
||||
/obj/item/melee/blood_magic/teleport/proc/try_teleport(atom/target, mob/living/carbon/user, proximity)
|
||||
set waitfor = FALSE
|
||||
var/list/potential_runes = list()
|
||||
var/list/teleportnames = list()
|
||||
for(var/R in GLOB.teleport_runes)
|
||||
var/obj/effect/rune/teleport/T = R
|
||||
potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
|
||||
|
||||
if(!potential_runes.len)
|
||||
to_chat(user, "<span class='warning'>There are no valid runes to teleport to!</span>")
|
||||
log_game("Teleport talisman failed - no other teleport runes")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(is_away_level(T.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
log_game("Teleport spell failed - user in away mission")
|
||||
return
|
||||
|
||||
var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
|
||||
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
|
||||
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
|
||||
return
|
||||
var/turf/dest = get_turf(actual_selected_rune)
|
||||
if(is_blocked_turf(dest, TRUE))
|
||||
to_chat(user, "<span class='warning'>The target rune is blocked. Attempting to teleport to it would be massively unwise.</span>")
|
||||
return
|
||||
uses--
|
||||
var/turf/origin = get_turf(user)
|
||||
var/mob/living/L = target
|
||||
if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
|
||||
origin.visible_message("<span class='warning'>Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!</span>", \
|
||||
"<span class='cultitalic'>You speak the words of the talisman and find yourself somewhere else!</span>", "<i>You hear a sharp crack.</i>")
|
||||
dest.visible_message("<span class='warning'>There is a boom of outrushing air as something appears above the rune!</span>", null, "<i>You hear a boom.</i>")
|
||||
post_cast(target, user, proximity)
|
||||
|
||||
//Shackles
|
||||
/obj/item/melee/blood_magic/shackles
|
||||
name = "Binding Aura"
|
||||
@@ -530,6 +535,7 @@
|
||||
user.visible_message("<span class='cultitalic'>This victim doesn't have enough arms to complete the restraint!</span>")
|
||||
return
|
||||
..()
|
||||
post_cast(target, user, proximity)
|
||||
|
||||
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
|
||||
if(!C.handcuffed)
|
||||
@@ -583,6 +589,7 @@
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
|
||||
new /obj/structure/constructshell(T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
post_cast(target, proximity_flag, user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need 50 metal to produce a construct shell!</span>")
|
||||
else if(istype(target, /obj/item/stack/sheet/plasteel))
|
||||
@@ -593,56 +600,73 @@
|
||||
new /obj/item/stack/sheet/runed_metal(T,quantity)
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
post_cast(target, user, proximity_flag)
|
||||
if(istype(target, /obj/item/clothing/suit/hooded/wintercoat) && target.type != /obj/item/clothing/suit/hooded/wintercoat/narsie)
|
||||
if (do_after(user,30,target=target))
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
|
||||
qdel(target)
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
convert_coat(target, user, proximity_flag, T)
|
||||
else if(istype(target,/mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/candidate = target
|
||||
if(!iscultist(user, TRUE))
|
||||
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
|
||||
else if(candidate.mmi)
|
||||
user.visible_message("<span class='danger'>A dark cloud emanates from [user]'s hand and swirls around [candidate]!</span>")
|
||||
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
|
||||
var/prev_color = candidate.color
|
||||
candidate.color = "black"
|
||||
if(do_after(user, 90, target = candidate))
|
||||
candidate.emp_act(80)
|
||||
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
|
||||
user.visible_message("<span class='danger'>The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!</span>")
|
||||
switch(construct_class)
|
||||
if("Juggernaut")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
|
||||
if("Wraith")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
|
||||
if("Artificer")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
uses--
|
||||
candidate.mmi = null
|
||||
qdel(candidate)
|
||||
else
|
||||
candidate.color = prev_color
|
||||
else
|
||||
uses--
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!</span>")
|
||||
new /obj/structure/constructshell(T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
convert_borg(target, user, proximity_flag, T)
|
||||
else if(istype(target,/obj/machinery/door/airlock))
|
||||
playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
|
||||
do_sparks(5, TRUE, target)
|
||||
if(do_after(user, 50, target = user))
|
||||
target.narsie_act()
|
||||
uses--
|
||||
user.visible_message("<span class='warning'>Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
convert_door(target, user, proximity_flag, T)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/melee/blood_magic/construction/proc/convert_coat(atom/target, mob/user, proximity_flag, turf/T)
|
||||
set waitfor = FALSE
|
||||
if(do_after(user,30,target=target))
|
||||
new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
|
||||
qdel(target)
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
post_cast(target, user, proximity_flag)
|
||||
|
||||
/obj/item/melee/blood_magic/construction/proc/convert_door(atom/target, mob/user, proximity_flag, turf/T)
|
||||
set waitfor = FALSE
|
||||
playsound(T, 'sound/machines/airlockforced.ogg', 50, 1)
|
||||
do_sparks(5, TRUE, target)
|
||||
if(do_after(user, 50, target = user))
|
||||
target.narsie_act()
|
||||
uses--
|
||||
user.visible_message("<span class='warning'>Black ribbons suddenly emanate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
post_cast(target, user, proximity_flag)
|
||||
|
||||
/obj/item/melee/blood_magic/construction/proc/convert_borg(atom/target, mob/user, proximity_flag, turf/T)
|
||||
set waitfor = FALSE
|
||||
var/mob/living/silicon/robot/candidate = target
|
||||
if(!iscultist(user, TRUE))
|
||||
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
|
||||
return
|
||||
else if(candidate.mmi)
|
||||
user.visible_message("<span class='danger'>A dark cloud emanates from [user]'s hand and swirls around [candidate]!</span>")
|
||||
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
|
||||
var/prev_color = candidate.color
|
||||
candidate.color = "black"
|
||||
if(do_after(user, 90, target = candidate))
|
||||
candidate.emp_act(80)
|
||||
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
|
||||
user.visible_message("<span class='danger'>The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!</span>")
|
||||
switch(construct_class)
|
||||
if("Juggernaut")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
|
||||
if("Wraith")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
|
||||
if("Artificer")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
uses--
|
||||
candidate.mmi = null
|
||||
qdel(candidate)
|
||||
else
|
||||
candidate.color = prev_color
|
||||
else
|
||||
uses--
|
||||
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [candidate] - twisting it into a construct shell!</span>")
|
||||
new /obj/structure/constructshell(T)
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
post_cast(target, user, proximity_flag)
|
||||
|
||||
//Armor: Gives the target a basic cultist combat loadout
|
||||
/obj/item/melee/blood_magic/armor
|
||||
name = "Bladed Aura"
|
||||
@@ -665,6 +689,7 @@
|
||||
C.put_in_hands(new /obj/item/melee/cultblade(user))
|
||||
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
|
||||
..()
|
||||
post_cast(target, user, proximity)
|
||||
|
||||
/obj/item/melee/blood_magic/manipulator
|
||||
name = "Ritual Aura"
|
||||
@@ -693,7 +718,9 @@
|
||||
H.adjust_integration_blood(uses * 2)
|
||||
to_chat(user,"<span class='danger'>You use the last of your blood rites to restore what blood you could!</span>")
|
||||
uses = 0
|
||||
return ..()
|
||||
..()
|
||||
post_cast(target, user, proximity)
|
||||
return
|
||||
else
|
||||
H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio)
|
||||
uses -= round(restore_blood/2)
|
||||
@@ -758,6 +785,7 @@
|
||||
if(istype(target, /obj/effect/decal/cleanable/blood))
|
||||
blood_draw(target, user)
|
||||
..()
|
||||
post_cast()
|
||||
|
||||
/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user)
|
||||
var/temp = 0
|
||||
|
||||
@@ -660,40 +660,42 @@
|
||||
return
|
||||
|
||||
if(istype(A, /obj/item))
|
||||
|
||||
var/list/cultists = list()
|
||||
for(var/datum/mind/M in SSticker.mode.cult)
|
||||
if(M.current && M.current.stat != DEAD)
|
||||
cultists |= M.current
|
||||
var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
|
||||
if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
|
||||
return
|
||||
if(!cultist_to_receive)
|
||||
to_chat(user, "<span class='cult italic'>You require a destination!</span>")
|
||||
log_game("Void torch failed - no target")
|
||||
return
|
||||
if(cultist_to_receive.stat == DEAD)
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] has died!</span>")
|
||||
log_game("Void torch failed - target died")
|
||||
return
|
||||
if(!iscultist(cultist_to_receive))
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] is not a follower of the Geometer!</span>")
|
||||
log_game("Void torch failed - target was deconverted")
|
||||
return
|
||||
if(A in user.GetAllContents())
|
||||
to_chat(user, "<span class='cult italic'>[A] must be on a surface in order to teleport it!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='cult italic'>You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
|
||||
cultist_to_receive.put_in_hands(A)
|
||||
charges--
|
||||
to_chat(user, "\The [src] now has [charges] charge\s.")
|
||||
if(charges == 0)
|
||||
qdel(src)
|
||||
transmit_item(A, user, proximity)
|
||||
|
||||
else
|
||||
..()
|
||||
to_chat(user, "<span class='warning'>\The [src] can only transport items!</span>")
|
||||
|
||||
/obj/item/flashlight/flare/culttorch/proc/transmit_item(atom/movable/A, mob/user, proximity)
|
||||
set waitfor = FALSE
|
||||
var/list/cultists = list()
|
||||
for(var/datum/mind/M in SSticker.mode.cult)
|
||||
if(M.current && M.current.stat != DEAD)
|
||||
cultists |= M.current
|
||||
var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
|
||||
if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
|
||||
return
|
||||
if(!cultist_to_receive)
|
||||
to_chat(user, "<span class='cult italic'>You require a destination!</span>")
|
||||
log_game("Void torch failed - no target")
|
||||
return
|
||||
if(cultist_to_receive.stat == DEAD)
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] has died!</span>")
|
||||
log_game("Void torch failed - target died")
|
||||
return
|
||||
if(!iscultist(cultist_to_receive))
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] is not a follower of the Geometer!</span>")
|
||||
log_game("Void torch failed - target was deconverted")
|
||||
return
|
||||
if(A in user.GetAllContents())
|
||||
to_chat(user, "<span class='cult italic'>[A] must be on a surface in order to teleport it!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='cult italic'>You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
|
||||
cultist_to_receive.put_in_hands(A)
|
||||
charges--
|
||||
to_chat(user, "\The [src] now has [charges] charge\s.")
|
||||
if(charges == 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/cult_spear
|
||||
name = "blood halberd"
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
/mob/living/carbon/true_devil/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
|
||||
return 666
|
||||
|
||||
/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, override_protection = 0)
|
||||
/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/tiled/flash, override_protection = 0)
|
||||
if(mind && has_bane(BANE_LIGHT))
|
||||
mind.disrupt_spells(-500)
|
||||
return ..() //flashes don't stop devils UNLESS it's their bane.
|
||||
@@ -179,7 +179,7 @@
|
||||
/mob/living/carbon/true_devil/is_literate()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/true_devil/ex_act(severity, ex_target)
|
||||
/mob/living/carbon/true_devil/ex_act(severity, target, origin)
|
||||
if(!ascended)
|
||||
var/b_loss
|
||||
switch (severity)
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_in_antagpanel = FALSE
|
||||
threat = 2
|
||||
ui_name = "AntagInfoMorph"
|
||||
|
||||
//It does nothing! (Besides tracking)
|
||||
|
||||
@@ -4,3 +4,5 @@
|
||||
show_name_in_check_antagonists = TRUE
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
ui_name = "AntagInfoNightmare"
|
||||
suicide_cry = "FOR THE DARKNESS!!"
|
||||
|
||||
@@ -236,6 +236,8 @@
|
||||
var/obj/machinery/nuclearbomb/tracked_nuke
|
||||
var/core_objective = /datum/objective/nuclear
|
||||
var/memorized_code
|
||||
var/list/team_discounts
|
||||
var/datum/weakref/war_button_ref
|
||||
|
||||
/datum/team/nuclear/New()
|
||||
..()
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
// Give uplink
|
||||
var/obj/item/uplink_holder = owner.equip_traitor(uplink_owner = src)
|
||||
var/obj/item/uplink_holder = owner.equip_traitor()
|
||||
var/datum/component/uplink/uplink = uplink_holder.GetComponent(/datum/component/uplink)
|
||||
uplink.telecrystals = INITIAL_CRYSTALS
|
||||
// Give AI hacking board
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
//Immunities
|
||||
|
||||
/mob/living/simple_animal/revenant/ex_act(severity, target)
|
||||
/mob/living/simple_animal/revenant/ex_act(severity, target, origin)
|
||||
return 1 //Immune to the effects of explosions.
|
||||
|
||||
/mob/living/simple_animal/revenant/wave_ex_act(power, datum/wave_explosion/explosion, dir)
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
released and fully healed, because in the end it's just a jape, \
|
||||
sibling!</B>"
|
||||
|
||||
/mob/living/simple_animal/slaughter/laughter/ex_act(severity)
|
||||
/mob/living/simple_animal/slaughter/laughter/ex_act(severity, target, origin)
|
||||
switch(severity)
|
||||
if(1)
|
||||
death()
|
||||
|
||||
@@ -7,37 +7,51 @@
|
||||
/datum/antagonist/traitor/internal_affairs
|
||||
name = "Internal Affairs Agent"
|
||||
employer = "Nanotrasen"
|
||||
special_role = "internal affairs agent"
|
||||
suicide_cry = "FOR THE COMPANY!!"
|
||||
antagpanel_category = "IAA"
|
||||
var/special_role = "internal affairs agent"
|
||||
var/syndicate = FALSE
|
||||
var/last_man_standing = FALSE
|
||||
var/list/datum/mind/targets_stolen
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/New()
|
||||
. = ..()
|
||||
LAZYADD(targets_stolen, src)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/give_pinpointer()
|
||||
if(owner && owner.current)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
|
||||
if(owner.current)
|
||||
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/apply_innate_effects()
|
||||
.=..() //in case the base is used in future
|
||||
if(owner && owner.current)
|
||||
. = ..()
|
||||
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
|
||||
if(owner.current)
|
||||
give_pinpointer(owner.current)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/remove_innate_effects()
|
||||
.=..()
|
||||
if(owner && owner.current)
|
||||
. = ..()
|
||||
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
|
||||
if(owner.current)
|
||||
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/on_gain()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
.=..()
|
||||
. = ..()
|
||||
/datum/antagonist/traitor/internal_affairs/on_removal()
|
||||
STOP_PROCESSING(SSprocessing,src)
|
||||
.=..()
|
||||
. = ..()
|
||||
/datum/antagonist/traitor/internal_affairs/process()
|
||||
iaa_process()
|
||||
|
||||
|
||||
/datum/status_effect/agent_pinpointer
|
||||
id = "agent_pinpointer"
|
||||
duration = -1
|
||||
@@ -46,6 +60,8 @@
|
||||
var/minimum_range = PINPOINTER_MINIMUM_RANGE
|
||||
var/range_fuzz_factor = PINPOINTER_EXTRA_RANDOM_RANGE
|
||||
var/mob/scan_target = null
|
||||
var/range_mid = 8
|
||||
var/range_far = 16
|
||||
|
||||
/atom/movable/screen/alert/status_effect/agent_pinpointer
|
||||
name = "Internal Affairs Integrated Pinpointer"
|
||||
@@ -66,13 +82,13 @@
|
||||
linked_alert.icon_state = "pinondirect"
|
||||
else
|
||||
linked_alert.setDir(get_dir(here, there))
|
||||
switch(get_dist(here, there))
|
||||
if(1 to 8)
|
||||
linked_alert.icon_state = "pinonclose"
|
||||
if(9 to 16)
|
||||
linked_alert.icon_state = "pinonmedium"
|
||||
if(16 to INFINITY)
|
||||
linked_alert.icon_state = "pinonfar"
|
||||
var/dist = (get_dist(here, there))
|
||||
if(dist >= 1 && dist <= range_mid)
|
||||
linked_alert.icon_state = "pinonclose"
|
||||
else if(dist > range_mid && dist <= range_far)
|
||||
linked_alert.icon_state = "pinonmedium"
|
||||
else if(dist > range_far)
|
||||
linked_alert.icon_state = "pinonfar"
|
||||
|
||||
/datum/status_effect/agent_pinpointer/proc/scan_for_target()
|
||||
scan_target = null
|
||||
@@ -99,37 +115,42 @@
|
||||
return (istype(O, /datum/objective/assassinate/internal)||istype(O, /datum/objective/destroy/internal))
|
||||
|
||||
/datum/antagonist/traitor/proc/replace_escape_objective()
|
||||
if(!owner || !objectives.len)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
if(!objectives.len)
|
||||
return
|
||||
for (var/objective_ in objectives)
|
||||
if(!(istype(objective_, /datum/objective/escape)||istype(objective_, /datum/objective/survive)))
|
||||
for (var/objective in objectives)
|
||||
if(!(istype(objective, /datum/objective/escape) || istype(objective, /datum/objective/survive)))
|
||||
continue
|
||||
remove_objective(objective_)
|
||||
objectives -= objective
|
||||
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/reinstate_escape_objective()
|
||||
if(!owner||!objectives.len)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
if(!objectives.len)
|
||||
return
|
||||
for (var/objective_ in objectives)
|
||||
if(!istype(objective_, /datum/objective/martyr))
|
||||
for (var/objective in objectives)
|
||||
if(!istype(objective, /datum/objective/martyr))
|
||||
continue
|
||||
remove_objective(objective_)
|
||||
remove_objective(objective)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
for (var/datum/objective/martyr/martyr_objective in objectives)
|
||||
objectives -= martyr_objective
|
||||
|
||||
var/datum/objective/escape_objective = new /datum/objective/escape()
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
objectives += escape_objective
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/steal_targets(datum/mind/victim)
|
||||
if(!owner.current||owner.current.stat==DEAD)
|
||||
return
|
||||
to_chat(owner.current, "<span class='userdanger'> Target eliminated: [victim.name]</span>")
|
||||
LAZYINITLIST(targets_stolen)
|
||||
to_chat(owner.current, span_userdanger("Target eliminated: [victim.name]"))
|
||||
for(var/objective_ in victim.get_all_objectives())
|
||||
if(istype(objective_, /datum/objective/assassinate/internal))
|
||||
var/datum/objective/assassinate/internal/objective = objective_
|
||||
@@ -143,7 +164,7 @@
|
||||
add_objective(new_objective)
|
||||
targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
to_chat(owner.current, span_userdanger("New target added to database: [objective.target.name] ([status_text])"))
|
||||
else if(istype(objective_, /datum/objective/destroy/internal))
|
||||
var/datum/objective/destroy/internal/objective = objective_
|
||||
var/datum/objective/destroy/internal/new_objective = new
|
||||
@@ -156,7 +177,7 @@
|
||||
add_objective(new_objective)
|
||||
targets_stolen += objective.target
|
||||
var/status_text = objective.check_completion() ? "neutralised" : "active"
|
||||
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
|
||||
to_chat(owner.current, span_userdanger("New target added to database: [objective.target.name] ([status_text])"))
|
||||
last_man_standing = TRUE
|
||||
for(var/objective_ in objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
@@ -167,13 +188,15 @@
|
||||
return
|
||||
if(last_man_standing)
|
||||
if(syndicate)
|
||||
to_chat(owner.current,"<span class='userdanger'>All the suspected agents are dead, and no more is required of you. Die a glorious death, agent.</span>")
|
||||
replace_escape_objective(owner)
|
||||
to_chat(owner.current,span_userdanger("All the suspected agents are dead, and no more is required of you. Die a glorious death, agent."))
|
||||
else
|
||||
to_chat(owner.current,"<span class='userdanger'>All the other agents are dead. You have done us all a great service and shall be honorably exiled upon returning to base.</span>")
|
||||
to_chat(owner.current,span_userdanger("All the other agents are dead. You have done us all a great service and shall be honorably exiled upon returning to base."))
|
||||
replace_escape_objective(owner)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/iaa_process()
|
||||
if(owner&&owner.current&&owner.current.stat!=DEAD)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
if(owner.current && owner.current.stat != DEAD)
|
||||
for(var/objective_ in objectives)
|
||||
if(!is_internal_objective(objective_))
|
||||
continue
|
||||
@@ -188,12 +211,12 @@
|
||||
objective.stolen = TRUE
|
||||
else
|
||||
if(objective.stolen)
|
||||
var/fail_msg = "<span class='userdanger'>Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! </span>"
|
||||
var/fail_msg = span_userdanger("Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! ")
|
||||
if(last_man_standing)
|
||||
if(syndicate)
|
||||
fail_msg += "<span class='userdanger'> You no longer have permission to die. </span>"
|
||||
fail_msg += span_userdanger(" You no longer have permission to die. ")
|
||||
else
|
||||
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to great shame.</span>"
|
||||
fail_msg += span_userdanger(" The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated.")
|
||||
reinstate_escape_objective(owner)
|
||||
last_man_standing = FALSE
|
||||
to_chat(owner.current, fail_msg)
|
||||
@@ -220,29 +243,24 @@
|
||||
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
var/datum/objective/escape_objective = new /datum/objective/escape()
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/greet_iaa()
|
||||
var/crime = pick("distribution of contraband" , "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "receiving bribes", "malpractice", "worship of prohibited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
var/crime = pick("distribution of contraband", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "receiving bribes", "malpractice", "worship of prohibited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>You are the [special_role].</span>")
|
||||
to_chat(owner.current, span_userdanger("You are the [special_role]."))
|
||||
if(syndicate)
|
||||
to_chat(owner.current, "<span class='userdanger'>GREAT LEADER IS DEAD. NANOTRASEN MUST FALL.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Your have infiltrated this vessel to cause chaos and assassinate targets known to have conspired against the Syndicate.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>You have been provided with a standard uplink to accomplish your task. </span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>By no means reveal that you are a Syndicate agent. By no means reveal that your targets are being hunted.</span>")
|
||||
to_chat(owner.current, span_userdanger("Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court."))
|
||||
to_chat(owner.current, "<span class='warningplain'><B><font size=5 color=red>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</font></B></span>")
|
||||
to_chat(owner.current, span_userdanger("You have been provided with a standard uplink to accomplish your task."))
|
||||
else
|
||||
to_chat(owner.current, "<span class='userdanger'>CAUTION: Your legal status as a citizen of NanoTrasen will be permanently revoked upon completion of your first contract.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target has been suspected of [crime], and must be removed from this plane.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>While you have a license to kill, you are to eliminate your targets with no collateral or unrelated deaths.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>For the sake of plausable deniability, you have been equipped with captured Syndicate equipment via uplink.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>By no means reveal that you, or any other NT employees, are undercover agents.</span>")
|
||||
to_chat(owner.current, span_userdanger("Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial."))
|
||||
to_chat(owner.current, "<span class='warningplain'><B><font size=5 color=red>While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.</font></B></span>")
|
||||
to_chat(owner.current, span_userdanger("For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink."))
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
|
||||
to_chat(owner.current, span_userdanger("Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them."))
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/greet()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
chaos = 5
|
||||
threat = 5
|
||||
min_players = 20
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_tc/contract_kit)
|
||||
|
||||
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/martyr/O = new
|
||||
|
||||
@@ -11,6 +11,8 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
/// Minimum players for this to randomly roll via get_random_traitor_kind().
|
||||
var/min_players = 0
|
||||
var/list/uplink_filters
|
||||
/// Specific tgui theme for the player's antag info panel.
|
||||
var/tgui_theme = "syndicate"
|
||||
|
||||
/datum/traitor_class/New()
|
||||
..()
|
||||
|
||||
@@ -5,14 +5,22 @@
|
||||
job_rank = ROLE_TRAITOR
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
|
||||
var/special_role = ROLE_TRAITOR
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
ui_name = "AntagInfoTraitor"
|
||||
suicide_cry = "FOR THE SYNDICATE!!"
|
||||
var/employer = "The Syndicate"
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
|
||||
///special datum about what kind of employer the trator has
|
||||
var/datum/traitor_class/traitor_kind
|
||||
|
||||
///reference to the uplink this traitor was given, if they were.
|
||||
var/datum/component/uplink/uplink
|
||||
|
||||
var/datum/contractor_hub/contractor_hub
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
threat = 5
|
||||
|
||||
/datum/antagonist/traitor/New()
|
||||
@@ -45,7 +53,7 @@
|
||||
/datum/antagonist/traitor/process()
|
||||
traitor_kind.on_process(src)
|
||||
|
||||
/proc/get_random_traitor_kind(var/list/blacklist = list())
|
||||
/proc/get_random_traitor_kind(list/blacklist = list())
|
||||
var/list/weights = list()
|
||||
for(var/C in GLOB.traitor_classes)
|
||||
if(!(C in blacklist))
|
||||
@@ -62,23 +70,24 @@
|
||||
return choice
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
owner.special_role = job_rank
|
||||
if(owner.current && isAI(owner.current))
|
||||
set_traitor_kind(TRAITOR_AI)
|
||||
else
|
||||
set_traitor_kind(get_random_traitor_kind())
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
finalize_traitor()
|
||||
..()
|
||||
uplink = owner.find_syndicate_uplink()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,span_userdanger("You are no longer the [job_rank]!"))
|
||||
//Remove malf powers.
|
||||
traitor_kind.on_removal(src)
|
||||
SSticker.mode.traitors -= owner
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
owner.special_role = null
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/proc/handle_hearing(datum/source, list/hearing_args)
|
||||
var/message = hearing_args[HEARING_RAW_MESSAGE]
|
||||
@@ -93,6 +102,7 @@
|
||||
/datum/antagonist/traitor/proc/remove_objective(datum/objective/O)
|
||||
objectives -= O
|
||||
|
||||
/// Generates a complete set of traitor objectives up to the traitor objective limit, including non-generic objectives such as martyr and hijack.
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
traitor_kind.forge_objectives(src)
|
||||
|
||||
@@ -151,21 +161,42 @@
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
UnregisterSignal(M, COMSIG_MOVABLE_HEAR)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["phrases"] = jointext(GLOB.syndicate_code_phrase, ", ")
|
||||
data["responses"] = jointext(GLOB.syndicate_code_response, ", ")
|
||||
data["theme"] = traitor_kind.tgui_theme //traitor_flavor["ui_theme"]
|
||||
data["code"] = uplink.unlock_code
|
||||
data["intro"] = "You are from [traitor_kind.employer]." //traitor_flavor["introduction"]
|
||||
data["allies"] = "Most other syndicate operatives are not to be trusted (but try not to rat them out), as they might have been assigned opposing objectives." //traitor_flavor["allies"]
|
||||
data["goal"] = "We do not approve of mindless killing of innocent workers; \"get in, get done, get out\" is our motto." //traitor_flavor["goal"]
|
||||
data["has_uplink"] = uplink ? TRUE : FALSE
|
||||
if(uplink)
|
||||
data["uplink_intro"] = "You have been provided with a standard uplink to accomplish your task." //traitor_flavor["uplink"]
|
||||
data["uplink_unlock_info"] = uplink.unlock_text
|
||||
data["objectives"] = get_objectives()
|
||||
return data
|
||||
|
||||
/// Outputs this shift's codewords and responses to the antag's chat and copies them to their memory.
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
if(!owner.current)
|
||||
return
|
||||
var/mob/traitor_mob=owner.current
|
||||
|
||||
var/mob/traitor_mob = owner.current
|
||||
|
||||
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
|
||||
var/responses = jointext(GLOB.syndicate_code_response, ", ")
|
||||
|
||||
var/dat = "<U><B>The Syndicate have provided you with the following codewords to identify fellow agents:</B></U>\n"
|
||||
dat += "<B>Code Phrase</B>: <span class='blue'>[phrases]</span>\n"
|
||||
dat += "<B>Code Response</B>: <span class='red'>[responses]</span>"
|
||||
to_chat(traitor_mob, dat)
|
||||
to_chat(traitor_mob, "<U><B>The Syndicate have provided you with the following codewords to identify fellow agents:</B></U>")
|
||||
to_chat(traitor_mob, "<B>Code Phrase</B>: [span_blue("[phrases]")]")
|
||||
to_chat(traitor_mob, "<B>Code Response</B>: [span_red("[responses]")]")
|
||||
|
||||
antag_memory += "<b>Code Phrase</b>: <span class='blue'>[phrases]</span><br>"
|
||||
antag_memory += "<b>Code Response</b>: <span class='red'>[responses]</span><br>"
|
||||
antag_memory += "<b>Code Phrase</b>: [span_blue("[phrases]")]<br>"
|
||||
antag_memory += "<b>Code Response</b>: [span_red("[responses]")]<br>"
|
||||
|
||||
to_chat(traitor_mob, "Use the codewords during regular conversation to identify other agents. Proceed with caution, however, as everyone is a potential foe.")
|
||||
to_chat(traitor_mob, span_alertwarning("You memorize the codewords, allowing you to recognise them when heard."))
|
||||
|
||||
/datum/antagonist/traitor/proc/add_law_zero()
|
||||
var/mob/living/silicon/ai/killer = owner.current
|
||||
@@ -220,44 +251,43 @@
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
|
||||
//TODO Collate
|
||||
/datum/antagonist/traitor/roundend_report()
|
||||
var/list/result = list()
|
||||
|
||||
var/traitorwin = TRUE
|
||||
var/traitor_won = TRUE
|
||||
|
||||
result += printplayer(owner)
|
||||
|
||||
var/TC_uses = 0
|
||||
var/uplink_true = FALSE
|
||||
var/used_telecrystals = 0
|
||||
var/uplink_owned = FALSE
|
||||
var/purchases = ""
|
||||
|
||||
LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
|
||||
var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[owner.key]
|
||||
if(H)
|
||||
TC_uses = H.total_spent
|
||||
uplink_true = TRUE
|
||||
purchases += H.generate_render(FALSE)
|
||||
// Uplinks add an entry to uplink_purchase_logs_by_key on init.
|
||||
var/datum/uplink_purchase_log/purchase_log = GLOB.uplink_purchase_logs_by_key[owner.key]
|
||||
if(purchase_log)
|
||||
used_telecrystals = purchase_log.total_spent
|
||||
uplink_owned = TRUE
|
||||
purchases += purchase_log.generate_render(FALSE)
|
||||
|
||||
var/objectives_text = ""
|
||||
if(objectives.len)//If the traitor had no objectives, don't need to process this.
|
||||
if(objectives.len) //If the traitor had no objectives, don't need to process this.
|
||||
var/count = 1
|
||||
for(var/datum/objective/objective in objectives)
|
||||
if(objective.completable)
|
||||
var/completion = objective.check_completion()
|
||||
if(completion >= 1)
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
|
||||
else if(completion <= 0)
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
traitorwin = FALSE
|
||||
else
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
|
||||
var/completion = objective.check_completion()
|
||||
if(completion >= 1)
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] [span_greentext("Success!")]"
|
||||
else if(completion <= 0)
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] [span_redtext("Fail.")]"
|
||||
traitor_won = FALSE
|
||||
else
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text]"
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
|
||||
|
||||
count++
|
||||
|
||||
if(uplink_true)
|
||||
var/uplink_text = "(used [TC_uses] TC) [purchases]"
|
||||
if(TC_uses==0 && traitorwin)
|
||||
if(uplink_owned)
|
||||
var/uplink_text = "(used [used_telecrystals] TC) [purchases]"
|
||||
if((used_telecrystals == 0) && traitor_won)
|
||||
var/static/icon/badass = icon('icons/badass.dmi', "badass")
|
||||
uplink_text += "<BIG>[icon2html(badass, world)]</BIG>"
|
||||
result += uplink_text
|
||||
@@ -266,55 +296,59 @@
|
||||
|
||||
var/special_role_text = lowertext(name)
|
||||
|
||||
if(contractor_hub)
|
||||
if (contractor_hub)
|
||||
result += contractor_round_end()
|
||||
|
||||
if(traitorwin)
|
||||
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
|
||||
if(traitor_won)
|
||||
result += span_greentext("The [special_role_text] was successful!")
|
||||
else
|
||||
result += "<span class='redtext'>The [special_role_text] has failed!</span>"
|
||||
result += span_redtext("The [special_role_text] has failed!")
|
||||
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
|
||||
|
||||
return result.Join("<br>")
|
||||
|
||||
/// Proc detailing contract kit buys/completed contracts/additional info
|
||||
/datum/antagonist/traitor/proc/contractor_round_end()
|
||||
var result = ""
|
||||
var total_spent_rep = 0
|
||||
var/result = ""
|
||||
var/total_spent_rep = 0
|
||||
|
||||
var/completed_contracts = 0
|
||||
var/completed_contracts = contractor_hub.contracts_completed
|
||||
var/tc_total = contractor_hub.contract_TC_payed_out + contractor_hub.contract_TC_to_redeem
|
||||
for(var/datum/syndicate_contract/contract in contractor_hub.assigned_contracts)
|
||||
if(contract.status == CONTRACT_STATUS_COMPLETE)
|
||||
completed_contracts++
|
||||
|
||||
var/contractor_item_icons = "" // Icons of purchases
|
||||
var/contractor_support_unit = "" // Set if they had a support unit - and shows appended to their contracts completed
|
||||
|
||||
for(var/datum/contractor_item/contractor_purchase in contractor_hub.purchased_items) // Get all the icons/total cost for all our items bought
|
||||
/// Get all the icons/total cost for all our items bought
|
||||
for (var/datum/contractor_item/contractor_purchase in contractor_hub.purchased_items)
|
||||
contractor_item_icons += "<span class='tooltip_container'>\[ <i class=\"fas [contractor_purchase.item_icon]\"></i><span class='tooltip_hover'><b>[contractor_purchase.name] - [contractor_purchase.cost] Rep</b><br><br>[contractor_purchase.desc]</span> \]</span>"
|
||||
|
||||
total_spent_rep += contractor_purchase.cost
|
||||
if(istype(contractor_purchase, /datum/contractor_item/contractor_partner)) // Special case for reinforcements, we want to show their ckey and name on round end.
|
||||
|
||||
/// Special case for reinforcements, we want to show their ckey and name on round end.
|
||||
if (istype(contractor_purchase, /datum/contractor_item/contractor_partner))
|
||||
var/datum/contractor_item/contractor_partner/partner = contractor_purchase
|
||||
contractor_support_unit += "<br><b>[partner.partner_mind.key]</b> played <b>[partner.partner_mind.current.name]</b>, their contractor support unit."
|
||||
|
||||
if (contractor_hub.purchased_items.len)
|
||||
result += "<br>(used [total_spent_rep] Rep)"
|
||||
result += "<br>(used [total_spent_rep] Rep) "
|
||||
result += contractor_item_icons
|
||||
result += "<br>"
|
||||
if(completed_contracts > 0)
|
||||
if (completed_contracts > 0)
|
||||
var/pluralCheck = "contract"
|
||||
if(completed_contracts > 1)
|
||||
if (completed_contracts > 1)
|
||||
pluralCheck = "contracts"
|
||||
result += "Completed <span class='greentext'>[completed_contracts]</span> [pluralCheck] for a total of \
|
||||
<span class='greentext'>[tc_total] TC</span>!<br>"
|
||||
|
||||
result += "Completed [span_greentext("[completed_contracts]")] [pluralCheck] for a total of \
|
||||
[span_greentext("[tc_total] TC")]![contractor_support_unit]<br>"
|
||||
|
||||
return result
|
||||
|
||||
/datum/antagonist/traitor/roundend_report_footer()
|
||||
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
|
||||
var/responses = jointext(GLOB.syndicate_code_response, ", ")
|
||||
|
||||
var message = "<br><b>The code phrases were:</b> <span class='bluetext'>[phrases]</span><br>\
|
||||
<b>The code responses were:</b> <span class='redtext'>[responses]</span><br>"
|
||||
var/message = "<br><b>The code phrases were:</b> <span class='bluetext'>[phrases]</span><br>\
|
||||
<b>The code responses were:</b> [span_redtext("[responses]")]<br>"
|
||||
|
||||
return message
|
||||
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
roundend_category = "wizards/witches"
|
||||
antagpanel_category = "Wizard"
|
||||
job_rank = ROLE_WIZARD
|
||||
antag_hud_type = ANTAG_HUD_WIZ
|
||||
antag_hud_name = "wizard"
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
threat = 30
|
||||
hijack_speed = 0.5
|
||||
ui_name = "AntagInfoWizard"
|
||||
suicide_cry = "FOR THE FEDERATION!!"
|
||||
var/give_objectives = TRUE
|
||||
var/strip = TRUE //strip before equipping
|
||||
var/allow_rename = TRUE
|
||||
var/hud_version = "wizard"
|
||||
var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
@@ -50,16 +53,17 @@
|
||||
wiz_team = new(owner)
|
||||
wiz_team.name = "[owner.current.real_name] team"
|
||||
wiz_team.master_wizard = src
|
||||
update_wiz_icons_added(owner.current)
|
||||
add_antag_hud(antag_hud_type, antag_hud_name, owner.current)
|
||||
|
||||
/datum/antagonist/wizard/proc/send_to_lair()
|
||||
if(!owner || !owner.current)
|
||||
if(!owner)
|
||||
CRASH("Antag datum with no owner.")
|
||||
if(!owner.current)
|
||||
return
|
||||
if(!GLOB.wizardstart.len)
|
||||
SSjob.SendToLateJoin(owner.current)
|
||||
to_chat(owner, "HOT INSERTION, GO GO GO")
|
||||
else
|
||||
owner.current.forceMove(pick(GLOB.wizardstart))
|
||||
owner.current.forceMove(pick(GLOB.wizardstart))
|
||||
|
||||
/datum/antagonist/wizard/proc/create_objectives()
|
||||
var/datum/objective/flavor/wizard/new_objective = new
|
||||
@@ -79,7 +83,7 @@
|
||||
|
||||
/datum/antagonist/wizard/proc/equip_wizard()
|
||||
if(!owner)
|
||||
return
|
||||
CRASH("Antag datum with no owner.")
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(!istype(H))
|
||||
return
|
||||
@@ -91,18 +95,14 @@
|
||||
H.age = wiz_age
|
||||
H.equipOutfit(outfit_type)
|
||||
|
||||
/datum/antagonist/wizard/greet()
|
||||
to_chat(owner, "<span class='boldannounce'>You are the Space Wizard!</span>")
|
||||
to_chat(owner, "<B>The Space Wizards Federation has given you the following tasks:</B>")
|
||||
owner.announce_objectives()
|
||||
to_chat(owner, "<B>These are merely guidelines! The federation are your masters, but you forge your own path!</B>")
|
||||
to_chat(owner, "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.")
|
||||
to_chat(owner, "The spellbook is bound to you, and others cannot use it.")
|
||||
to_chat(owner, "In your pockets you will find a teleport scroll. Use it as needed.")
|
||||
to_chat(owner,"<B>Remember:</B> do not forget to prepare your spells.")
|
||||
/datum/antagonist/wizard/ui_static_data(mob/user)
|
||||
. = ..()
|
||||
var/list/data = list()
|
||||
data["objectives"] = get_objectives()
|
||||
return data
|
||||
|
||||
/datum/antagonist/wizard/farewell()
|
||||
to_chat(owner, "<span class='userdanger'>You have been brainwashed! You are no longer a wizard!</span>")
|
||||
to_chat(owner, span_userdanger("You have been brainwashed! You are no longer a wizard!"))
|
||||
|
||||
/datum/antagonist/wizard/proc/rename_wizard()
|
||||
set waitfor = FALSE
|
||||
@@ -111,7 +111,7 @@
|
||||
var/wizard_name_second = pick(GLOB.wizard_second)
|
||||
var/randomname = "[wizard_name_first] [wizard_name_second]"
|
||||
var/mob/living/wiz_mob = owner.current
|
||||
var/newname = reject_bad_name(stripped_input(wiz_mob, "You are the [name]. Would you like to change your name to something else?", "Name change", randomname, MAX_NAME_LEN))
|
||||
var/newname = sanitize_name(reject_bad_text(stripped_input(wiz_mob, "You are the [name]. Would you like to change your name to something else?", "Name change", randomname, MAX_NAME_LEN)))
|
||||
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
@@ -120,12 +120,12 @@
|
||||
|
||||
/datum/antagonist/wizard/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_wiz_icons_added(M, wiz_team ? TRUE : FALSE) //Don't bother showing the icon if you're solo wizard
|
||||
add_antag_hud(antag_hud_type, antag_hud_name, M)
|
||||
M.faction |= ROLE_WIZARD
|
||||
|
||||
/datum/antagonist/wizard/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_wiz_icons_removed(M)
|
||||
remove_antag_hud(antag_hud_type, M)
|
||||
M.faction -= ROLE_WIZARD
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
/datum/antagonist/wizard/apprentice
|
||||
name = "Wizard Apprentice"
|
||||
hud_version = "apprentice"
|
||||
antag_hud_name = "apprentice"
|
||||
var/datum/mind/master
|
||||
var/school = APPRENTICE_DESTRUCTION
|
||||
outfit_type = /datum/outfit/wizard/apprentice
|
||||
@@ -157,7 +157,7 @@
|
||||
/datum/antagonist/wizard/apprentice/equip_wizard()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
CRASH("Antag datum with no owner.")
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(!istype(H))
|
||||
return
|
||||
@@ -169,12 +169,12 @@
|
||||
if(APPRENTICE_BLUESPACE)
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt.")
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned reality-bending mobility spells. You are able to cast teleport and ethereal jaunt.")
|
||||
if(APPRENTICE_HEALING)
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall(null))
|
||||
H.put_in_hands(new /obj/item/gun/magic/staff/healing(H))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.")
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned life-saving survival spells. You are able to cast charge and forcewall.")
|
||||
if(APPRENTICE_ROBELESS)
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/pointed/mind_transfer(null))
|
||||
@@ -194,6 +194,7 @@
|
||||
//Random event wizard
|
||||
/datum/antagonist/wizard/apprentice/imposter
|
||||
name = "Wizard Imposter"
|
||||
show_in_antagpanel = FALSE
|
||||
allow_rename = FALSE
|
||||
move_to_lair = FALSE
|
||||
|
||||
@@ -224,20 +225,11 @@
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
|
||||
|
||||
/datum/antagonist/wizard/proc/update_wiz_icons_added(mob/living/wiz,join = TRUE)
|
||||
var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
|
||||
wizhud.join_hud(wiz)
|
||||
set_antag_hud(wiz, hud_version)
|
||||
|
||||
/datum/antagonist/wizard/proc/update_wiz_icons_removed(mob/living/wiz)
|
||||
var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
|
||||
wizhud.leave_hud(wiz)
|
||||
set_antag_hud(wiz, null)
|
||||
|
||||
|
||||
/datum/antagonist/wizard/academy
|
||||
name = "Academy Teacher"
|
||||
show_in_antagpanel = FALSE
|
||||
outfit_type = /datum/outfit/wizard/academy
|
||||
move_to_lair = FALSE
|
||||
|
||||
/datum/antagonist/wizard/academy/equip_wizard()
|
||||
. = ..()
|
||||
@@ -250,7 +242,7 @@
|
||||
if(!istype(M))
|
||||
return
|
||||
|
||||
var/obj/item/implant/exile/Implant = new
|
||||
var/obj/item/implant/exile/Implant = new/obj/item/implant/exile(M)
|
||||
Implant.implant(M)
|
||||
|
||||
/datum/antagonist/wizard/academy/create_objectives()
|
||||
@@ -265,25 +257,25 @@
|
||||
parts += printplayer(owner)
|
||||
|
||||
var/count = 1
|
||||
var/wizardwin = 1
|
||||
var/wizardwin = TRUE
|
||||
for(var/datum/objective/objective in objectives)
|
||||
if(objective.completable)
|
||||
var/completion = objective.check_completion()
|
||||
if(completion >= 1)
|
||||
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
|
||||
parts += "<br><B>Objective #[count]</B>: [objective.explanation_text] [span_greentext("Success!")]"
|
||||
else if(completion <= 0)
|
||||
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
parts += "<br><B>Objective #[count]</B>: [objective.explanation_text] [span_redtext("Fail.")]"
|
||||
wizardwin = FALSE
|
||||
else
|
||||
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
|
||||
parts += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
|
||||
else
|
||||
parts += "<B>Objective #[count]</B>: [objective.explanation_text]"
|
||||
count++
|
||||
|
||||
if(wizardwin)
|
||||
parts += "<span class='greentext'>The wizard was successful!</span>"
|
||||
parts += span_greentext("The wizard was successful!")
|
||||
else
|
||||
parts += "<span class='redtext'>The wizard has failed!</span>"
|
||||
parts += span_redtext("The wizard has failed!")
|
||||
|
||||
if(owner.spell_list.len>0)
|
||||
parts += "<B>[owner.name] used the following spells: </B>"
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
if(spill && R.total_volume >= 5)
|
||||
R.reaction(turfing ? target : target.loc, TOUCH, 1, 0)
|
||||
if(!turfing)
|
||||
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1))
|
||||
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1), log = TRUE)
|
||||
G.last_orgasmed = world.time
|
||||
R.clear_reagents()
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE))
|
||||
return
|
||||
to_chat(src,"<span class='userlove'>You used your [G.name] to fill [container].</span>")
|
||||
message_admins("[src] used their [G.name] to fill [container].")
|
||||
do_climax(fluid_source, container, G, FALSE)
|
||||
|
||||
/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE)
|
||||
|
||||
@@ -34,14 +34,16 @@
|
||||
|
||||
/obj/item/assembly/proc/on_attach()
|
||||
|
||||
/obj/item/assembly/proc/on_detach() //call this when detaching it from a device. handles any special functions that need to be updated ex post facto
|
||||
///Call this when detaching it from a device. handles any special functions that need to be updated ex post facto
|
||||
/obj/item/assembly/proc/on_detach()
|
||||
if(!holder)
|
||||
return FALSE
|
||||
forceMove(holder.drop_location())
|
||||
holder = null
|
||||
return TRUE
|
||||
|
||||
/obj/item/assembly/proc/holder_movement() //Called when the holder is moved
|
||||
///Called when the holder is moved
|
||||
/obj/item/assembly/proc/holder_movement()
|
||||
if(!holder)
|
||||
return FALSE
|
||||
setDir(holder.dir)
|
||||
@@ -53,7 +55,6 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
//Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
|
||||
/obj/item/assembly/proc/pulsed(radio = FALSE)
|
||||
if(wire_type & WIRE_RECEIVE)
|
||||
@@ -62,7 +63,6 @@
|
||||
INVOKE_ASYNC(src, .proc/activate)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
|
||||
/obj/item/assembly/proc/pulse(radio = FALSE)
|
||||
if(connected && wire_type)
|
||||
@@ -74,7 +74,6 @@
|
||||
holder.process_activation(src, 0, 1)
|
||||
return TRUE
|
||||
|
||||
|
||||
// What the device does when turned on
|
||||
/obj/item/assembly/proc/activate()
|
||||
if(QDELETED(src) || !secured || (next_activate > world.time))
|
||||
@@ -82,13 +81,11 @@
|
||||
next_activate = world.time + activate_cooldown
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/assembly/proc/toggle_secure()
|
||||
secured = !secured
|
||||
update_icon()
|
||||
return secured
|
||||
|
||||
|
||||
/obj/item/assembly/attackby(obj/item/W, mob/user, params)
|
||||
if(isassembly(W))
|
||||
var/obj/item/assembly/A = W
|
||||
@@ -115,7 +112,6 @@
|
||||
. = ..()
|
||||
. += "<span class='notice'>\The [src] [secured? "is secured and ready to be used!" : "can be attached to other things."]</span>"
|
||||
|
||||
|
||||
/obj/item/assembly/attack_self(mob/user)
|
||||
if(!user)
|
||||
return FALSE
|
||||
@@ -125,3 +121,11 @@
|
||||
|
||||
/obj/item/assembly/interact(mob/user)
|
||||
return ui_interact(user)
|
||||
|
||||
/obj/item/assembly/ui_host(mob/user)
|
||||
if(holder)
|
||||
return holder
|
||||
return src
|
||||
|
||||
/obj/item/assembly/ui_state(mob/user)
|
||||
return GLOB.hands_state
|
||||
|
||||
@@ -88,14 +88,14 @@
|
||||
if(a_right)
|
||||
a_right.dropped(user)
|
||||
|
||||
/obj/item/assembly_holder/on_attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
/obj/item/assembly_holder/on_attack_hand(user, act_intent)//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(a_left)
|
||||
a_left.attack_hand()
|
||||
a_left.attack_hand(user, act_intent)
|
||||
if(a_right)
|
||||
a_right.attack_hand()
|
||||
a_right.attack_hand(user, act_intent)
|
||||
|
||||
/obj/item/assembly_holder/screwdriver_act(mob/user, obj/item/tool)
|
||||
if(..())
|
||||
|
||||
@@ -13,9 +13,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
var/_abstract = /datum/asset
|
||||
var/cached_url_mappings
|
||||
|
||||
/// Whether or not this asset should be loaded in the "early assets" SS
|
||||
var/early = FALSE
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
@@ -368,28 +365,3 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
/datum/asset/simple/namespaced/proc/get_htmlloader(filename)
|
||||
return url2htmlloader(SSassets.transport.get_asset_url(filename, assets[filename]))
|
||||
|
||||
/// A subtype to generate a JSON file from a list
|
||||
/datum/asset/json
|
||||
_abstract = /datum/asset/json
|
||||
/// The filename, will be suffixed with ".json"
|
||||
var/name
|
||||
|
||||
/datum/asset/json/send(client)
|
||||
return SSassets.transport.send_assets(client, "data/[name].json")
|
||||
|
||||
/datum/asset/json/get_url_mappings()
|
||||
return list(
|
||||
"[name].json" = SSassets.transport.get_asset_url("data/[name].json"),
|
||||
)
|
||||
|
||||
/datum/asset/json/register()
|
||||
var/filename = "data/[name].json"
|
||||
fdel(filename)
|
||||
text2file(json_encode(generate()), filename)
|
||||
SSassets.transport.register_asset(filename, fcopy_rsc(filename))
|
||||
fdel(filename)
|
||||
|
||||
/// Returns the data that will be JSON encoded
|
||||
/datum/asset/json/proc/generate()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
CRASH("generate() not implemented for [type]!")
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
/datum/asset/simple/tgui_common
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-common.bundle.js" = file("tgui/public/tgui-common.bundle.js"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
@@ -54,9 +48,14 @@
|
||||
|
||||
/datum/asset/simple/radar_assets
|
||||
assets = list(
|
||||
"ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
|
||||
"ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
|
||||
"ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
|
||||
"ntosradarbackground.png" = 'icons/ui_icons/tgui/ntosradar_background.png',
|
||||
"ntosradarpointer.png" = 'icons/ui_icons/tgui/ntosradar_pointer.png',
|
||||
"ntosradarpointerS.png" = 'icons/ui_icons/tgui/ntosradar_pointer_S.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/circuit_assets
|
||||
assets = list(
|
||||
"grid_background.png" = 'icons/ui_icons/tgui/grid_background.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pda
|
||||
@@ -91,6 +90,7 @@
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
// "droneblacklist" = 'icons/pda_icons/pda_droneblacklist.png',
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/paper
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
/datum/asset/simple/irv
|
||||
assets = list(
|
||||
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
|
||||
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/jquery/jquery-ui.custom-core-widgit-mouse-sortable.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/group/irv
|
||||
@@ -125,35 +125,10 @@
|
||||
/datum/asset/simple/irv
|
||||
)
|
||||
|
||||
/datum/asset/simple/namespaced/changelog
|
||||
assets = list(
|
||||
"88x31.png" = 'html/88x31.png',
|
||||
"bug-minus.png" = 'html/bug-minus.png',
|
||||
"cross-circle.png" = 'html/cross-circle.png',
|
||||
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
|
||||
"image-minus.png" = 'html/image-minus.png',
|
||||
"image-plus.png" = 'html/image-plus.png',
|
||||
"music-minus.png" = 'html/music-minus.png',
|
||||
"music-plus.png" = 'html/music-plus.png',
|
||||
"tick-circle.png" = 'html/tick-circle.png',
|
||||
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
|
||||
"spell-check.png" = 'html/spell-check.png',
|
||||
"burn-exclamation.png" = 'html/burn-exclamation.png',
|
||||
"chevron.png" = 'html/chevron.png',
|
||||
"chevron-expand.png" = 'html/chevron-expand.png',
|
||||
"scales.png" = 'html/scales.png',
|
||||
"coding.png" = 'html/coding.png',
|
||||
"ban.png" = 'html/ban.png',
|
||||
"chrome-wrench.png" = 'html/chrome-wrench.png',
|
||||
"changelog.css" = 'html/changelog.css'
|
||||
)
|
||||
parents = list("changelog.html" = 'html/changelog.html')
|
||||
|
||||
|
||||
/datum/asset/simple/jquery
|
||||
legacy = TRUE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'html/jquery.min.js',
|
||||
"jquery.min.js" = 'html/jquery/jquery.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/namespaced/fontawesome
|
||||
@@ -223,102 +198,102 @@
|
||||
|
||||
/datum/asset/simple/arcade
|
||||
assets = list(
|
||||
"boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
|
||||
"boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
|
||||
"boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
|
||||
"boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
|
||||
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
|
||||
"boss1.gif" = 'icons/ui_icons/arcade/boss1.gif',
|
||||
"boss2.gif" = 'icons/ui_icons/arcade/boss2.gif',
|
||||
"boss3.gif" = 'icons/ui_icons/arcade/boss3.gif',
|
||||
"boss4.gif" = 'icons/ui_icons/arcade/boss4.gif',
|
||||
"boss5.gif" = 'icons/ui_icons/arcade/boss5.gif',
|
||||
"boss6.gif" = 'icons/ui_icons/arcade/boss6.gif',
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/achievements
|
||||
name ="achievements"
|
||||
assets = list(
|
||||
"default" = 'icons/UI_Icons/Achievements/default.png',
|
||||
"basemisc" = 'icons/UI_Icons/Achievements/basemisc.png',
|
||||
"baseboss" = 'icons/UI_Icons/Achievements/baseboss.png',
|
||||
"baseskill" = 'icons/UI_Icons/Achievements/baseskill.png',
|
||||
"bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
|
||||
"colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
|
||||
"hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
|
||||
"drake" = 'icons/UI_Icons/Achievements/Boss/drake.png',
|
||||
"legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
|
||||
"miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
|
||||
"swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
|
||||
"tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png',
|
||||
"featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png',
|
||||
"helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png',
|
||||
"jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png',
|
||||
"meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png',
|
||||
"timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png',
|
||||
"upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png',
|
||||
"clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
|
||||
"clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
|
||||
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
|
||||
"longshift" = 'icons/UI_Icons/Achievements/Misc/longshift.png',
|
||||
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
|
||||
"ascension" = 'icons/UI_Icons/Achievements/Misc/ascension.png',
|
||||
"ashascend" = 'icons/UI_Icons/Achievements/Misc/ashascend.png',
|
||||
"fleshascend" = 'icons/UI_Icons/Achievements/Misc/fleshascend.png',
|
||||
"rustascend" = 'icons/UI_Icons/Achievements/Misc/rustascend.png',
|
||||
"voidascend" = 'icons/UI_Icons/Achievements/Misc/voidascend.png',
|
||||
"toolbox_soul" = 'icons/UI_Icons/Achievements/Misc/toolbox_soul.png',
|
||||
"chem_tut" = 'icons/UI_Icons/Achievements/Misc/chem_tut.png',
|
||||
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
|
||||
"mafia" = 'icons/UI_Icons/Achievements/Mafia/mafia.png',
|
||||
"town" = 'icons/UI_Icons/Achievements/Mafia/town.png',
|
||||
"neutral" = 'icons/UI_Icons/Achievements/Mafia/neutral.png',
|
||||
"hated" = 'icons/UI_Icons/Achievements/Mafia/hated.png',
|
||||
"basemafia" ='icons/UI_Icons/Achievements/basemafia.png',
|
||||
"frenching" = 'icons/UI_Icons/Achievements/Misc/frenchingthebubble.png'
|
||||
"default" = 'icons/ui_icons/achievements/default.png',
|
||||
"basemisc" = 'icons/ui_icons/achievements/basemisc.png',
|
||||
"baseboss" = 'icons/ui_icons/achievements/baseboss.png',
|
||||
"baseskill" = 'icons/ui_icons/achievements/baseskill.png',
|
||||
"bbgum" = 'icons/ui_icons/achievements/Boss/bbgum.png',
|
||||
"colossus" = 'icons/ui_icons/achievements/Boss/colossus.png',
|
||||
"hierophant" = 'icons/ui_icons/achievements/Boss/hierophant.png',
|
||||
"drake" = 'icons/ui_icons/achievements/Boss/drake.png',
|
||||
"legion" = 'icons/ui_icons/achievements/Boss/legion.png',
|
||||
"miner" = 'icons/ui_icons/achievements/Boss/miner.png',
|
||||
"swarmer" = 'icons/ui_icons/achievements/Boss/swarmer.png',
|
||||
"tendril" = 'icons/ui_icons/achievements/Boss/tendril.png',
|
||||
"featofstrength" = 'icons/ui_icons/achievements/Misc/featofstrength.png',
|
||||
"helbital" = 'icons/ui_icons/achievements/Misc/helbital.png',
|
||||
"jackpot" = 'icons/ui_icons/achievements/Misc/jackpot.png',
|
||||
"meteors" = 'icons/ui_icons/achievements/Misc/meteors.png',
|
||||
"timewaste" = 'icons/ui_icons/achievements/Misc/timewaste.png',
|
||||
"upgrade" = 'icons/ui_icons/achievements/Misc/upgrade.png',
|
||||
"clownking" = 'icons/ui_icons/achievements/Misc/clownking.png',
|
||||
"clownthanks" = 'icons/ui_icons/achievements/Misc/clownthanks.png',
|
||||
"rule8" = 'icons/ui_icons/achievements/Misc/rule8.png',
|
||||
"longshift" = 'icons/ui_icons/achievements/Misc/longshift.png',
|
||||
"snail" = 'icons/ui_icons/achievements/Misc/snail.png',
|
||||
"ascension" = 'icons/ui_icons/achievements/Misc/ascension.png',
|
||||
"ashascend" = 'icons/ui_icons/achievements/Misc/ashascend.png',
|
||||
"fleshascend" = 'icons/ui_icons/achievements/Misc/fleshascend.png',
|
||||
"rustascend" = 'icons/ui_icons/achievements/Misc/rustascend.png',
|
||||
"voidascend" = 'icons/ui_icons/achievements/Misc/voidascend.png',
|
||||
"toolbox_soul" = 'icons/ui_icons/achievements/Misc/toolbox_soul.png',
|
||||
"chem_tut" = 'icons/ui_icons/achievements/Misc/chem_tut.png',
|
||||
"mining" = 'icons/ui_icons/achievements/Skills/mining.png',
|
||||
"mafia" = 'icons/ui_icons/achievements/Mafia/mafia.png',
|
||||
"town" = 'icons/ui_icons/achievements/Mafia/town.png',
|
||||
"neutral" = 'icons/ui_icons/achievements/Mafia/neutral.png',
|
||||
"hated" = 'icons/ui_icons/achievements/Mafia/hated.png',
|
||||
"basemafia" ='icons/ui_icons/achievements/basemafia.png',
|
||||
"frenching" = 'icons/ui_icons/achievements/Misc/frenchingthebubble.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name = "pills"
|
||||
assets = list(
|
||||
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
|
||||
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
|
||||
"pill3" = 'icons/UI_Icons/Pills/pill3.png',
|
||||
"pill4" = 'icons/UI_Icons/Pills/pill4.png',
|
||||
"pill5" = 'icons/UI_Icons/Pills/pill5.png',
|
||||
"pill6" = 'icons/UI_Icons/Pills/pill6.png',
|
||||
"pill7" = 'icons/UI_Icons/Pills/pill7.png',
|
||||
"pill8" = 'icons/UI_Icons/Pills/pill8.png',
|
||||
"pill9" = 'icons/UI_Icons/Pills/pill9.png',
|
||||
"pill10" = 'icons/UI_Icons/Pills/pill10.png',
|
||||
"pill11" = 'icons/UI_Icons/Pills/pill11.png',
|
||||
"pill12" = 'icons/UI_Icons/Pills/pill12.png',
|
||||
"pill13" = 'icons/UI_Icons/Pills/pill13.png',
|
||||
"pill14" = 'icons/UI_Icons/Pills/pill14.png',
|
||||
"pill15" = 'icons/UI_Icons/Pills/pill15.png',
|
||||
"pill16" = 'icons/UI_Icons/Pills/pill16.png',
|
||||
"pill17" = 'icons/UI_Icons/Pills/pill17.png',
|
||||
"pill18" = 'icons/UI_Icons/Pills/pill18.png',
|
||||
"pill19" = 'icons/UI_Icons/Pills/pill19.png',
|
||||
"pill20" = 'icons/UI_Icons/Pills/pill20.png',
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
"pill1" = 'icons/ui_icons/pills/pill1.png',
|
||||
"pill2" = 'icons/ui_icons/pills/pill2.png',
|
||||
"pill3" = 'icons/ui_icons/pills/pill3.png',
|
||||
"pill4" = 'icons/ui_icons/pills/pill4.png',
|
||||
"pill5" = 'icons/ui_icons/pills/pill5.png',
|
||||
"pill6" = 'icons/ui_icons/pills/pill6.png',
|
||||
"pill7" = 'icons/ui_icons/pills/pill7.png',
|
||||
"pill8" = 'icons/ui_icons/pills/pill8.png',
|
||||
"pill9" = 'icons/ui_icons/pills/pill9.png',
|
||||
"pill10" = 'icons/ui_icons/pills/pill10.png',
|
||||
"pill11" = 'icons/ui_icons/pills/pill11.png',
|
||||
"pill12" = 'icons/ui_icons/pills/pill12.png',
|
||||
"pill13" = 'icons/ui_icons/pills/pill13.png',
|
||||
"pill14" = 'icons/ui_icons/pills/pill14.png',
|
||||
"pill15" = 'icons/ui_icons/pills/pill15.png',
|
||||
"pill16" = 'icons/ui_icons/pills/pill16.png',
|
||||
"pill17" = 'icons/ui_icons/pills/pill17.png',
|
||||
"pill18" = 'icons/ui_icons/pills/pill18.png',
|
||||
"pill19" = 'icons/ui_icons/pills/pill19.png',
|
||||
"pill20" = 'icons/ui_icons/pills/pill20.png',
|
||||
"pill21" = 'icons/ui_icons/pills/pill21.png',
|
||||
"pill22" = 'icons/ui_icons/pills/pill22.png',
|
||||
)
|
||||
|
||||
// /datum/asset/spritesheet/simple/condiments
|
||||
// name = "condiments"
|
||||
// assets = list(
|
||||
// CONDIMASTER_STYLE_FALLBACK = 'icons/UI_Icons/Condiments/emptycondiment.png',
|
||||
// "enzyme" = 'icons/UI_Icons/Condiments/enzyme.png',
|
||||
// "flour" = 'icons/UI_Icons/Condiments/flour.png',
|
||||
// "mayonnaise" = 'icons/UI_Icons/Condiments/mayonnaise.png',
|
||||
// "milk" = 'icons/UI_Icons/Condiments/milk.png',
|
||||
// "blackpepper" = 'icons/UI_Icons/Condiments/peppermillsmall.png',
|
||||
// "rice" = 'icons/UI_Icons/Condiments/rice.png',
|
||||
// "sodiumchloride" = 'icons/UI_Icons/Condiments/saltshakersmall.png',
|
||||
// "soymilk" = 'icons/UI_Icons/Condiments/soymilk.png',
|
||||
// "soysauce" = 'icons/UI_Icons/Condiments/soysauce.png',
|
||||
// "sugar" = 'icons/UI_Icons/Condiments/sugar.png',
|
||||
// "ketchup" = 'icons/UI_Icons/Condiments/ketchup.png',
|
||||
// "capsaicin" = 'icons/UI_Icons/Condiments/hotsauce.png',
|
||||
// "frostoil" = 'icons/UI_Icons/Condiments/coldsauce.png',
|
||||
// "bbqsauce" = 'icons/UI_Icons/Condiments/bbqsauce.png',
|
||||
// "cornoil" = 'icons/UI_Icons/Condiments/oliveoil.png',
|
||||
// CONDIMASTER_STYLE_FALLBACK = 'icons/ui_icons/condiments/emptycondiment.png',
|
||||
// "enzyme" = 'icons/ui_icons/condiments/enzyme.png',
|
||||
// "flour" = 'icons/ui_icons/condiments/flour.png',
|
||||
// "mayonnaise" = 'icons/ui_icons/condiments/mayonnaise.png',
|
||||
// "milk" = 'icons/ui_icons/condiments/milk.png',
|
||||
// "blackpepper" = 'icons/ui_icons/condiments/peppermillsmall.png',
|
||||
// "rice" = 'icons/ui_icons/condiments/rice.png',
|
||||
// "sodiumchloride" = 'icons/ui_icons/condiments/saltshakersmall.png',
|
||||
// "soymilk" = 'icons/ui_icons/condiments/soymilk.png',
|
||||
// "soysauce" = 'icons/ui_icons/condiments/soysauce.png',
|
||||
// "sugar" = 'icons/ui_icons/condiments/sugar.png',
|
||||
// "ketchup" = 'icons/ui_icons/condiments/ketchup.png',
|
||||
// "capsaicin" = 'icons/ui_icons/condiments/hotsauce.png',
|
||||
// "frostoil" = 'icons/ui_icons/condiments/coldsauce.png',
|
||||
// "bbqsauce" = 'icons/ui_icons/condiments/bbqsauce.png',
|
||||
// "cornoil" = 'icons/ui_icons/condiments/oliveoil.png',
|
||||
// )
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
@@ -410,9 +385,15 @@
|
||||
if (machine)
|
||||
item = machine
|
||||
|
||||
// Check for GAGS support where necessary
|
||||
// var/greyscale_config = initial(item.greyscale_config)
|
||||
// var/greyscale_colors = initial(item.greyscale_colors)
|
||||
// if (greyscale_config && greyscale_colors)
|
||||
// icon_file = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors)
|
||||
// else
|
||||
icon_file = initial(item.icon)
|
||||
icon_state = initial(item.icon_state)
|
||||
|
||||
icon_state = initial(item.icon_state)
|
||||
if(!(icon_state in icon_states(icon_file)))
|
||||
warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
|
||||
continue
|
||||
@@ -441,7 +422,11 @@
|
||||
if (!ispath(item, /atom))
|
||||
continue
|
||||
|
||||
var/icon_file = initial(item.icon)
|
||||
var/icon_file
|
||||
// if (initial(item.greyscale_colors) && initial(item.greyscale_config))
|
||||
// icon_file = SSgreyscale.GetColoredIconByType(initial(item.greyscale_config), initial(item.greyscale_colors))
|
||||
// else
|
||||
icon_file = initial(item.icon)
|
||||
var/icon_state = initial(item.icon_state)
|
||||
var/icon/I
|
||||
|
||||
@@ -543,6 +528,35 @@
|
||||
// Insert(id, fish_icon, fish_icon_state)
|
||||
// ..()
|
||||
|
||||
/datum/asset/simple/adventure
|
||||
assets = list(
|
||||
"default" = 'icons/ui_icons/adventure/default.png',
|
||||
"grue" = 'icons/ui_icons/adventure/grue.png',
|
||||
"signal_lost" ='icons/ui_icons/adventure/signal_lost.png',
|
||||
"trade" = 'icons/ui_icons/adventure/trade.png',
|
||||
)
|
||||
|
||||
/datum/asset/simple/inventory
|
||||
assets = list(
|
||||
"inventory-glasses.png" = 'icons/ui_icons/inventory/glasses.png',
|
||||
"inventory-head.png" = 'icons/ui_icons/inventory/head.png',
|
||||
"inventory-neck.png" = 'icons/ui_icons/inventory/neck.png',
|
||||
"inventory-mask.png" = 'icons/ui_icons/inventory/mask.png',
|
||||
"inventory-ears.png" = 'icons/ui_icons/inventory/ears.png',
|
||||
"inventory-uniform.png" = 'icons/ui_icons/inventory/uniform.png',
|
||||
"inventory-suit.png" = 'icons/ui_icons/inventory/suit.png',
|
||||
"inventory-gloves.png" = 'icons/ui_icons/inventory/gloves.png',
|
||||
"inventory-hand_l.png" = 'icons/ui_icons/inventory/hand_l.png',
|
||||
"inventory-hand_r.png" = 'icons/ui_icons/inventory/hand_r.png',
|
||||
"inventory-shoes.png" = 'icons/ui_icons/inventory/shoes.png',
|
||||
"inventory-suit_storage.png" = 'icons/ui_icons/inventory/suit_storage.png',
|
||||
"inventory-id.png" = 'icons/ui_icons/inventory/id.png',
|
||||
"inventory-belt.png" = 'icons/ui_icons/inventory/belt.png',
|
||||
"inventory-back.png" = 'icons/ui_icons/inventory/back.png',
|
||||
"inventory-pocket.png" = 'icons/ui_icons/inventory/pocket.png',
|
||||
"inventory-collar.png" = 'icons/ui_icons/inventory/collar.png',
|
||||
)
|
||||
|
||||
/// Removes all non-alphanumerics from the text, keep in mind this can lead to id conflicts
|
||||
/proc/sanitize_css_class_name(name)
|
||||
var/static/regex/regex = new(@"[^a-zA-Z0-9]","g")
|
||||
@@ -550,5 +564,34 @@
|
||||
|
||||
/datum/asset/simple/tutorial_advisors
|
||||
assets = list(
|
||||
"chem_help_advisor.gif" = 'icons/UI_Icons/Advisors/chem_help_advisor.gif',
|
||||
"chem_help_advisor.gif" = 'icons/ui_icons/advisors/chem_help_advisor.gif',
|
||||
)
|
||||
|
||||
// /datum/asset/spritesheet/moods
|
||||
// name = "moods"
|
||||
// var/iconinserted = 1
|
||||
|
||||
// /datum/asset/spritesheet/moods/register()
|
||||
// for(var/i in 1 to 9)
|
||||
// var/target_to_insert = "mood"+"[iconinserted]"
|
||||
// Insert(target_to_insert, 'icons/hud/screen_gen.dmi', target_to_insert)
|
||||
// iconinserted++
|
||||
// ..()
|
||||
|
||||
// /datum/asset/spritesheet/moods/ModifyInserted(icon/pre_asset)
|
||||
// var/blended_color
|
||||
// switch(iconinserted)
|
||||
// if(1)
|
||||
// blended_color = "#f15d36"
|
||||
// if(2 to 3)
|
||||
// blended_color = "#f38943"
|
||||
// if(4)
|
||||
// blended_color = "#dfa65b"
|
||||
// if(5)
|
||||
// blended_color = "#4b96c4"
|
||||
// if(6)
|
||||
// blended_color = "#86d656"
|
||||
// else
|
||||
// blended_color = "#2eeb9a"
|
||||
// pre_asset.Blend(blended_color, ICON_MULTIPLY)
|
||||
// return pre_asset
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
if (unreceived.len)
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
to_chat(client, "<span class='infoplain'>Sending Resources...</span>")
|
||||
|
||||
for (var/asset_name in unreceived)
|
||||
var/new_asset_name = asset_name
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
)
|
||||
)
|
||||
fusion_power = 3
|
||||
enthalpy = -393500
|
||||
|
||||
/datum/gas/plasma
|
||||
id = GAS_PLASMA
|
||||
@@ -54,7 +55,10 @@
|
||||
heat_penalty = 15
|
||||
transmit_modifier = 4
|
||||
powermix = 1
|
||||
// no fire info cause it has its own bespoke reaction for trit generation reasons
|
||||
fire_burn_rate = OXYGEN_BURN_RATE_BASE // named when plasma fires were the only fires, surely
|
||||
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
|
||||
fire_products = "plasma_fire"
|
||||
enthalpy = FIRE_PLASMA_ENERGY_RELEASED // 3000000, 3 megajoules, 3000 kj
|
||||
|
||||
/datum/gas/water_vapor
|
||||
id = GAS_H2O
|
||||
@@ -64,6 +68,7 @@
|
||||
moles_visible = MOLES_GAS_VISIBLE
|
||||
fusion_power = 8
|
||||
heat_penalty = 8
|
||||
enthalpy = -241800 // FIRE_HYDROGEN_ENERGY_RELEASED is actually what this was supposed to be
|
||||
powermix = 1
|
||||
breath_reagent = /datum/reagent/water
|
||||
|
||||
@@ -84,6 +89,7 @@
|
||||
fire_products = list(GAS_N2 = 1)
|
||||
oxidation_rate = 0.5
|
||||
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + 100
|
||||
enthalpy = 81600
|
||||
heat_resistance = 6
|
||||
|
||||
/datum/gas/nitryl
|
||||
@@ -95,8 +101,22 @@
|
||||
flags = GAS_FLAG_DANGEROUS
|
||||
fusion_power = 15
|
||||
fire_products = list(GAS_N2 = 0.5)
|
||||
enthalpy = 33200
|
||||
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
|
||||
|
||||
/datum/gas/hydrogen
|
||||
id = GAS_HYDROGEN
|
||||
specific_heat = 10
|
||||
name = "Hydrogen"
|
||||
flags = GAS_FLAG_DANGEROUS
|
||||
fusion_power = 0
|
||||
powermix = 1
|
||||
heat_penalty = 3
|
||||
transmit_modifier = 10
|
||||
fire_products = list(GAS_H2O = 1)
|
||||
fire_burn_rate = 2
|
||||
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
|
||||
|
||||
/datum/gas/tritium
|
||||
id = GAS_TRITIUM
|
||||
specific_heat = 10
|
||||
@@ -108,13 +128,11 @@
|
||||
powermix = 1
|
||||
heat_penalty = 10
|
||||
transmit_modifier = 30
|
||||
/*
|
||||
these are for when we add hydrogen, trit gets to keep its hardcoded fire for legacy reasons
|
||||
fire_provides = list(GAS_H2O = 2)
|
||||
fire_products = list(GAS_H2O = 1)
|
||||
enthalpy = 40000
|
||||
fire_burn_rate = 2
|
||||
fire_energy_released = FIRE_HYDROGEN_ENERGY_RELEASED
|
||||
fire_radiation_released = 50 // arbitrary number, basically 60 moles of trit burning will just barely start to harm you
|
||||
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
|
||||
*/
|
||||
|
||||
/datum/gas/bz
|
||||
id = GAS_BZ
|
||||
@@ -124,6 +142,7 @@
|
||||
fusion_power = 8
|
||||
powermix = 1
|
||||
heat_penalty = 5
|
||||
enthalpy = FIRE_CARBON_ENERGY_RELEASED // it is a mystery
|
||||
transmit_modifier = -2
|
||||
radioactivity_modifier = 5
|
||||
|
||||
@@ -139,7 +158,8 @@
|
||||
name = "Pluoxium"
|
||||
fusion_power = 10
|
||||
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 1000 // it is VERY stable
|
||||
oxidation_rate = 8
|
||||
oxidation_rate = 8 // when it can oxidize, it can oxidize a LOT
|
||||
enthalpy = -50000 // but it reduces the heat output a bit
|
||||
powermix = -1
|
||||
heat_penalty = -1
|
||||
transmit_modifier = -5
|
||||
@@ -172,7 +192,7 @@
|
||||
alert_type = /atom/movable/screen/alert/too_much_ch4
|
||||
)
|
||||
)
|
||||
fire_energy_released = FIRE_CARBON_ENERGY_RELEASED
|
||||
enthalpy = -74600
|
||||
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
|
||||
|
||||
/datum/gas/methyl_bromide
|
||||
@@ -192,7 +212,28 @@
|
||||
alert_type = /atom/movable/screen/alert/too_much_ch3br
|
||||
)
|
||||
)
|
||||
fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5, GAS_BZ = 0.5)
|
||||
fire_energy_released = FIRE_CARBON_ENERGY_RELEASED
|
||||
fire_burn_rate = 0.5
|
||||
fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5, GAS_BROMINE = 0.5)
|
||||
enthalpy = -35400
|
||||
fire_burn_rate = 4 / 7 // oh no
|
||||
fire_temperature = 808 // its autoignition, it apparently doesn't spark readily, so i don't put it lower
|
||||
|
||||
/datum/gas/bromine
|
||||
id = GAS_BROMINE
|
||||
specific_heat = 76
|
||||
name = "Bromine"
|
||||
flags = GAS_FLAG_DANGEROUS
|
||||
group = GAS_GROUP_CHEMICALS
|
||||
enthalpy = 193 // yeah it's small but it's good to include it
|
||||
breath_reagent = /datum/reagent/bromine
|
||||
|
||||
/datum/gas/ammonia
|
||||
id = GAS_AMMONIA
|
||||
specific_heat = 35
|
||||
name = "Ammonia"
|
||||
flags = GAS_FLAG_DANGEROUS
|
||||
group = GAS_GROUP_CHEMICALS
|
||||
enthalpy = -45900
|
||||
breath_reagent = /datum/reagent/ammonia
|
||||
fire_products = list(GAS_H2O = 1.5, GAS_N2 = 0.5)
|
||||
fire_burn_rate = 4/3
|
||||
fire_temperature = 924
|
||||
|
||||
@@ -15,6 +15,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
|
||||
/proc/_auxtools_register_gas(datum/gas/gas) // makes sure auxtools knows stuff about this gas
|
||||
|
||||
/datum/auxgm
|
||||
var/done_initializing = FALSE
|
||||
var/list/datums = list()
|
||||
var/list/specific_heats = list()
|
||||
var/list/names = list()
|
||||
@@ -32,30 +33,34 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
|
||||
var/list/oxidation_temperatures = list()
|
||||
var/list/oxidation_rates = list()
|
||||
var/list/fire_temperatures = list()
|
||||
var/list/fire_enthalpies = list()
|
||||
var/list/enthalpies = list()
|
||||
var/list/fire_products = list()
|
||||
var/list/fire_burn_rates = list()
|
||||
var/list/supermatter = list()
|
||||
|
||||
var/list/groups_by_gas = list()
|
||||
var/list/groups = list()
|
||||
|
||||
/datum/gas
|
||||
var/id = ""
|
||||
var/specific_heat = 0
|
||||
var/name = ""
|
||||
var/gas_overlay = "" //icon_state in icons/effects/atmospherics.dmi
|
||||
var/color = "#ffff"
|
||||
var/moles_visible = null
|
||||
var/flags = NONE //currently used by canisters
|
||||
var/group = null // groups for scrubber/filter listing
|
||||
var/fusion_power = 0 // How much the gas destabilizes a fusion reaction
|
||||
var/breath_results = GAS_CO2 // what breathing this breathes out
|
||||
var/breath_reagent = null // what breathing this adds to your reagents
|
||||
var/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
|
||||
var/datum/reagent/breath_reagent = null // what breathing this adds to your reagents
|
||||
var/datum/reagent/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
|
||||
var/list/breath_alert_info = null // list for alerts that pop up when you have too much/not enough of something
|
||||
var/oxidation_temperature = null // temperature above which this gas is an oxidizer; null for none
|
||||
var/oxidation_rate = 1 // how many moles of this can oxidize how many moles of material
|
||||
var/fire_temperature = null // temperature above which gas may catch fire; null for none
|
||||
var/list/fire_products = null // what results when this gas is burned (oxidizer or fuel); null for none
|
||||
var/fire_energy_released = 0 // how much energy is released per mole of fuel burned
|
||||
var/enthalpy = 0 // Standard enthalpy of formation in joules, used for fires
|
||||
var/fire_burn_rate = 1 // how many moles are burned per product released
|
||||
var/fire_radiation_released = 0 // How much radiation is released when this gas burns
|
||||
var/powermix = 0 // how much this gas contributes to the supermatter's powermix ratio
|
||||
var/heat_penalty = 0 // heat and waste penalty from having the supermatter crystal surrounded by this gas; negative numbers reduce
|
||||
var/transmit_modifier = 0 // bonus to supermatter power generation (multiplicative, since it's % based, and divided by 10)
|
||||
@@ -94,21 +99,31 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
|
||||
breath_reagents[g] = gas.breath_reagent
|
||||
if(gas.breath_reagent_dangerous)
|
||||
breath_reagents_dangerous[g] = gas.breath_reagent_dangerous
|
||||
|
||||
if(gas.oxidation_temperature)
|
||||
oxidation_temperatures[g] = gas.oxidation_temperature
|
||||
oxidation_rates[g] = gas.oxidation_rate
|
||||
if(gas.fire_products)
|
||||
fire_products[g] = gas.fire_products
|
||||
fire_enthalpies[g] = gas.fire_energy_released
|
||||
enthalpies[g] = gas.enthalpy
|
||||
else if(gas.fire_temperature)
|
||||
fire_temperatures[g] = gas.fire_temperature
|
||||
fire_burn_rates[g] = gas.fire_burn_rate
|
||||
if(gas.fire_products)
|
||||
fire_products[g] = gas.fire_products
|
||||
fire_enthalpies[g] = gas.fire_energy_released
|
||||
enthalpies[g] = gas.enthalpy
|
||||
if(gas.group)
|
||||
if(!(gas.group in groups))
|
||||
groups[gas.group] = list()
|
||||
groups[gas.group] += gas
|
||||
groups_by_gas[g] = gas.group
|
||||
add_supermatter_properties(gas)
|
||||
_auxtools_register_gas(gas)
|
||||
if(done_initializing)
|
||||
for(var/r in SSair.gas_reactions)
|
||||
var/datum/gas_reaction/R = r
|
||||
R.init_reqs()
|
||||
SSair.auxtools_update_reactions()
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_GAS, g)
|
||||
|
||||
/proc/finalize_gas_refs()
|
||||
|
||||
@@ -127,6 +142,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
|
||||
for(var/breathing_class_path in subtypesof(/datum/breathing_class))
|
||||
var/datum/breathing_class/class = new breathing_class_path
|
||||
breathing_classes[breathing_class_path] = class
|
||||
done_initializing = TRUE
|
||||
finalize_gas_refs()
|
||||
|
||||
|
||||
|
||||
@@ -53,23 +53,68 @@
|
||||
id = "vapor"
|
||||
|
||||
/datum/gas_reaction/water_vapor/init_reqs()
|
||||
min_requirements = list(GAS_H2O = MOLES_GAS_VISIBLE)
|
||||
min_requirements = list(
|
||||
GAS_H2O = MOLES_GAS_VISIBLE,
|
||||
"MAX_TEMP" = T0C + 40
|
||||
)
|
||||
|
||||
/datum/gas_reaction/water_vapor/react(datum/gas_mixture/air, datum/holder)
|
||||
var/turf/open/location = isturf(holder) ? holder : null
|
||||
. = NO_REACTION
|
||||
var/turf/open/location = holder
|
||||
if(!istype(location))
|
||||
return NO_REACTION
|
||||
if (air.return_temperature() <= WATER_VAPOR_FREEZE)
|
||||
if(location && location.freon_gas_act())
|
||||
. = REACTING
|
||||
return REACTING
|
||||
else if(location && location.water_vapor_gas_act())
|
||||
air.adjust_moles(GAS_H2O,-MOLES_GAS_VISIBLE)
|
||||
. = REACTING
|
||||
return REACTING
|
||||
|
||||
// no test cause it's entirely based on location
|
||||
|
||||
/datum/gas_reaction/condensation
|
||||
priority = 0
|
||||
name = "Condensation"
|
||||
id = "condense"
|
||||
exclude = TRUE
|
||||
var/datum/reagent/condensing_reagent
|
||||
|
||||
/datum/gas_reaction/condensation/New(datum/reagent/R)
|
||||
. = ..()
|
||||
if(!istype(R))
|
||||
return
|
||||
min_requirements = list(
|
||||
"MAX_TEMP" = initial(R.boiling_point)
|
||||
)
|
||||
min_requirements[R.get_gas()] = MOLES_GAS_VISIBLE
|
||||
name = "[R.name] condensation"
|
||||
id = "[R.type] condensation"
|
||||
condensing_reagent = R
|
||||
exclude = FALSE
|
||||
|
||||
/datum/gas_reaction/condensation/react(datum/gas_mixture/air, datum/holder)
|
||||
. = NO_REACTION
|
||||
var/turf/open/location = holder
|
||||
if(!istype(location))
|
||||
return
|
||||
var/temperature = air.return_temperature()
|
||||
var/static/datum/reagents/reagents_holder = new
|
||||
reagents_holder.clear_reagents()
|
||||
reagents_holder.chem_temp = temperature
|
||||
var/G = condensing_reagent.get_gas()
|
||||
var/amt = air.get_moles(G)
|
||||
air.adjust_moles(G, -min(initial(condensing_reagent.condensation_amount), amt))
|
||||
reagents_holder.add_reagent(condensing_reagent, amt)
|
||||
. = REACTING
|
||||
for(var/atom/movable/AM in location)
|
||||
if(location.intact && AM.level == 1)
|
||||
continue
|
||||
reagents_holder.reaction(AM, TOUCH)
|
||||
reagents_holder.reaction(location, TOUCH)
|
||||
|
||||
//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
|
||||
/datum/gas_reaction/tritfire
|
||||
priority = -1 //fire should ALWAYS be last, but tritium fires happen before plasma fires
|
||||
exclude = TRUE // generic fire now takes care of this
|
||||
name = "Tritium Combustion"
|
||||
id = "tritfire"
|
||||
|
||||
@@ -88,9 +133,9 @@
|
||||
item.temperature_expose(air, temperature, CELL_VOLUME)
|
||||
location.temperature_expose(air, temperature, CELL_VOLUME)
|
||||
|
||||
/proc/radiation_burn(turf/open/location, energy_released)
|
||||
/proc/radiation_burn(turf/open/location, rad_power)
|
||||
if(istype(location) && prob(10))
|
||||
radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
|
||||
radiation_pulse(location, rad_power)
|
||||
|
||||
/datum/gas_reaction/tritfire/react(datum/gas_mixture/air, datum/holder)
|
||||
var/energy_released = 0
|
||||
@@ -151,6 +196,7 @@
|
||||
/datum/gas_reaction/plasmafire
|
||||
priority = -2 //fire should ALWAYS be last, but plasma fires happen after tritium fires
|
||||
name = "Plasma Combustion"
|
||||
exclude = TRUE // generic fire now takes care of this
|
||||
id = "plasmafire"
|
||||
|
||||
/datum/gas_reaction/plasmafire/init_reqs()
|
||||
@@ -300,7 +346,7 @@
|
||||
fuels[fuel] *= oxidation_ratio
|
||||
fuels += oxidizers
|
||||
var/list/fire_products = GLOB.gas_data.fire_products
|
||||
var/list/fire_enthalpies = GLOB.gas_data.fire_enthalpies
|
||||
var/list/fire_enthalpies = GLOB.gas_data.enthalpies
|
||||
for(var/fuel in fuels + oxidizers)
|
||||
var/amt = fuels[fuel]
|
||||
if(!burn_results[fuel])
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
for(var/device_id in A.air_scrub_names)
|
||||
send_signal(device_id, list(
|
||||
"power" = 1,
|
||||
"set_filters" = list(GAS_CO2, GAS_MIASMA),
|
||||
"set_filters" = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS),
|
||||
"scrubbing" = 1,
|
||||
"widenet" = 0,
|
||||
))
|
||||
@@ -554,6 +554,7 @@
|
||||
GAS_MIASMA,
|
||||
GAS_PLASMA,
|
||||
GAS_H2O,
|
||||
GAS_HYDROGEN,
|
||||
GAS_HYPERNOB,
|
||||
GAS_NITROUS,
|
||||
GAS_NITRYL,
|
||||
@@ -562,7 +563,8 @@
|
||||
GAS_STIMULUM,
|
||||
GAS_PLUOXIUM,
|
||||
GAS_METHANE,
|
||||
GAS_METHYL_BROMIDE
|
||||
GAS_METHYL_BROMIDE,
|
||||
GAS_GROUP_CHEMICALS
|
||||
),
|
||||
"scrubbing" = 1,
|
||||
"widenet" = 1,
|
||||
@@ -582,9 +584,16 @@
|
||||
))
|
||||
for(var/device_id in A.air_vent_names)
|
||||
send_signal(device_id, list(
|
||||
"is_pressurizing" = 1,
|
||||
"power" = 1,
|
||||
"checks" = 1,
|
||||
"set_external_pressure" = ONE_ATMOSPHERE*2
|
||||
"set_external_pressure" = ONE_ATMOSPHERE*1.4
|
||||
))
|
||||
send_signal(device_id, list(
|
||||
"is_siphoning" = 1,
|
||||
"power" = 1,
|
||||
"checks" = 1,
|
||||
"set_external_pressure" = ONE_ATMOSPHERE/1.4
|
||||
))
|
||||
if(AALARM_MODE_REFILL)
|
||||
for(var/device_id in A.air_scrub_names)
|
||||
@@ -596,10 +605,15 @@
|
||||
))
|
||||
for(var/device_id in A.air_vent_names)
|
||||
send_signal(device_id, list(
|
||||
"is_pressurizing" = 1,
|
||||
"power" = 1,
|
||||
"checks" = 1,
|
||||
"set_external_pressure" = ONE_ATMOSPHERE * 3
|
||||
))
|
||||
send_signal(device_id, list(
|
||||
"is_siphoning" = 1,
|
||||
"power" = 0,
|
||||
))
|
||||
if(AALARM_MODE_PANIC,
|
||||
AALARM_MODE_REPLACEMENT)
|
||||
for(var/device_id in A.air_scrub_names)
|
||||
@@ -610,8 +624,14 @@
|
||||
))
|
||||
for(var/device_id in A.air_vent_names)
|
||||
send_signal(device_id, list(
|
||||
"is_pressurizing" = 1,
|
||||
"power" = 0
|
||||
))
|
||||
send_signal(device_id, list(
|
||||
"is_siphoning" = 1,
|
||||
"power" = 1,
|
||||
"checks" = 0
|
||||
))
|
||||
if(AALARM_MODE_SIPHON)
|
||||
for(var/device_id in A.air_scrub_names)
|
||||
send_signal(device_id, list(
|
||||
@@ -621,9 +641,14 @@
|
||||
))
|
||||
for(var/device_id in A.air_vent_names)
|
||||
send_signal(device_id, list(
|
||||
"is_pressurizing" = 1,
|
||||
"power" = 0
|
||||
))
|
||||
|
||||
send_signal(device_id, list(
|
||||
"is_siphoning" = 1,
|
||||
"power" = 1,
|
||||
"checks" = 0
|
||||
))
|
||||
if(AALARM_MODE_OFF)
|
||||
for(var/device_id in A.air_scrub_names)
|
||||
send_signal(device_id, list(
|
||||
@@ -641,8 +666,12 @@
|
||||
for(var/device_id in A.air_vent_names)
|
||||
send_signal(device_id, list(
|
||||
"power" = 1,
|
||||
"checks" = 2,
|
||||
"set_internal_pressure" = 0
|
||||
"checks" = 0,
|
||||
"is_pressurizing" = 1
|
||||
))
|
||||
send_signal(device_id, list(
|
||||
"power" = 0,
|
||||
"is_siphoning" = 1
|
||||
))
|
||||
|
||||
/obj/machinery/airalarm/update_icon_state()
|
||||
|
||||
@@ -29,13 +29,16 @@ Passive gate is similar to the regular pump except:
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user)
|
||||
if(can_interact(user))
|
||||
on = !on
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/AltClick(mob/user)
|
||||
if(can_interact(user))
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "pressure output set to [target_pressure] kPa")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/Destroy()
|
||||
|
||||
@@ -33,25 +33,19 @@
|
||||
. += "<span class='notice'>You can hold <b>Alt</b> and click on it to maximize its pressure.</span>"
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/CtrlClick(mob/user)
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE,))
|
||||
if(can_interact(user))
|
||||
on = !on
|
||||
update_icon()
|
||||
investigate_log("Pump, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
|
||||
message_admins("Pump, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return ..()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/AltClick(mob/user)
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE,))
|
||||
if(can_interact(user))
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
to_chat(user,"<span class='notice'>You maximize the pressure on the [src].</span>")
|
||||
investigate_log("Pump, [src.name], was maximized by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
|
||||
message_admins("Pump, [src.name], was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return TRUE
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "pressure output set to [target_pressure] kPa")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
|
||||
@@ -33,15 +33,20 @@
|
||||
. += "<span class='notice'>You can hold <b>Alt</b> and click on it to maximize its pressure.</span>"
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/CtrlClick(mob/user)
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE,))
|
||||
on = !on
|
||||
update_icon()
|
||||
investigate_log("Volume Pump, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
|
||||
message_admins("Volume Pump, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/AltClick(mob/user)
|
||||
if(can_interact(user))
|
||||
transfer_rate = MAX_TRANSFER_RATE
|
||||
investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "volume output set to [transfer_rate] L/s")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
@@ -20,25 +20,19 @@
|
||||
. += "<span class='notice'>You can hold <b>Alt</b> and click on it to maximize its flow rate.</span>"
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/CtrlClick(mob/user)
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE,))
|
||||
on = !on
|
||||
update_icon()
|
||||
investigate_log("Filter, [src.name], turned on by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
|
||||
message_admins("Filter, [src.name], turned [on ? "on" : "off"] by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/AltClick(mob/user)
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE,))
|
||||
if(can_interact(user))
|
||||
transfer_rate = MAX_TRANSFER_RATE
|
||||
to_chat(user,"<span class='notice'>You maximize the flow rate on the [src].</span>")
|
||||
investigate_log("Filter, [src.name], was maximized by [key_name(usr)] at [x], [y], [z], [A]", INVESTIGATE_ATMOS)
|
||||
message_admins("Filter, [src.name], was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return TRUE
|
||||
investigate_log("was set to [transfer_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "volume output set to [transfer_rate] L/s")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
@@ -100,7 +94,10 @@
|
||||
if(transfer_ratio > 0)
|
||||
|
||||
if(filter_type && air2.return_pressure() <= 9000)
|
||||
air1.scrub_into(air2, transfer_ratio, list(filter_type))
|
||||
if(filter_type in GLOB.gas_data.groups)
|
||||
air1.scrub_into(air2, transfer_ratio, GLOB.gas_data.groups[filter_type])
|
||||
else
|
||||
air1.scrub_into(air2, transfer_ratio, list(filter_type))
|
||||
if(air3.return_pressure() <= 9000)
|
||||
air1.transfer_ratio_to(air3, transfer_ratio)
|
||||
|
||||
@@ -125,8 +122,10 @@
|
||||
data["filter_types"] = list()
|
||||
data["filter_types"] += list(list("name" = "Nothing", "id" = "", "selected" = !filter_type))
|
||||
for(var/id in GLOB.gas_data.ids)
|
||||
data["filter_types"] += list(list("name" = GLOB.gas_data.names[id], "id" = id, "selected" = (id == filter_type)))
|
||||
|
||||
if(!(id in GLOB.gas_data.groups_by_gas))
|
||||
data["filter_types"] += list(list("name" = GLOB.gas_data.names[id], "id" = id, "selected" = (id == filter_type)))
|
||||
for(var/group in GLOB.gas_data.groups)
|
||||
data["filter_types"] += list(list("name" = group, "id" = group, "selected" = (group == filter_type)))
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/ui_act(action, params)
|
||||
|
||||
@@ -17,35 +17,27 @@
|
||||
//node 3 is the outlet, nodes 1 & 2 are intakes
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/mixer/CtrlClick(mob/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
if(can_interact(user))
|
||||
on = !on
|
||||
update_icon()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/mixer/AltClick(mob/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
if(can_interact(user))
|
||||
target_pressure = MAX_OUTPUT_PRESSURE
|
||||
update_icon()
|
||||
investigate_log("was set to [target_pressure] kPa by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "pressure output on set to [target_pressure] kPa")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
//node 3 is the outlet, nodes 1 & 2 are intakes
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/mixer/update_icon()
|
||||
cut_overlays()
|
||||
/obj/machinery/atmospherics/components/trinary/mixer/update_overlays()
|
||||
. = ..()
|
||||
for(var/direction in GLOB.cardinals)
|
||||
if(!(direction & initialize_directions))
|
||||
continue
|
||||
var/obj/machinery/atmospherics/node = findConnecting(direction)
|
||||
|
||||
var/image/cap
|
||||
if(node)
|
||||
cap = getpipeimage(icon, "cap", direction, node.pipe_color, piping_layer = piping_layer)
|
||||
else
|
||||
cap = getpipeimage(icon, "cap", direction, piping_layer = piping_layer)
|
||||
|
||||
add_overlay(cap)
|
||||
|
||||
return ..()
|
||||
. += getpipeimage(icon, "cap", direction, pipe_color, piping_layer, TRUE)
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/mixer/update_icon_nopipes()
|
||||
var/on_state = on && nodes[1] && nodes[2] && nodes[3] && is_operational()
|
||||
|
||||
@@ -72,10 +72,10 @@
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/contents_explosion(severity, target)
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/contents_explosion(severity, target, origin)
|
||||
..()
|
||||
if(beaker)
|
||||
beaker.ex_act(severity, target)
|
||||
beaker.ex_act(severity, target, origin)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/handle_atom_del(atom/A)
|
||||
..()
|
||||
@@ -439,7 +439,7 @@
|
||||
return // we don't see the pipe network while inside cryo.
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/get_remote_view_fullscreens(mob/user)
|
||||
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
|
||||
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/scaled/impaired, 1)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/can_crawl_through()
|
||||
return // can't ventcrawl in or out of cryo.
|
||||
|
||||
@@ -24,13 +24,16 @@
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/CtrlClick(mob/user)
|
||||
if(can_interact(user))
|
||||
on = !on
|
||||
update_icon()
|
||||
investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/AltClick(mob/user)
|
||||
if(can_interact(user))
|
||||
volume_rate = MAX_TRANSFER_RATE
|
||||
update_icon()
|
||||
investigate_log("was set to [volume_rate] L/s by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "volume output set to [volume_rate] L/s")
|
||||
update_appearance()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/Destroy()
|
||||
|
||||
@@ -59,10 +59,10 @@
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>The thermostat is set to [target_temperature]K ([(T0C-target_temperature)*-1]C).</span>"
|
||||
. += "<span class='notice'>The thermostat is set to [target_temperature]K ([target_temperature-T0C]C).</span>"
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += "<span class='notice'>The status display reads: Efficiency <b>[(heat_capacity/5000)*100]%</b>.</span>"
|
||||
. += "<span class='notice'>Temperature range <b>[min_temperature]K - [max_temperature]K ([(T0C-min_temperature)*-1]C - [(T0C-max_temperature)*-1]C)</b>.</span>"
|
||||
. += "<span class='notice'>The status display reads: Effective heat capacity <b>[heat_capacity] J/K</b>.</span>"
|
||||
. += "<span class='notice'>Temperature range <b>[min_temperature]K - [max_temperature]K ([min_temperature-T0C]C - [max_temperature-T0C]C)</b>.</span>"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/process_atmos()
|
||||
..()
|
||||
@@ -217,16 +217,11 @@
|
||||
min_temperature = max(T0C - (initial(min_temperature) + L * 15), TCMB) //73.15K with T1 stock parts
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
if(!can_interact(user))
|
||||
return
|
||||
target_temperature = min_temperature
|
||||
to_chat(user,"<span class='notice'>You minimize the temperature on the [src].</span>")
|
||||
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
|
||||
message_admins("[src.name] was minimized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
|
||||
return TRUE
|
||||
investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS)
|
||||
balloon_alert(user, "temperature reset to [target_temperature] K")
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/thermomachine/heater
|
||||
name = "heater"
|
||||
|
||||
@@ -178,6 +178,9 @@
|
||||
|
||||
var/mob/signal_sender = signal.data["user"]
|
||||
|
||||
if((("is_siphoning" in signal.data) && pump_direction == RELEASING) || (("is_pressurizing" in signal.data) && pump_direction == SIPHONING))
|
||||
return
|
||||
|
||||
if("purge" in signal.data)
|
||||
pressure_checks &= ~EXT_BOUND
|
||||
pump_direction = SIPHONING
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
var/id_tag = null
|
||||
var/scrubbing = SCRUBBING //0 = siphoning, 1 = scrubbing
|
||||
|
||||
var/filter_types = list(GAS_CO2)
|
||||
var/filter_types = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS)
|
||||
var/list/clean_filter_types = null
|
||||
var/volume_rate = 200
|
||||
var/widenet = 0 //is this scrubber acting on the 3x3 area around it.
|
||||
var/list/turf/adjacent_turfs = list()
|
||||
@@ -34,6 +35,16 @@
|
||||
..()
|
||||
if(!id_tag)
|
||||
id_tag = assign_uid_vents()
|
||||
generate_clean_filter_types()
|
||||
RegisterSignal(SSdcs,COMSIG_GLOB_NEW_GAS,.proc/generate_clean_filter_types)
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/generate_clean_filter_types()
|
||||
clean_filter_types = list()
|
||||
for(var/id in filter_types)
|
||||
if(id in GLOB.gas_data.groups)
|
||||
clean_filter_types += GLOB.gas_data.groups[id]
|
||||
else
|
||||
clean_filter_types += id
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/vent_scrubber/Destroy()
|
||||
var/area/A = get_base_area(src)
|
||||
@@ -95,7 +106,11 @@
|
||||
|
||||
var/list/f_types = list()
|
||||
for(var/id in GLOB.gas_data.ids)
|
||||
f_types += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in filter_types)))
|
||||
if(!(id in GLOB.gas_data.groups_by_gas))
|
||||
f_types += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in filter_types)))
|
||||
|
||||
for(var/group in GLOB.gas_data.groups)
|
||||
f_types += list(list("gas_id" = group, "gas_name" = group, "enabled" = (group in filter_types)))
|
||||
|
||||
var/datum/signal/signal = new(list(
|
||||
"tag" = id_tag,
|
||||
@@ -147,11 +162,11 @@
|
||||
var/datum/gas_mixture/environment = tile.return_air()
|
||||
var/datum/gas_mixture/air_contents = airs[1]
|
||||
|
||||
if(air_contents.return_pressure() >= 50*ONE_ATMOSPHERE || !islist(filter_types))
|
||||
if(air_contents.return_pressure() >= 50*ONE_ATMOSPHERE || !islist(clean_filter_types))
|
||||
return FALSE
|
||||
|
||||
if(scrubbing & SCRUBBING)
|
||||
environment.scrub_into(air_contents, volume_rate/environment.return_volume(), filter_types)
|
||||
environment.scrub_into(air_contents, volume_rate/environment.return_volume(), clean_filter_types)
|
||||
|
||||
tile.air_update_turf()
|
||||
|
||||
@@ -205,11 +220,13 @@
|
||||
|
||||
if("toggle_filter" in signal.data)
|
||||
filter_types ^= signal.data["toggle_filter"]
|
||||
generate_clean_filter_types()
|
||||
|
||||
if("set_filters" in signal.data)
|
||||
filter_types = list()
|
||||
for(var/gas in signal.data["set_filters"])
|
||||
filter_types += gas
|
||||
generate_clean_filter_types()
|
||||
|
||||
if("init" in signal.data)
|
||||
name = signal.data["init"]
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
var/ghost_usable = TRUE
|
||||
var/skip_reentry_check = FALSE //Skips the ghost role blacklist time for people who ghost/suicide/cryo
|
||||
|
||||
///override this to add special spawn conditions to a ghost role
|
||||
/obj/effect/mob_spawn/proc/allow_spawn(mob/user, silent = FALSE)
|
||||
return TRUE
|
||||
|
||||
//ATTACK GHOST IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/mob_spawn/attack_ghost(mob/user, latejoinercalling)
|
||||
if(!SSticker.HasRoundStarted() || !loc || !ghost_usable)
|
||||
@@ -43,6 +47,8 @@
|
||||
if(jobban_isbanned(user, banType))
|
||||
to_chat(user, "<span class='warning'>You are jobanned!</span>")
|
||||
return
|
||||
if(!allow_spawn(user, silent = FALSE))
|
||||
return
|
||||
if(QDELETED(src) || QDELETED(user))
|
||||
return
|
||||
if(isobserver(user))
|
||||
|
||||
@@ -149,5 +149,5 @@ GLOBAL_VAR_INIT(sc_safecode5, "[rand(0,9)]")
|
||||
if(prob(25))
|
||||
mezzer()
|
||||
|
||||
/obj/singularity/narsie/mini/ex_act()
|
||||
/obj/singularity/narsie/mini/ex_act(severity, target, origin)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#define BALLOON_TEXT_WIDTH 200
|
||||
#define BALLOON_TEXT_SPAWN_TIME (0.2 SECONDS)
|
||||
#define BALLOON_TEXT_FADE_TIME (0.1 SECONDS)
|
||||
#define BALLOON_TEXT_FULLY_VISIBLE_TIME (0.7 SECONDS)
|
||||
#define BALLOON_TEXT_TOTAL_LIFETIME(mult) (BALLOON_TEXT_SPAWN_TIME + BALLOON_TEXT_FULLY_VISIBLE_TIME*mult + BALLOON_TEXT_FADE_TIME)
|
||||
/// The increase in duration per character in seconds
|
||||
#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT (0.05)
|
||||
/// The amount of characters needed before this increase takes into effect
|
||||
#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN 10
|
||||
|
||||
/// Creates text that will float from the atom upwards to the viewer.
|
||||
/atom/proc/balloon_alert(mob/viewer, text)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
INVOKE_ASYNC(src, .proc/balloon_alert_perform, viewer, text)
|
||||
|
||||
/// Create balloon alerts (text that floats up) to everything within range.
|
||||
/// Will only display to people who can see.
|
||||
/atom/proc/balloon_alert_to_viewers(message, self_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
var/list/hearers = get_hearers_in_view(vision_distance, src)
|
||||
hearers -= ignored_mobs
|
||||
|
||||
for (var/mob/hearer in hearers)
|
||||
if (hearer.is_blind())
|
||||
continue
|
||||
|
||||
balloon_alert(hearer, (hearer == src && self_message) || message)
|
||||
|
||||
// Do not use.
|
||||
// MeasureText blocks. I have no idea for how long.
|
||||
// I would've made the maptext_height update on its own, but I don't know
|
||||
// if this would look bad on laggy clients.
|
||||
/atom/proc/balloon_alert_perform(mob/viewer, text)
|
||||
var/client/viewer_client = viewer.client
|
||||
if (isnull(viewer_client))
|
||||
return
|
||||
|
||||
var/bound_width = world.icon_size
|
||||
if (ismovable(src))
|
||||
var/atom/movable/movable_source = src
|
||||
bound_width = movable_source.bound_width
|
||||
|
||||
var/image/balloon_alert = image(loc = get_atom_on_turf(src), layer = ABOVE_MOB_LAYER)
|
||||
balloon_alert.plane = BALLOON_CHAT_PLANE
|
||||
balloon_alert.alpha = 0
|
||||
balloon_alert.appearance_flags = RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
|
||||
balloon_alert.maptext = MAPTEXT("<span style='text-align: center; -dm-text-outline: 1px #0005'>[text]</span>")
|
||||
balloon_alert.maptext_x = (BALLOON_TEXT_WIDTH - bound_width) * -0.5
|
||||
balloon_alert.maptext_height = WXH_TO_HEIGHT(viewer_client?.MeasureText(text, null, BALLOON_TEXT_WIDTH))
|
||||
balloon_alert.maptext_width = BALLOON_TEXT_WIDTH
|
||||
|
||||
viewer_client?.images += balloon_alert
|
||||
|
||||
var/duration_mult = 1
|
||||
var/duration_length = length(text) - BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN
|
||||
|
||||
if(duration_length > 0)
|
||||
duration_mult += duration_length*BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT
|
||||
|
||||
animate(
|
||||
balloon_alert,
|
||||
pixel_y = world.icon_size * 1.2,
|
||||
time = BALLOON_TEXT_TOTAL_LIFETIME(1),
|
||||
easing = SINE_EASING | EASE_OUT,
|
||||
)
|
||||
|
||||
animate(
|
||||
alpha = 255,
|
||||
time = BALLOON_TEXT_SPAWN_TIME,
|
||||
easing = CUBIC_EASING | EASE_OUT,
|
||||
flags = ANIMATION_PARALLEL,
|
||||
)
|
||||
|
||||
animate(
|
||||
alpha = 0,
|
||||
time = BALLOON_TEXT_FULLY_VISIBLE_TIME*duration_mult,
|
||||
easing = CUBIC_EASING | EASE_IN,
|
||||
)
|
||||
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/remove_image_from_client, balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult))
|
||||
|
||||
#undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN
|
||||
#undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT
|
||||
#undef BALLOON_TEXT_FADE_TIME
|
||||
#undef BALLOON_TEXT_FULLY_VISIBLE_TIME
|
||||
#undef BALLOON_TEXT_SPAWN_TIME
|
||||
#undef BALLOON_TEXT_TOTAL_LIFETIME
|
||||
#undef BALLOON_TEXT_WIDTH
|
||||
@@ -0,0 +1,65 @@
|
||||
GLOBAL_VAR_INIT(save_area_executing, FALSE)
|
||||
|
||||
/datum/mapGenerator/save_area
|
||||
buildmode_name = "Save Area"
|
||||
modules = list(/datum/mapGeneratorModule/save_area)
|
||||
var/min_x = 0
|
||||
var/min_y = 0
|
||||
var/max_x = 0
|
||||
var/max_y = 0
|
||||
|
||||
/datum/mapGenerator/save_area/defineRegion(turf/Start, turf/End, replace = 0)
|
||||
min_x = min(Start.x,End.x)
|
||||
min_y = min(Start.y,End.y)
|
||||
max_x = max(Start.x,End.x)
|
||||
max_y = max(Start.y,End.y)
|
||||
..()
|
||||
|
||||
/datum/mapGeneratorModule/save_area
|
||||
var/areaName = "default.dm"
|
||||
|
||||
//This could be optimised by making turfs that are the same go in the same, but this is a quick bodge solution so yea, fun job for coder here :)
|
||||
/datum/mapGeneratorModule/save_area/generate()
|
||||
var/datum/mapGenerator/save_area/L = mother
|
||||
if(!istype(L))
|
||||
return
|
||||
//If someone somehow gets build mode, stop them from using this.
|
||||
if(!check_rights(R_ADMIN))
|
||||
message_admins("[ckey(usr)] tried to run the map save generator but was rejected due to insufficient perms.")
|
||||
to_chat(usr, "<span class='warning'>You must have R_ADMIN privellages to use this.</span>")
|
||||
return
|
||||
//Emergency check
|
||||
if(L.map.len > 1600)
|
||||
var/confirm = alert("Uhm, are you sure, the area is quiet large?", "Run generator", "Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
|
||||
if(GLOB.save_area_executing)
|
||||
to_chat(usr, "<span class='warning'>Someone is already running the generator! Try again in a bit.</span>")
|
||||
return
|
||||
|
||||
to_chat(usr, "<span class='warning'>Saving, please wait...</span>")
|
||||
GLOB.save_area_executing = TRUE
|
||||
|
||||
//Log just in case something happens
|
||||
log_game("[key_name(usr)] ran the save level map generator on [L.map.len] turfs.")
|
||||
message_admins("[key_name(usr)] ran the save level map generator on [L.map.len] turfs.")
|
||||
|
||||
//Step 1: Get the data (This can take a while)
|
||||
var/dat = "//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE\n"
|
||||
dat += convert_map_to_tgm(L.map)
|
||||
|
||||
//Step 2: Write the data to a file
|
||||
var/filedir = file("data/temp.dmm")
|
||||
if(fexists(filedir))
|
||||
fdel(filedir)
|
||||
WRITE_FILE(filedir, "[dat]")
|
||||
|
||||
//Step 3: Give the file to client for download
|
||||
usr << ftp(filedir)
|
||||
|
||||
//Step 4: Remove the file from the server (hopefully we can find a way to avoid step)
|
||||
fdel(filedir)
|
||||
log_game("[L.map.len] turfs have been saved by [ckey(usr)]")
|
||||
alert("Area saved successfully.", "Action Successful!", "Ok")
|
||||
GLOB.save_area_executing = FALSE
|
||||
@@ -52,7 +52,7 @@
|
||||
desc = "Packs of tools waiting to be used for repairing. Contains a tool and engineering vending machine refill. Requires CE access."
|
||||
cost = 5500 //Powerfull
|
||||
access = ACCESS_CE
|
||||
contains = list(/obj/item/vending_refill/tool,
|
||||
contains = list(/obj/item/vending_refill/youtool,
|
||||
/obj/item/vending_refill/engivend)
|
||||
crate_name = "engineering supply crate"
|
||||
crate_type = /obj/structure/closet/crate/secure/engineering
|
||||
|
||||
@@ -187,10 +187,10 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/closet/supplypod/ex_act() //Explosions dont do SHIT TO US! This is because supplypods create explosions when they land.
|
||||
/obj/structure/closet/supplypod/ex_act(severity, target, origin) //Explosions dont do SHIT TO US! This is because supplypods create explosions when they land.
|
||||
return
|
||||
|
||||
/obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding.
|
||||
/obj/structure/closet/supplypod/contents_explosion(severity, target, origin) //Supplypods also protect their contents from the harmful effects of fucking exploding.
|
||||
return
|
||||
|
||||
/obj/structure/closet/supplypod/toggle(mob/living/user)
|
||||
|
||||
@@ -4,6 +4,16 @@
|
||||
//BLACK MAGIC THINGS//
|
||||
//////////////////////
|
||||
parent_type = /datum
|
||||
|
||||
///////////////
|
||||
// Rendering //
|
||||
///////////////
|
||||
|
||||
/// Click catcher
|
||||
var/atom/movable/screen/click_catcher/click_catcher
|
||||
/// Parallax holder
|
||||
var/datum/parallax_holder/parallax_holder
|
||||
|
||||
////////////////
|
||||
//ADMIN THINGS//
|
||||
////////////////
|
||||
@@ -34,6 +44,9 @@
|
||||
var/last_move = 0
|
||||
var/area = null
|
||||
|
||||
/// Timers are now handled by clients, not by doing a mess on the item and multiple people overwriting a single timer on the object, have fun.
|
||||
var/tip_timer = null
|
||||
|
||||
/// Last time we Click()ed. No clicking twice in one tick!
|
||||
var/last_click = 0
|
||||
|
||||
@@ -150,20 +163,6 @@
|
||||
///When was the last time we warned them about not cryoing without an ahelp, set to -5 minutes so that rounstart cryo still warns
|
||||
var/cryo_warned = -5 MINUTES
|
||||
|
||||
var/list/parallax_layers
|
||||
var/list/parallax_layers_cached
|
||||
var/atom/movable/movingmob
|
||||
var/turf/previous_turf
|
||||
///world.time of when we can state animate()ing parallax again
|
||||
var/dont_animate_parallax
|
||||
///world.time of last parallax update
|
||||
var/last_parallax_shift
|
||||
///ds between parallax updates
|
||||
var/parallax_throttle = 0
|
||||
var/parallax_movedir = 0
|
||||
var/parallax_layers_max = 3
|
||||
var/parallax_animate_timer
|
||||
|
||||
/**
|
||||
* Assoc list with all the active maps - when a screen obj is added to
|
||||
* a map, it's put in here as well.
|
||||
|
||||
@@ -79,15 +79,16 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
// Tgui Topic middleware
|
||||
if(tgui_Topic(href_list))
|
||||
if(CONFIG_GET(flag/emergency_tgui_logging))
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
return
|
||||
if(href_list["reload_tguipanel"])
|
||||
nuke_chat()
|
||||
if(href_list["reload_statbrowser"])
|
||||
src << browse(file('html/statbrowser.html'), "window=statbrowser")
|
||||
// Log all hrefs
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
|
||||
last_activity = world.time
|
||||
|
||||
//Logs all hrefs
|
||||
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
|
||||
|
||||
//byond bug ID:2256651
|
||||
if (asset_cache_job && (asset_cache_job in completed_asset_jobs))
|
||||
to_chat(src, "<span class='danger'>An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)</span>")
|
||||
@@ -353,13 +354,19 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
return
|
||||
|
||||
// Initialize tgui panel
|
||||
tgui_panel.initialize()
|
||||
src << browse(file('html/statbrowser.html'), "window=statbrowser")
|
||||
addtimer(CALLBACK(src, .proc/check_panel_loaded), 30 SECONDS)
|
||||
tgui_panel.initialize()
|
||||
|
||||
|
||||
if(alert_mob_dupe_login)
|
||||
spawn()
|
||||
alert(mob, "You have logged in already with another key this round, please log out of this one NOW or risk being banned!")
|
||||
if(alert_mob_dupe_login && !holder)
|
||||
var/dupe_login_message = "Your ComputerID has already logged in with another key this round, please log out of this one NOW or risk being banned!"
|
||||
// if (alert_admin_multikey)
|
||||
// dupe_login_message += "\nAdmins have been informed."
|
||||
// message_admins(span_danger("<B>MULTIKEYING: </B></span><span class='notice'>[key_name_admin(src)] has a matching CID+IP with another player and is clearly multikeying. They have been warned to leave the server or risk getting banned."))
|
||||
// log_admin_private("MULTIKEYING: [key_name(src)] has a matching CID+IP with another player and is clearly multikeying. They have been warned to leave the server or risk getting banned.")
|
||||
spawn(0.5 SECONDS) //needs to run during world init, do not convert to add timer
|
||||
alert(mob, dupe_login_message) //players get banned if they don't see this message, do not convert to tgui_alert (or even tg_alert) please.
|
||||
to_chat(mob, span_danger(dupe_login_message))
|
||||
|
||||
connection_time = world.time
|
||||
connection_realtime = world.realtime
|
||||
@@ -437,8 +444,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
send_resources()
|
||||
|
||||
generate_clickcatcher()
|
||||
apply_clickcatcher()
|
||||
update_clickcatcher()
|
||||
|
||||
if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates.
|
||||
to_chat(src, "<span class='info'>You have unread updates in the changelog.</span>")
|
||||
@@ -528,9 +534,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
send2adminchat("Server", "[cheesy_message] (No admins online)")
|
||||
QDEL_LIST_ASSOC_VAL(char_render_holders)
|
||||
if(movingmob != null)
|
||||
movingmob.client_mobs_in_contents -= mob
|
||||
UNSETEMPTY(movingmob.client_mobs_in_contents)
|
||||
// seen_messages = null
|
||||
Master.UpdateTickRate()
|
||||
. = ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening
|
||||
@@ -1007,7 +1010,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
var/list/old_view = getviewsize(view)
|
||||
view = new_size
|
||||
var/list/actualview = getviewsize(view)
|
||||
apply_clickcatcher(actualview)
|
||||
update_clickcatcher()
|
||||
parallax_holder.Reset()
|
||||
mob.reload_fullscreen()
|
||||
if (isliving(mob))
|
||||
var/mob/living/M = mob
|
||||
@@ -1016,33 +1020,31 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls.
|
||||
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_CHANGE_VIEW, src, old_view, actualview)
|
||||
|
||||
/client/proc/generate_clickcatcher()
|
||||
if(!void)
|
||||
void = new()
|
||||
screen += void
|
||||
|
||||
/client/proc/apply_clickcatcher(list/actualview)
|
||||
generate_clickcatcher()
|
||||
if(!actualview)
|
||||
actualview = getviewsize(view)
|
||||
void.UpdateGreed(actualview[1],actualview[2])
|
||||
|
||||
/client/proc/AnnouncePR(announcement)
|
||||
if(prefs && prefs.chat_toggles & CHAT_PULLR)
|
||||
to_chat(src, announcement)
|
||||
|
||||
/client/proc/show_character_previews(mutable_appearance/MA)
|
||||
/client/proc/show_character_previews(mutable_appearance/source)
|
||||
LAZYINITLIST(char_render_holders)
|
||||
if(!LAZYLEN(char_render_holders))
|
||||
for(var/plane_master_path as anything in subtypesof(/atom/movable/screen/plane_master))
|
||||
var/atom/movable/screen/plane_master/plane_master = new plane_master_path()
|
||||
char_render_holders["plane_master-[plane_master.plane]"] = plane_master
|
||||
plane_master.backdrop(mob)
|
||||
screen |= plane_master
|
||||
plane_master.screen_loc = "character_preview_map:0,CENTER"
|
||||
|
||||
var/pos = 0
|
||||
for(var/D in GLOB.cardinals)
|
||||
for(var/dir in GLOB.cardinals)
|
||||
pos++
|
||||
var/atom/movable/screen/O = LAZYACCESS(char_render_holders, "[D]")
|
||||
if(!O)
|
||||
O = new
|
||||
LAZYSET(char_render_holders, "[D]", O)
|
||||
screen |= O
|
||||
O.appearance = MA
|
||||
O.dir = D
|
||||
O.screen_loc = "character_preview_map:0,[pos]"
|
||||
var/atom/movable/screen/preview = char_render_holders["preview-[dir]"]
|
||||
if(!preview)
|
||||
preview = new
|
||||
char_render_holders["preview-[dir]"] = preview
|
||||
screen |= preview
|
||||
preview.appearance = source
|
||||
preview.dir = dir
|
||||
preview.screen_loc = "character_preview_map:0,[pos]"
|
||||
|
||||
/client/proc/clear_character_previews()
|
||||
for(var/index in char_render_holders)
|
||||
@@ -1078,8 +1080,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(IsAdminAdvancedProcCall())
|
||||
return
|
||||
var/list/verblist = list()
|
||||
verb_tabs.Cut()
|
||||
for(var/thing in (verbs + mob?.verbs))
|
||||
var/list/verbstoprocess = verbs.Copy()
|
||||
if(mob)
|
||||
verbstoprocess += mob.verbs
|
||||
for(var/AM in mob.contents)
|
||||
var/atom/movable/thing = AM
|
||||
verbstoprocess += thing.verbs
|
||||
panel_tabs.Cut() // panel_tabs get reset in init_verbs on JS side anyway
|
||||
for(var/thing in verbstoprocess)
|
||||
var/procpath/verb_to_init = thing
|
||||
if(!verb_to_init)
|
||||
continue
|
||||
@@ -1087,9 +1095,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
continue
|
||||
if(!istext(verb_to_init.category))
|
||||
continue
|
||||
verb_tabs |= verb_to_init.category
|
||||
panel_tabs |= verb_to_init.category
|
||||
verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name)
|
||||
src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
|
||||
src << output("[url_encode(json_encode(panel_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
|
||||
|
||||
/client/proc/check_panel_loaded()
|
||||
if(statbrowser_ready)
|
||||
return
|
||||
to_chat(src, span_userdanger("Statpanel failed to load, click <a href='?src=[REF(src)];reload_statbrowser=1'>here</a> to reload the panel "))
|
||||
|
||||
//increment progress for an unlockable loadout item
|
||||
/client/proc/increment_progress(key, amount)
|
||||
|
||||
@@ -61,7 +61,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
var/UI_style = null
|
||||
var/outline_enabled = TRUE
|
||||
var/outline_color = COLOR_BLUE_GRAY
|
||||
var/outline_color = COLOR_THEME_MIDNIGHT
|
||||
var/buttons_locked = FALSE
|
||||
var/hotkeys = FALSE
|
||||
|
||||
@@ -164,13 +164,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
var/clientfps = 0
|
||||
|
||||
var/parallax
|
||||
var/parallax = PARALLAX_INSANE
|
||||
|
||||
var/ambientocclusion = TRUE
|
||||
///Should we automatically fit the viewport?
|
||||
var/auto_fit_viewport = FALSE
|
||||
///Should we be in the widescreen mode set by the config?
|
||||
var/widescreenpref = TRUE
|
||||
///Strip menu style
|
||||
var/long_strip_menu = FALSE
|
||||
///What size should pixels be displayed as? 0 is strech to fit
|
||||
var/pixel_size = 0
|
||||
///What scaling method should we use?
|
||||
@@ -785,7 +787,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<h2>General Settings</h2>"
|
||||
dat += "<b>UI Style:</b> <a href='?_src_=prefs;task=input;preference=ui'>[UI_style]</a><br>"
|
||||
dat += "<b>Outline:</b> <a href='?_src_=prefs;preference=outline_enabled'>[outline_enabled ? "Enabled" : "Disabled"]</a><br>"
|
||||
dat += "<b>Outline Color:</b> <span style='border:1px solid #161616; background-color: [outline_color];'> </span> <a href='?_src_=prefs;preference=outline_color'>Change</a><BR>"
|
||||
dat += "<b>Outline Color:</b> [outline_color ? "<span style='border:1px solid #161616; background-color: [outline_color];'>" : "Theme-based (null)"] </span> <a href='?_src_=prefs;preference=outline_color'>Change</a><BR>"
|
||||
dat += "<b>tgui Monitors:</b> <a href='?_src_=prefs;preference=tgui_lock'>[(tgui_lock) ? "Primary" : "All"]</a><br>"
|
||||
dat += "<b>tgui Style:</b> <a href='?_src_=prefs;preference=tgui_fancy'>[(tgui_fancy) ? "Fancy" : "No Frills"]</a><br>"
|
||||
dat += "<b>Show Runechat Chat Bubbles:</b> <a href='?_src_=prefs;preference=chat_on_map'>[chat_on_map ? "Enabled" : "Disabled"]</a><br>"
|
||||
@@ -829,6 +831,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat +="<td width='300px' height='300px' valign='top'>"
|
||||
dat += "<h2>Citadel Preferences</h2>" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe.
|
||||
dat += "<b>Widescreen:</b> <a href='?_src_=prefs;preference=widescreenpref'>[widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]</a><br>"
|
||||
dat += "<b>Long strip menu:</b> <a href='?_src_=prefs;preference=long_strip_menu'>[long_strip_menu ? "Enabled" : "Disabled"]</a><br>"
|
||||
dat += "<b>Auto stand:</b> <a href='?_src_=prefs;preference=autostand'>[autostand ? "Enabled" : "Disabled"]</a><br>"
|
||||
dat += "<b>Auto OOC:</b> <a href='?_src_=prefs;preference=auto_ooc'>[auto_ooc ? "Enabled" : "Disabled"]</a><br>"
|
||||
dat += "<b>Force Slot Storage HUD:</b> <a href='?_src_=prefs;preference=no_tetris_storage'>[no_tetris_storage ? "Enabled" : "Disabled"]</a><br>"
|
||||
@@ -2591,6 +2594,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if("widescreenpref")
|
||||
widescreenpref = !widescreenpref
|
||||
user.client.view_size.setDefault(getScreenSize(widescreenpref))
|
||||
if("long_strip_menu")
|
||||
long_strip_menu = !long_strip_menu
|
||||
|
||||
if("pixel_size")
|
||||
switch(pixel_size)
|
||||
@@ -2739,8 +2744,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
outline_enabled = !outline_enabled
|
||||
if("outline_color")
|
||||
var/pickedOutlineColor = input(user, "Choose your outline color.", "General Preference", outline_color) as color|null
|
||||
if(pickedOutlineColor)
|
||||
outline_color = pickedOutlineColor
|
||||
if(pickedOutlineColor != pickedOutlineColor)
|
||||
outline_color = pickedOutlineColor // nullable
|
||||
if("tgui_lock")
|
||||
tgui_lock = !tgui_lock
|
||||
if("winflash")
|
||||
@@ -2811,14 +2816,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
toggles ^= MIDROUND_ANTAG
|
||||
|
||||
if("parallaxup")
|
||||
parallax = WRAP(parallax + 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
|
||||
if (parent && parent.mob && parent.mob.hud_used)
|
||||
parent.mob.hud_used.update_parallax_pref(parent.mob)
|
||||
parallax = WRAP(parallax + 1, PARALLAX_DISABLE, PARALLAX_INSANE + 1)
|
||||
parent?.parallax_holder?.Reset()
|
||||
|
||||
if("parallaxdown")
|
||||
parallax = WRAP(parallax - 1, PARALLAX_INSANE, PARALLAX_DISABLE + 1)
|
||||
if (parent && parent.mob && parent.mob.hud_used)
|
||||
parent.mob.hud_used.update_parallax_pref(parent.mob)
|
||||
parallax = WRAP(parallax - 1, PARALLAX_DISABLE, PARALLAX_INSANE + 1)
|
||||
parent?.parallax_holder?.Reset()
|
||||
|
||||
// Citadel edit - Prefs don't work outside of this. :c
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// You do not need to raise this if you are adding new values that have sane defaults.
|
||||
// Only raise this value when changing the meaning/format/name/layout of an existing value
|
||||
// where you would want the updater procs below to run
|
||||
#define SAVEFILE_VERSION_MAX 52
|
||||
#define SAVEFILE_VERSION_MAX 53
|
||||
|
||||
/*
|
||||
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
|
||||
@@ -47,7 +47,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice.
|
||||
if(current_version < 30)
|
||||
outline_enabled = TRUE
|
||||
outline_color = COLOR_BLUE_GRAY
|
||||
outline_color = COLOR_THEME_MIDNIGHT
|
||||
|
||||
/datum/preferences/proc/update_character(current_version, savefile/S)
|
||||
if(current_version < 19)
|
||||
@@ -343,6 +343,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
marking_list += list(list(part, old_marking_value, copied_color_list))
|
||||
features["mam_body_markings"] = marking_list
|
||||
|
||||
if(current_version < 53)
|
||||
parallax = PARALLAX_INSANE
|
||||
|
||||
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
|
||||
if(!ckey)
|
||||
return
|
||||
@@ -410,6 +413,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["ambientocclusion"] >> ambientocclusion
|
||||
S["auto_fit_viewport"] >> auto_fit_viewport
|
||||
S["widescreenpref"] >> widescreenpref
|
||||
S["long_strip_menu"] >> long_strip_menu
|
||||
S["pixel_size"] >> pixel_size
|
||||
S["scaling_method"] >> scaling_method
|
||||
S["hud_toggle_flash"] >> hud_toggle_flash
|
||||
@@ -468,10 +472,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
|
||||
toggles = sanitize_integer(toggles, 0, 16777215, initial(toggles))
|
||||
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
|
||||
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
|
||||
parallax = sanitize_integer(parallax, PARALLAX_DISABLE, PARALLAX_INSANE, null)
|
||||
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
|
||||
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
|
||||
widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
|
||||
long_strip_menu = sanitize_integer(long_strip_menu, 0, 1, initial(long_strip_menu))
|
||||
pixel_size = sanitize_integer(pixel_size, PIXEL_SCALING_AUTO, PIXEL_SCALING_3X, initial(pixel_size))
|
||||
scaling_method = sanitize_text(scaling_method, initial(scaling_method))
|
||||
hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash))
|
||||
@@ -604,6 +609,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["damagescreenshake"], damagescreenshake)
|
||||
WRITE_FILE(S["arousable"], arousable)
|
||||
WRITE_FILE(S["widescreenpref"], widescreenpref)
|
||||
WRITE_FILE(S["long_strip_menu"], long_strip_menu)
|
||||
WRITE_FILE(S["autostand"], autostand)
|
||||
WRITE_FILE(S["cit_toggles"], cit_toggles)
|
||||
WRITE_FILE(S["preferred_chaos"], preferred_chaos)
|
||||
|
||||
@@ -18,3 +18,12 @@
|
||||
prefs.tip_delay = max(indelay, 0.01)
|
||||
prefs.save_preferences()
|
||||
to_chat(usr, "<span class='danger'>Tooltip delay set to [indelay] milliseconds.</span>")
|
||||
|
||||
/client/verb/toggle_hover_outline()
|
||||
set name = "Toggle hover outline"
|
||||
set desc = "Toggles hover-over item outline"
|
||||
set category = "Preferences"
|
||||
|
||||
prefs.outline_enabled = !prefs.outline_enabled
|
||||
prefs.save_preferences()
|
||||
to_chat(usr, "<span class='danger'>Item outline [prefs.outline_enabled ? "en" : "dis"]abled.</span>")
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
var/active_sound = null
|
||||
var/toggle_cooldown = null
|
||||
var/cooldown = 0
|
||||
var/obj/item/flashlight/F = null
|
||||
var/can_flashlight = 0
|
||||
|
||||
var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
|
||||
|
||||
@@ -445,7 +443,7 @@ BLIND // can't see anything
|
||||
..()
|
||||
|
||||
//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc.
|
||||
/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE)
|
||||
/obj/item/clothing/mob_can_equip(M, equipper, slot, disable_warning = TRUE, bypass_equip_delay_self)
|
||||
|
||||
//if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam)
|
||||
if(!..())
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/obj/item/clothing/gloves/mittens
|
||||
desc = "These gloves will keep your hands warm!"
|
||||
name = "mittens"
|
||||
icon_state = "mittens"
|
||||
item_state = "wgloves"
|
||||
//item_color = "white"
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
resistance_flags = NONE
|
||||
|
||||
/obj/item/clothing/gloves/mittens/random
|
||||
|
||||
/obj/item/clothing/gloves/mittens/random/Initialize()
|
||||
..()
|
||||
var/colours = list("black", "yellow", "lightbrown", "brown", "orange", "red", "purple", "green", "blue", "kitten")
|
||||
var/picked_c = pick(colours)
|
||||
if(picked_c == "kitten")
|
||||
new /obj/item/clothing/gloves/mittens/kitten(loc)
|
||||
qdel(src)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
item_state = "[picked_c]gloves"
|
||||
//item_color = "[picked_c]"
|
||||
color = picked_c
|
||||
|
||||
/obj/item/clothing/gloves/mittens/kitten
|
||||
name = "Kitten mittens"
|
||||
desc = "These gloves will keep your hands warm, and feature cute kittens"
|
||||
icon_state = "kittenmittens"
|
||||
item_state = "blackgloves"
|
||||
//item_color = "black"
|
||||
@@ -16,17 +16,47 @@
|
||||
|
||||
dog_fashion = /datum/dog_fashion/head/helmet
|
||||
|
||||
var/can_flashlight = FALSE //if a flashlight can be mounted. if it has a flashlight and this is false, it is permanently attached.
|
||||
var/obj/item/flashlight/seclite/attached_light
|
||||
var/datum/action/item_action/toggle_helmet_flashlight/alight
|
||||
|
||||
/obj/item/clothing/head/helmet/Initialize(mapload)
|
||||
. = ..()
|
||||
if(attached_light)
|
||||
alight = new(src)
|
||||
|
||||
/obj/item/clothing/head/helmet/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_HEAD))
|
||||
|
||||
/obj/item/clothing/head/helmet/examine(mob/user)
|
||||
. = ..()
|
||||
if(attached_light)
|
||||
. += "It has \a [attached_light] [can_flashlight ? "" : "permanently "]mounted on it."
|
||||
if(can_flashlight)
|
||||
. += "<span class='info'>[attached_light] looks like it can be <b>unscrewed</b> from [src].</span>"
|
||||
else if(can_flashlight)
|
||||
. += "It has a mounting point for a <b>seclite</b>."
|
||||
|
||||
/obj/item/clothing/head/helmet/Destroy()
|
||||
QDEL_NULL(attached_light)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/helmet/handle_atom_del(atom/A)
|
||||
if(A == attached_light)
|
||||
attached_light = null
|
||||
update_helmlight()
|
||||
update_icon()
|
||||
QDEL_NULL(alight)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/helmet/sec
|
||||
can_flashlight = 1
|
||||
|
||||
/obj/item/clothing/head/helmet/sec/attackby(obj/item/I, mob/user, params)
|
||||
if(issignaler(I))
|
||||
var/obj/item/assembly/signaler/S = I
|
||||
if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
|
||||
if(attached_light) //Has a flashlight. Player must remove it, else it will be lost forever.
|
||||
to_chat(user, "<span class='warning'>The mounted flashlight is in the way, remove it first!</span>")
|
||||
return
|
||||
|
||||
@@ -280,8 +310,8 @@
|
||||
|
||||
/obj/item/clothing/head/helmet/update_icon_state()
|
||||
var/state = "[initial(icon_state)]"
|
||||
if(F)
|
||||
if(F.on)
|
||||
if(attached_light)
|
||||
if(attached_light.on)
|
||||
state += "-flight-on" //"helmet-flight-on" // "helmet-cam-flight-on"
|
||||
else
|
||||
state += "-flight" //etc.
|
||||
@@ -289,7 +319,7 @@
|
||||
icon_state = state
|
||||
|
||||
/obj/item/clothing/head/helmet/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/toggle_helmet_flashlight))
|
||||
if(istype(action, alight))
|
||||
toggle_helmlight()
|
||||
else
|
||||
..()
|
||||
@@ -297,60 +327,60 @@
|
||||
/obj/item/clothing/head/helmet/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/flashlight/seclite))
|
||||
var/obj/item/flashlight/seclite/S = I
|
||||
if(can_flashlight)
|
||||
if(!F)
|
||||
if(!user.transferItemToLoc(S, src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You click [S] into place on [src].</span>")
|
||||
if(S.on)
|
||||
set_light(0)
|
||||
F = S
|
||||
update_icon()
|
||||
update_helmlight(user)
|
||||
verbs += /obj/item/clothing/head/helmet/proc/toggle_helmlight
|
||||
var/datum/action/A = new /datum/action/item_action/toggle_helmet_flashlight(src)
|
||||
if(loc == user)
|
||||
A.Grant(user)
|
||||
if(can_flashlight && !attached_light)
|
||||
if(!user.transferItemToLoc(S, src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You click [S] into place on [src].</span>")
|
||||
if(S.on)
|
||||
set_light(0)
|
||||
attached_light = S
|
||||
update_icon()
|
||||
update_helmlight()
|
||||
alight = new(src)
|
||||
if(loc == user)
|
||||
alight.Grant(user)
|
||||
return
|
||||
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(F)
|
||||
for(var/obj/item/flashlight/seclite/S in src)
|
||||
to_chat(user, "<span class='notice'>You unscrew the seclite from [src].</span>")
|
||||
F = null
|
||||
S.forceMove(user.drop_location())
|
||||
update_helmlight(user)
|
||||
S.update_brightness(user)
|
||||
update_icon()
|
||||
usr.update_inv_head()
|
||||
verbs -= /obj/item/clothing/head/helmet/proc/toggle_helmlight
|
||||
for(var/datum/action/item_action/toggle_helmet_flashlight/THL in actions)
|
||||
qdel(THL)
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/helmet/screwdriver_act(mob/living/user, obj/item/I)
|
||||
..()
|
||||
if(can_flashlight && attached_light) //if it has a light but can_flashlight is false, the light is permanently attached.
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, "<span class='notice'>You unscrew [attached_light] from [src].</span>")
|
||||
attached_light.forceMove(drop_location())
|
||||
if(Adjacent(user) && !issilicon(user))
|
||||
user.put_in_hands(attached_light)
|
||||
|
||||
var/obj/item/flashlight/removed_light = attached_light
|
||||
attached_light = null
|
||||
update_helmlight()
|
||||
removed_light.update_brightness(user)
|
||||
update_icon()
|
||||
user.update_inv_head()
|
||||
QDEL_NULL(alight)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/head/helmet/proc/toggle_helmlight()
|
||||
set name = "Toggle Helmetlight"
|
||||
set category = "Object"
|
||||
set desc = "Click to toggle your helmet's attached flashlight."
|
||||
|
||||
if(!F)
|
||||
if(!attached_light)
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
if(user.incapacitated())
|
||||
return
|
||||
F.on = !F.on
|
||||
to_chat(user, "<span class='notice'>You toggle the helmetlight [F.on ? "on":"off"].</span>")
|
||||
attached_light.on = !attached_light.on
|
||||
to_chat(user, "<span class='notice'>You toggle the helmet-light [attached_light.on ? "on":"off"].</span>")
|
||||
|
||||
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
|
||||
update_helmlight(user)
|
||||
|
||||
/obj/item/clothing/head/helmet/proc/update_helmlight(mob/user = null)
|
||||
if(F)
|
||||
if(F.on)
|
||||
set_light(F.brightness_on, F.flashlight_power, F.light_color)
|
||||
if(attached_light)
|
||||
if(attached_light.on)
|
||||
set_light(attached_light.brightness_on, attached_light.flashlight_power, attached_light.light_color)
|
||||
else
|
||||
set_light(0)
|
||||
update_icon()
|
||||
|
||||
@@ -267,9 +267,15 @@
|
||||
desc = "A specialized pair of combat boots with a built-in propulsion system for rapid foward movement."
|
||||
icon_state = "jetboots"
|
||||
resistance_flags = FIRE_PROOF
|
||||
cold_protection = FEET|LEGS
|
||||
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
|
||||
heat_protection = FEET|LEGS
|
||||
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
|
||||
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
|
||||
actions_types = list(/datum/action/item_action/bhop)
|
||||
permeability_coefficient = 0.05
|
||||
unique_reskin = list("Explorer" = "miningjet",
|
||||
"Jackboot" = "jetboots")
|
||||
var/jumpdistance = 5 //-1 from to see the actual distance, e.g 4 goes over 3 tiles
|
||||
var/jumpspeed = 3
|
||||
var/recharging_rate = 60 //default 6 seconds between each dash
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/Initialize()
|
||||
. = ..()
|
||||
soundloop = new(list(), FALSE, TRUE)
|
||||
soundloop = new(src, FALSE, TRUE)
|
||||
soundloop.volume = 5
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/Destroy()
|
||||
. = ..()
|
||||
if(!QDELETED(suit))
|
||||
qdel(suit)
|
||||
suit = null
|
||||
QDEL_NULL(soundloop)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/attack_self(mob/user)
|
||||
@@ -633,7 +637,7 @@
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/clown
|
||||
mutantrace_variation = STYLE_DIGITIGRADE
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, slot)
|
||||
/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, equipper, slot, disable_warning, bypass_equip_delay_self)
|
||||
if(!..() || !ishuman(M))
|
||||
return FALSE
|
||||
if(M.mind && HAS_TRAIT(M.mind, TRAIT_CLOWN_MENTALITY))
|
||||
|
||||
@@ -53,5 +53,5 @@
|
||||
desc = "An ironically skimpy blue dress with gold markings denoting the rank of \"Captain\"."
|
||||
icon_state = "lewdcap"
|
||||
item_state = "lewdcap"
|
||||
can_adjust = FALSE
|
||||
alt_covers_chest = TRUE
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME 10
|
||||
#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME 30
|
||||
|
||||
//this datum is used by the events controller to dictate how it selects events
|
||||
/datum/round_event_control
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/datum/round_event_control/atmos_flux
|
||||
name = "Atmospheric Flux"
|
||||
typepath = /datum/round_event/atmos_flux
|
||||
max_occurrences = 1
|
||||
weight = 5
|
||||
endWhen = 600
|
||||
var/original_speed
|
||||
|
||||
/datum/round_event/atmos_flux
|
||||
announceWhen = 1
|
||||
|
||||
/datum/round_event/atmos_flux/announce(fake)
|
||||
priority_announce("Atmospheric flux in your sector detected. Sensors show that air may move [(SSair.share_max_steps_target > original_speed) ? "faster" : "slower"] than usual for some time.", "Atmos Alert")
|
||||
|
||||
/datum/round_event/atmos_flux/start()
|
||||
original_speed = SSair.share_max_steps_target
|
||||
if(prob(20))
|
||||
SSair.share_max_steps_target = max(1, original_speed - rand(1,original_speed-1))
|
||||
else
|
||||
SSair.share_max_steps_target += rand(2,10)
|
||||
|
||||
/datum/round_event/atmos_flux/end()
|
||||
SSair.share_max_steps_target = original_speed
|
||||
@@ -99,7 +99,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
|
||||
walk(src,0)
|
||||
walk_towards(src, destination, 1)
|
||||
|
||||
/obj/effect/immovablerod/ex_act(severity, target)
|
||||
/obj/effect/immovablerod/ex_act(severity, target, origin)
|
||||
return 0
|
||||
|
||||
/obj/effect/immovablerod/singularity_act()
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
if(master)
|
||||
master.spawn_spacevine_piece(stepturf, src)
|
||||
|
||||
/obj/structure/spacevine/ex_act(severity, target)
|
||||
/obj/structure/spacevine/ex_act(severity, target, origin)
|
||||
if(istype(target, type)) //if its agressive spread vine dont do anything
|
||||
return
|
||||
var/i
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
supernova.power_mod = min(supernova.power_mod*1.2, power)
|
||||
if(activeFor > endWhen-10)
|
||||
supernova.power_mod /= 4
|
||||
if(prob(round(supernova.power_mod)) && prob(3) && storm_count < 5 && !SSweather.get_weather_by_type(/datum/weather/rad_storm))
|
||||
if(prob(round(supernova.power_mod)) && prob(5-storm_count) && !SSweather.get_weather_by_type(/datum/weather/rad_storm))
|
||||
SSweather.run_weather(/datum/weather/rad_storm/supernova)
|
||||
storm_count++
|
||||
|
||||
@@ -73,6 +73,6 @@
|
||||
weather_duration_lower = 50
|
||||
weather_duration_upper = 100
|
||||
telegraph_duration = 200
|
||||
radiation_intensity = 1000
|
||||
radiation_intensity = 500
|
||||
weather_sound = null
|
||||
telegraph_message = "<span class='userdanger'>The air begins to grow very warm!</span>"
|
||||
|
||||
@@ -57,7 +57,11 @@ God bless America.
|
||||
component_parts += new /obj/item/circuitboard/machine/deep_fryer(null)
|
||||
component_parts += new /obj/item/stock_parts/micro_laser(null)
|
||||
RefreshParts()
|
||||
fry_loop = new(list(src), FALSE)
|
||||
fry_loop = new(src, FALSE)
|
||||
|
||||
/obj/machinery/deepfryer/Destroy()
|
||||
QDEL_NULL(fry_loop)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/deepfryer/RefreshParts()
|
||||
var/oil_efficiency
|
||||
|
||||
@@ -13,15 +13,21 @@
|
||||
|
||||
/obj/machinery/grill/Initialize()
|
||||
. = ..()
|
||||
grill_loop = new(list(src), FALSE)
|
||||
grill_loop = new(src, FALSE)
|
||||
|
||||
/obj/machinery/grill/Destroy()
|
||||
QDEL_NULL(grill_loop)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/grill/update_icon_state()
|
||||
if(grilled_item)
|
||||
icon_state = "grill"
|
||||
else if(grill_fuel)
|
||||
return ..()
|
||||
if(grill_fuel > 0)
|
||||
icon_state = "grill_on"
|
||||
else
|
||||
icon_state = "grill_open"
|
||||
return ..()
|
||||
icon_state = "grill_open"
|
||||
return ..()
|
||||
|
||||
/obj/machinery/grill/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/stack/sheet/mineral/coal) || istype(I, /obj/item/stack/sheet/mineral/wood))
|
||||
@@ -60,21 +66,21 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/grill/process()
|
||||
/obj/machinery/grill/process(delta_time)
|
||||
..()
|
||||
update_icon()
|
||||
if(!grill_fuel)
|
||||
update_appearance()
|
||||
if(grill_fuel <= 0)
|
||||
return
|
||||
else
|
||||
grill_fuel -= 1
|
||||
if(prob(1))
|
||||
grill_fuel -= 0.5 * delta_time
|
||||
if(DT_PROB(0.5, delta_time))
|
||||
var/datum/effect_system/smoke_spread/bad/smoke = new
|
||||
smoke.set_up(1, loc)
|
||||
smoke.start()
|
||||
if(grilled_item)
|
||||
grill_time += 1
|
||||
grill_time += delta_time
|
||||
grilled_item.reagents.add_reagent("char", 1)
|
||||
grill_fuel -= 10
|
||||
grill_fuel -= 5 * delta_time
|
||||
grilled_item.AddComponent(/datum/component/sizzle)
|
||||
|
||||
/obj/machinery/grill/Exited(atom/movable/AM)
|
||||
@@ -109,9 +115,9 @@
|
||||
|
||||
/obj/machinery/grill/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(grilled_item)
|
||||
to_chat(user, "<span class='notice'>You take out [grilled_item] from [src].</span>")
|
||||
to_chat(user, span_notice("You take out [grilled_item] from [src]."))
|
||||
grilled_item.forceMove(drop_location())
|
||||
update_icon()
|
||||
update_appearance()
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -36,12 +36,13 @@
|
||||
. = ..()
|
||||
wires = new /datum/wires/microwave(src)
|
||||
create_reagents(100)
|
||||
soundloop = new(list(src), FALSE)
|
||||
soundloop = new(src, FALSE)
|
||||
|
||||
/obj/machinery/microwave/Destroy()
|
||||
eject()
|
||||
if(wires)
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(soundloop)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/microwave/RefreshParts()
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
speech_span = "spooky"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/active = TRUE
|
||||
var/BallTutorial = FALSE
|
||||
|
||||
/obj/item/barthpot/attackby(obj/item/I, mob/user, params)
|
||||
if(BallTutorial)
|
||||
say("Hello and welcome to the annual Citadelstation Spookyball 2021! CENTCOM requisitioned this old hospital as a new colony site two years ago, and we’re back again after a few additions here and there. Next to me you can find all the tools you’ll need to build a nice private house, if you’re here for that kind of thing. The axes will chop trees, and give you wood. Shovels will remove grass and things, which you can use the grass to make beds and backets. The pickaxe will allow you pick out the nearby rocks, if you’re more interested in building a cave dwelling. Finally the umbrella and light sources are because it’s spooky, and it might rain! As for interesting spots; There’s the old abandoned mansion which you can get to by going through the entrance and towards the east. There’s also a mech arena directly south, and a racetrack in the caves to the right of the arena, follow the lanterns. And make sure to explore the caves too! Lots of neat things to find!")
|
||||
return
|
||||
if(!active)
|
||||
say("Meow!")
|
||||
return
|
||||
@@ -27,6 +31,9 @@
|
||||
say("It doesn't seem like that's magical enough!")
|
||||
|
||||
/obj/item/barthpot/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(BallTutorial)
|
||||
say("Hello and welcome to the annual Citadelstation Spookyball 2021! CENTCOM requisitioned this old hospital as a new colony site two years ago, and we’re back again after a few additions here and there. Next to me you can find all the tools you’ll need to build a nice private house, if you’re here for that kind of thing. The axes will chop trees, and give you wood. Shovels will remove grass and things, which you can use the grass to make beds and backets. The pickaxe will allow you pick out the nearby rocks, if you’re more interested in building a cave dwelling. Finally the umbrella and light sources are because it’s spooky, and it might rain! As for interesting spots; There’s the old abandoned mansion which you can get to by going through the entrance and towards the east. There’s also a mech arena directly south, and a racetrack in the caves to the right of the arena, follow the lanterns. And make sure to explore the caves too! Lots of neat things to find!")
|
||||
return
|
||||
if(!active)
|
||||
say("Meow!")
|
||||
return
|
||||
|
||||
@@ -268,3 +268,65 @@
|
||||
category = "Holiday"
|
||||
item = /obj/item/card/emag/halloween
|
||||
surplus = 0
|
||||
|
||||
/////////////////////////
|
||||
// Ball map Items //
|
||||
/////////////////////////
|
||||
|
||||
|
||||
/obj/item/wisp_lantern/pumpkin
|
||||
name = "Pumpkin lantern"
|
||||
desc = "This lantern gives off no light, but is home to a friendly Jacq o' latern."
|
||||
icon_state = "lantern-on"
|
||||
var/obj/effect/wisp/pumpkin/wisp2
|
||||
|
||||
//Hoooo boy that's some wild code there.
|
||||
/obj/item/wisp_lantern/pumpkin/Initialize()
|
||||
. = ..()
|
||||
qdel(wisp)
|
||||
wisp2 = new(src)
|
||||
wisp = wisp2
|
||||
|
||||
/obj/effect/wisp/pumpkin
|
||||
name = "Friendly pumpkin"
|
||||
desc = "Happy to spook your way."
|
||||
icon = 'icons/obj/clothing/hats.dmi'
|
||||
icon_state = "hardhat1_pumpkin_j"
|
||||
light_range = 5
|
||||
light_color = "#EE9933"
|
||||
layer = 0
|
||||
sight_flags = SEE_MOBS
|
||||
lighting_alpha = 0
|
||||
|
||||
/obj/effect/wisp/pumpkin/update_user_sight(mob/user) //Disables SUPERLIGHTS
|
||||
return
|
||||
|
||||
//Damnit LazyBones
|
||||
/mob/living/simple_animal/lazy_bones
|
||||
name = "Lazy Bones"
|
||||
desc = "Simply refuses to get out of bed!"
|
||||
icon = 'icons/mob/simple_human.dmi'
|
||||
icon_state = "skeleton"
|
||||
icon_living = "skeleton"
|
||||
icon_dead = "skeleton"
|
||||
gender = NEUTER
|
||||
mob_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
|
||||
turns_per_move = 5
|
||||
speak_emote = list("rattles")
|
||||
emote_see = list("rattles")
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
speed = 0
|
||||
harm_intent_damage = 0
|
||||
melee_damage_lower = 0
|
||||
melee_damage_upper = 0
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 1500
|
||||
faction = list("skeleton")
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
deathmessage = "collapses into a pile of bones!"
|
||||
del_on_death = 1
|
||||
loot = list(/obj/effect/decal/remains/human)
|
||||
|
||||
stop_automated_movement = 1
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
var/cached_z
|
||||
/// I'm busy, don't move.
|
||||
var/busy = FALSE
|
||||
var/spawn_cars = FALSE
|
||||
|
||||
var/static/blacklisted_items = typecacheof(list(
|
||||
/obj/effect,
|
||||
@@ -91,6 +92,9 @@
|
||||
poof()
|
||||
|
||||
/mob/living/simple_animal/jacq/on_attack_hand(mob/living/carbon/human/M)
|
||||
if(spawn_cars)
|
||||
spawn_cars(M)
|
||||
return ..()
|
||||
if(!active)
|
||||
say("Hello there [gender_check(M)]!")
|
||||
return ..()
|
||||
@@ -101,6 +105,9 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/jacq/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(spawn_cars)
|
||||
spawn_cars(M)
|
||||
return ..()
|
||||
if(!active)
|
||||
say("Hello there [gender_check(M)]!")
|
||||
return ..()
|
||||
@@ -128,6 +135,8 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/jacq/proc/poof()
|
||||
if(!active)//if disabled, don't poof
|
||||
return
|
||||
last_poof = world.realtime
|
||||
var/datum/reagents/R = new/datum/reagents(100)//Hey, just in case.
|
||||
var/datum/effect_system/smoke_spread/chem/s = new()
|
||||
@@ -145,7 +154,7 @@
|
||||
pop_areas += A
|
||||
|
||||
var/list/targets = list()
|
||||
for(var/H in GLOB.network_holopads)
|
||||
for(var/H in GLOB.the_station_areas)
|
||||
var/area/A = get_area(H)
|
||||
if(!A || findtextEx(A.name, "AI") || !(A in pop_areas) || !is_station_level(H))
|
||||
continue
|
||||
@@ -470,6 +479,30 @@
|
||||
sleep(20)
|
||||
poof()
|
||||
|
||||
/mob/living/simple_animal/jacq/proc/spawn_cars(mob/living/carbon/C)
|
||||
visible_message("<b>[src]</b> gives off a glowing smile, <span class='spooky'>\"What ken Ah offer ye? I can magic up a vectorcraft in manual or automatic fer ye.\"</span>")
|
||||
var/choices_reward = list("Manual", "Automatic", "How do Automatics work?", "Nothing, thanks")
|
||||
var/choice_reward = input(usr, "Trick or Treat?", "Trick or Treat?") in choices_reward
|
||||
|
||||
switch(choice_reward)
|
||||
if("Manual")
|
||||
visible_message("<b>[src]</b> waves their arms around, <span class='spooky'>\"Great choice! 'Ere's yer car.\"</span>")
|
||||
jacqrunes("Great choice! 'Ere's yer car.", C)
|
||||
new /obj/vehicle/sealed/vectorcraft(loc)
|
||||
if("Automatic")
|
||||
visible_message("<b>[src]</b> waves their arms around, <span class='spooky'>\"'Ere's yer car. Not as fast as an automatic mind.\"</span>")
|
||||
jacqrunes("'Ere's yer car. Not as fast as an automatic mind.", C)
|
||||
new /obj/vehicle/sealed/vectorcraft/auto(loc)
|
||||
if("How do Automatics work?")
|
||||
visible_message("<b>[src]</b> smiles, <span class='spooky'>\"Hold wasd to gain speed in a direction, c to enable/disable the clutch, 1 2 3 4 to change gears (help is gear 1, disarm is gear 2, grab is gear 3 and harm is gear 4) while holding a direction (make sure the clutch is enabled when you change gears, you should hear a sound when you've successfully changed gears), r to toggle handbrake, hold alt for brake and press shift for boost (the machine will beep when the boost is recharged)! If you hear an ebbing sound like \"brbrbrbrbr\" you need to gear down, the whining sound means you need to gear up. Hearing a pleasant \"whumwhumwhum\" is optimal gearage! It can be a lil slow to start, so make sure you're in the 1st gear, andusing a boost to get you started is a good idea. If you've got a good speed you'll likely never need to dip down to gear 1 again, and make sure to hold the acceleration pedal down while changing gears (hold a direction). 1st gear is for slow movement, and it's a good idea to mvoe to 2nd gear as quick as you can, you can coldstart a car from gear one by slowly moving, then using the boost to jump you up to gear 2 speeds. The upper gears are for unlimiting your top speed.\"</span>")
|
||||
jacqrunes("They're a bit tricky, aye. Basically;", C)
|
||||
if("Nothing, thanks")
|
||||
visible_message("<b>[src]</b> shrugs, <span class='spooky'>\"Suit yerself.\"</span>")
|
||||
jacqrunes("Suit yerself.", C)
|
||||
|
||||
visible_message("<b>[src]</b> shrugs, <span class='spooky'>\"Oh and look after the crafts, aye? They can get a wee bit... explosive if banged up a tad too much. They move slower damaged too like. Ye can repair 'em with the welders o'er there.\"</span>")
|
||||
jacqrunes("Oh and look after the crafts, aye? They can get a wee bit... explosive if banged up a tad too much. They move slower damaged too like. Ye can repair 'em with the welders o'er there. ", C)
|
||||
|
||||
/mob/living/simple_animal/jacq/update_mobility()
|
||||
. = ..()
|
||||
if(busy)
|
||||
@@ -478,7 +511,150 @@
|
||||
. |= MOBILITY_MOVE
|
||||
mobility_flags = .
|
||||
|
||||
//Christmas car spawner
|
||||
|
||||
/mob/living/simple_animal/jacq/car_spawner
|
||||
name = "Jacqueline cars terminal"
|
||||
icon_state = "jacq_cars_spawner"
|
||||
AIStatus = AI_OFF
|
||||
spawn_cars = TRUE
|
||||
active = FALSE
|
||||
|
||||
/mob/living/simple_animal/jacq/car_spawner/Destroy()
|
||||
visible_message("The <b>[src]</b> gives out an error sound, <span class='spooky'>\"Ey! Bugger off!\"</span>")
|
||||
fully_heal(FALSE)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/jacq/car_spawner/death()
|
||||
visible_message("The <b>[src]</b> gives out an error sound, <span class='spooky'>\"Ey! Bugger off!\"</span>")
|
||||
fully_heal(FALSE)
|
||||
|
||||
/mob/living/simple_animal/jacq/car_spawner/poof()
|
||||
if(!active)//if disabled, don't poof
|
||||
return
|
||||
var/datum/reagents/R = new/datum/reagents(100)//Hey, just in case.
|
||||
var/datum/effect_system/smoke_spread/chem/s = new()
|
||||
R.add_reagent(/datum/reagent/fermi/secretcatchem, 10)
|
||||
s.set_up(R, 0, loc)
|
||||
s.start()
|
||||
stopmove()
|
||||
health = 25
|
||||
|
||||
/mob/living/simple_animal/jacq/car_spawner/spawn_cars(mob/living/carbon/C)
|
||||
visible_message("<b>[src]</b> boots up and displays jacq's glowing smile, <span class='spooky'>\"Hallo there user! Merry Christmas! What ken type o' craft ken Ah offer ye? I can magic up a vectorcraft in manual, automatic or customise it if yer feeling technical.\"</span>")
|
||||
jacqrunes("Hallo there user! What ken type o' craft ken Ah offer ye? I can magic up a vectorcraft in manual, automatic or customise it if yer feeling technical.", C)
|
||||
|
||||
var/choices_reward = list("Manual", "Automatic", "Customise", "Are you a computer now Jacq?", "Nothing, thanks")
|
||||
var/choice_reward = input(usr, "Merry Trick_or_Treat.exe initiated!", "Merry Trick_or_Treat.exe initiated!") in choices_reward
|
||||
|
||||
switch(choice_reward)
|
||||
if("Manual")
|
||||
visible_message("The <b>[src]</b> makes a magical booping sound, <span class='spooky'>\"Great choice! 'Ere's yer car.\"</span>")
|
||||
jacqrunes("Great choice! 'Ere's yer car.", C)
|
||||
new /obj/vehicle/sealed/vectorcraft(loc)
|
||||
if("Automatic")
|
||||
visible_message("<b>[src]</b> makes a magical booping sound, <span class='spooky'>\"'Ere's yer car. Not as fast as an automatic mind.\"</span>")
|
||||
jacqrunes("'Ere's yer car. Not as fast as an automatic mind.", C)
|
||||
new /obj/vehicle/sealed/vectorcraft/auto(loc)
|
||||
if("Are you a computer now Jacq?")
|
||||
visible_message("<b>[src]</b> makes a frustrated error sound, <span class='spooky'>\"Nae, are ye daft? Ah built these thingies tae magic up cars fer ye. Well, I got a speccy four eyes tae do it fer me, but me names on it like cause it was me idea.\"</span>")
|
||||
jacqrunes("Nae, are ye daft? Ah built these thingies tae magic up cars fer ye. Well, I got a speccy four eyes tae do it fer me, but me names on it like cause it was me idea.", C)
|
||||
if("Customise")
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Arright, Manual or Automatic?\"</span>")
|
||||
var/choices_transm = list("Manual", "Automatic")
|
||||
var/choice_transm = input(usr, "Choose transmission", "Choose transmission") in choices_transm
|
||||
var/points = 0
|
||||
var/obj/vehicle/sealed/vectorcraft/VC
|
||||
switch(choice_transm)
|
||||
if("Manual")
|
||||
VC = new /obj/vehicle/sealed/vectorcraft(loc)
|
||||
if("Automatic")
|
||||
VC = new /obj/vehicle/sealed/vectorcraft/auto(loc)
|
||||
points += 500
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Maximum acceleration? (default [VC.max_acceleration], max 10)\"</span>")
|
||||
var/max_accl = text2num(input(usr, "Maximum acceleration? (default [VC.max_acceleration], max 10)", "[VC.max_acceleration]"))
|
||||
max_accl = clamp(max_accl, 0, 10)
|
||||
VC.max_acceleration = max_accl
|
||||
VC.i_m_acell = max_accl
|
||||
points += max_accl*10
|
||||
|
||||
/* This is internally used
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Acceleration step? (default 0.3, max 1)\"</span>")
|
||||
var/max_accl_s = text2num(input(usr, "Acceleration step? (default 0.3, max 1)", "[VC.accel_step]"))
|
||||
max_accl_s = clamp(max_accl_s, 0, 1)
|
||||
VC.max_acceleration = max_accl_s
|
||||
points += max_accl_s*100
|
||||
*/
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Acceleration? (default [VC.acceleration], max 2)\"</span>")
|
||||
var/accl = text2num(input(usr, "Acceleration? (default [VC.acceleration], max 2)", "[VC.acceleration]"))
|
||||
accl = clamp(accl, 0, 2)
|
||||
VC.acceleration = accl
|
||||
VC.i_acell = accl
|
||||
points += accl*100
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Maximum deceleration? (default [VC.max_deceleration], max 15)\"</span>")
|
||||
var/deaccl = text2num(input(usr, "Max_deceleration? (default [VC.max_deceleration], max 15)", "[VC.max_deceleration]"))
|
||||
deaccl = clamp(deaccl, 0, 15)
|
||||
VC.max_deceleration = deaccl
|
||||
VC.i_m_decell = deaccl
|
||||
points += deaccl*10
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Maximum velocity? (default [VC.max_velocity], max 200)\"</span>")
|
||||
var/m_velo = text2num(input(usr, "Maximum velocity? (default [VC.max_velocity], max 200)", "[VC.max_velocity]"))
|
||||
m_velo = clamp(m_velo, 0, 200)
|
||||
VC.max_velocity = m_velo
|
||||
points += m_velo
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Boost power? (default [VC.boost_power], max 200)\"</span>")
|
||||
var/boost = text2num(input(usr, "Boost power? (default [VC.boost_power], max 200)", "[VC.boost_power]"))
|
||||
boost = clamp(boost, 0, 200)
|
||||
VC.boost_power = boost
|
||||
VC.i_boost = boost
|
||||
points += boost
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Health points? (default [VC.max_integrity], max 1000)\"</span>")
|
||||
var/health = text2num(input(usr, "Health points? (default [VC.max_integrity], max 1000)", "[VC.max_integrity]"))
|
||||
health = clamp(health, 0, 500)
|
||||
VC.max_integrity = health
|
||||
points += health/2
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Arright, 'ow do ye want it tae look?\"</span>")
|
||||
var/choices_icon = list("Racer", "Truck", "Cyber", "Ambulance", "Pod", "Clown")
|
||||
var/choice_icon = input(usr, "Choose body", "Choose body") in choices_icon
|
||||
switch(choice_icon)
|
||||
if("Truck")
|
||||
VC.icon_state = "truck"
|
||||
|
||||
if("Cyber")
|
||||
VC.icon_state = "cyber"
|
||||
|
||||
if("Ambulance")
|
||||
VC.icon_state = "ambutruck"
|
||||
|
||||
if("Pod")
|
||||
VC.icon_state = "engineering_pod"
|
||||
|
||||
if("Clown")
|
||||
VC.icon_state = "clowncar"
|
||||
|
||||
visible_message("The <b>[src]</b> pings, <span class='spooky'>\"Finally; what name are ye gonna give it?\"</span>")
|
||||
var/choice_name = input(usr, "Pick a name!", "")
|
||||
choice_name += " (Points cost:[points])"
|
||||
VC.name = choice_name
|
||||
|
||||
visible_message("The <b>[src]</b> gives a final boop, <span class='spooky'>\"There ye be, enjoy!\"</span>")
|
||||
|
||||
if("How do Automatics work?")
|
||||
visible_message("The image of Jacq on the <b>[src]</b> smiles, <span class='spooky'>\"Hold wasd to gain speed in a direction, c to enable/disable the clutch, 1 2 3 4 to change gears (help is gear 1, disarm is gear 2, grab is gear 3 and harm is gear 4) while holding a direction (make sure the clutch is enabled when you change gears, you should hear a sound when you've successfully changed gears), r to toggle handbrake, hold alt for brake and press shift for boost (the machine will beep when the boost is recharged)! If you hear an ebbing sound like \"brbrbrbrbr\" you need to gear down, the whining sound means you need to gear up. Hearing a pleasant \"whumwhumwhum\" is optimal gearage! It can be a lil slow to start, so make sure you're in the 1st gear, andusing a boost to get you started is a good idea. If you've got a good speed you'll likely never need to dip down to gear 1 again, and make sure to hold the acceleration pedal down while changing gears (hold a direction). 1st gear is for slow movement, and it's a good idea to mvoe to 2nd gear as quick as you can, you can coldstart a car from gear one by slowly moving, then using the boost to jump you up to gear 2 speeds. The upper gears are for unlimiting your top speed.\"</span>")
|
||||
jacqrunes("They're a bit tricky, aye. Basically;", C)
|
||||
if("Nothing, thanks")
|
||||
visible_message("The image of Jacq on the <b>[src]</b> shrugs, <span class='spooky'>\"Suit yerself.\"</span>")
|
||||
jacqrunes("Suit yerself.", C)
|
||||
|
||||
visible_message("The <b>[src]</b> beeps, <span class='spooky'>\"Oh and look after the crafts, aye? They can get a wee bit... explosive if banged up a tad too much. They move slower damaged too like. Ye can repair 'em with the welders o'er there.\"</span>")
|
||||
jacqrunes("Oh and look after the crafts, aye? They can get a wee bit... explosive if banged up a tad too much. They move slower damaged too like. Ye can repair 'em with the welders o'er there. ", C)
|
||||
|
||||
/obj/item/clothing/head/hardhat/pumpkinhead/jaqc
|
||||
name = "Jacq o' latern"
|
||||
@@ -555,9 +731,13 @@
|
||||
|
||||
/obj/item/reagent_containers/potion_container/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
..()
|
||||
delayed_release_smoke()
|
||||
|
||||
/obj/item/reagent_containers/potion_container/proc/delayed_release_smoke()
|
||||
set waitfor = FALSE
|
||||
sleep(20)
|
||||
var/datum/effect_system/smoke_spread/chem/s = new()
|
||||
s.set_up(src.reagents, 3, src.loc)
|
||||
s.set_up(src.reagents, 3, get_turf(src))
|
||||
s.start()
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
return
|
||||
emergency_shutdown()
|
||||
|
||||
/obj/machinery/computer/holodeck/ex_act(severity, target)
|
||||
/obj/machinery/computer/holodeck/ex_act(severity, target, origin)
|
||||
emergency_shutdown()
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/biogenerator/contents_explosion(severity, target)
|
||||
/obj/machinery/biogenerator/contents_explosion(severity, target, origin)
|
||||
..()
|
||||
if(beaker)
|
||||
beaker.ex_act(severity, target)
|
||||
beaker.ex_act(severity, target, origin)
|
||||
|
||||
/obj/machinery/biogenerator/handle_atom_del(atom/A)
|
||||
..()
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
var/mob/M = loc
|
||||
M.dropItemToGround(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/ex_act(severity)
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/ex_act(severity, target, origin)
|
||||
qdel(src) //Ensuring that it's deleted by its own explosion
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime(mob/living/lanced_by)
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/ex_act(severity)
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/ex_act(severity, target, origin)
|
||||
qdel(src) //Ensuring that it's deleted by its own explosion. Also prevents mass chain reaction with piles of cherry bombs
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime(mob/living/lanced_by)
|
||||
@@ -500,7 +500,7 @@
|
||||
log_game("Coconut bomb detonation at [AREACOORD(T)], location [loc]")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/coconut/ex_act(severity)
|
||||
/obj/item/reagent_containers/food/snacks/grown/coconut/ex_act(severity, target, origin)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/coconut/deconstruct(disassembled = TRUE)
|
||||
|
||||
@@ -53,31 +53,21 @@
|
||||
|
||||
/obj/item/seeds/replicapod/on_reagent_change(changetype)
|
||||
if(changetype == ADD_REAGENT)
|
||||
var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood)
|
||||
if(B)
|
||||
if(B.data["mind"] && B.data["cloneable"])
|
||||
mind = B.data["mind"]
|
||||
ckey = B.data["ckey"]
|
||||
realName = B.data["real_name"]
|
||||
blood_gender = B.data["gender"]
|
||||
blood_type = B.data["blood_type"]
|
||||
features = B.data["features"]
|
||||
factions = B.data["factions"]
|
||||
quirks = B.data["quirks"]
|
||||
contains_sample = TRUE
|
||||
visible_message("<span class='notice'>The [src] is injected with a fresh blood sample.</span>")
|
||||
else
|
||||
visible_message("<span class='warning'>The [src] rejects the sample!</span>")
|
||||
|
||||
if(!reagents.has_reagent(/datum/reagent/blood))
|
||||
mind = null
|
||||
ckey = null
|
||||
realName = null
|
||||
blood_gender = null
|
||||
blood_type = null
|
||||
features = null
|
||||
factions = null
|
||||
contains_sample = FALSE
|
||||
for(var/datum/reagent/R as anything in reagents.reagent_list)
|
||||
if(R.data["mind"])
|
||||
if(R.data["cloneable"])
|
||||
mind = R.data["mind"]
|
||||
ckey = R.data["ckey"]
|
||||
realName = R.data["real_name"]
|
||||
blood_gender = R.data["gender"]
|
||||
blood_type = R.data["blood_type"]
|
||||
features = R.data["features"]
|
||||
factions = R.data["factions"]
|
||||
quirks = R.data["quirks"]
|
||||
contains_sample = TRUE
|
||||
visible_message("<span class='notice'>The [src] is injected with a fresh blood sample.</span>")
|
||||
else
|
||||
visible_message("<span class='warning'>The [src] rejects the sample!</span>")
|
||||
|
||||
/obj/item/seeds/replicapod/get_analyzer_text()
|
||||
var/text = ..()
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"light blue" = COLOR_ASSEMBLY_LBLUE,
|
||||
"blue" = COLOR_ASSEMBLY_BLUE,
|
||||
"purple" = COLOR_ASSEMBLY_PURPLE,
|
||||
"pink" = COLOR_ASSEMBLY_PINK,
|
||||
"pink" = LIGHT_COLOR_PINK,
|
||||
"custom" = COLOR_ASSEMBLY_WHITE
|
||||
)
|
||||
|
||||
|
||||
@@ -36,3 +36,25 @@
|
||||
/datum/keybinding/living/toggle_resting/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.lay_down()
|
||||
|
||||
/datum/keybinding/living/cancel_action
|
||||
hotkey_keys = list("Unbound")
|
||||
name = "cancel_action"
|
||||
full_name = "Cancel Action"
|
||||
description = "Cancel the current action."
|
||||
|
||||
/// Technically you shouldn't be doing any actions if you were sleeping either but...
|
||||
/datum/keybinding/living/can_use(client/user)
|
||||
. = ..()
|
||||
var/mob/living/mob = user.mob
|
||||
return . && (mob.stat == CONSCIOUS)
|
||||
|
||||
/datum/keybinding/living/cancel_action/down(client/user)
|
||||
var/mob/M = user.mob
|
||||
if(length(M.do_afters))
|
||||
var/atom/target = M.do_afters[M.do_afters.len]
|
||||
to_chat(M, "<span class='notice'>You stop interacting with \the [target].</span>")
|
||||
LAZYREMOVE(M.do_afters, target)
|
||||
else
|
||||
to_chat(M, "<span class='notice'>There's nothing that you can cancel right now.</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
speech_verb = "chitter"
|
||||
ask_verb = "chitter"
|
||||
exclaim_verb = "chitter"
|
||||
key = "r"
|
||||
key = "c"
|
||||
flags = NO_STUTTER | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
|
||||
|
||||
icon_state = "arachnid"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
ask_verb = "queries"
|
||||
exclaim_verb = "declares"
|
||||
whisper_verb = "hushes"
|
||||
key = "k"
|
||||
key = "j"
|
||||
space_chance = 40
|
||||
default_priority = 94
|
||||
flags = TONGUELESS_SPEECH
|
||||
|
||||
@@ -193,6 +193,13 @@
|
||||
new /obj/item/book/manual/wiki/research_and_development(src)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/bookcase/manuals/medical
|
||||
name = "medical manuals bookcase"
|
||||
|
||||
/obj/structure/bookcase/manuals/medical/Initialize()
|
||||
. = ..()
|
||||
new /obj/item/book/manual/wiki/medical_cloning(src)
|
||||
update_icon()
|
||||
|
||||
/*
|
||||
* Book
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
color = GLOB.em_block_color
|
||||
|
||||
|
||||
/atom/movable/emissive_blocker/ex_act(severity)
|
||||
/atom/movable/emissive_blocker/ex_act(severity, target, origin)
|
||||
return FALSE
|
||||
|
||||
/atom/movable/emissive_blocker/singularity_act()
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
// Variety of overrides so the overlays don't get affected by weird things.
|
||||
|
||||
/atom/movable/lighting_object/ex_act(severity)
|
||||
/atom/movable/lighting_object/ex_act(severity, target, origin)
|
||||
return 0
|
||||
|
||||
/atom/movable/lighting_object/singularity_act()
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
//Map exporter
|
||||
//Inputting a list of turfs into convert_map_to_tgm() will output a string
|
||||
//with the turfs and their objects / areas on said turf into the TGM mapping format
|
||||
//for .dmm files. This file can then be opened in the map editor or imported
|
||||
//back into the game.
|
||||
//============================
|
||||
//This has been made semi-modular so you should be able to use these functions
|
||||
//elsewhere in code if you ever need to get a file in the .dmm format
|
||||
/atom/proc/get_save_vars()
|
||||
return
|
||||
|
||||
GLOBAL_LIST_INIT(save_file_chars, list(
|
||||
"a","b","c","d","e",
|
||||
"f","g","h","i","j",
|
||||
"k","l","m","n","o",
|
||||
"p","q","r","s","t",
|
||||
"u","v","w","x","y",
|
||||
"z","A","B","C","D",
|
||||
"E","F","G","H","I",
|
||||
"J","K","L","M","N",
|
||||
"O","P","Q","R","S",
|
||||
"T","U","V","W","X",
|
||||
"Y","Z"
|
||||
))
|
||||
|
||||
//Converts a list of turfs into TGM file format
|
||||
/proc/convert_map_to_tgm(list/map,\
|
||||
save_flag = SAVE_ALL, \
|
||||
shuttle_area_flag = SAVE_SHUTTLEAREA_DONTCARE, \
|
||||
list/vars_to_save = list("pixel_x", "pixel_y", "dir", "name", "req_access", "req_access_txt", "piping_layer", "color", "icon_state", "pipe_color", "amount"),\
|
||||
list/obj_blacklist = list())
|
||||
//Calculate the bounds
|
||||
var/minx = 1024
|
||||
var/miny = 1024
|
||||
var/maxx = -1
|
||||
var/maxy = -1
|
||||
for(var/turf/place in map)
|
||||
minx = min(place.x, minx)
|
||||
miny = min(place.y, miny)
|
||||
maxx = max(place.x, maxx)
|
||||
maxy = max(place.y, maxy)
|
||||
var/width = maxx - minx + 1
|
||||
var/height = maxy - miny + 1
|
||||
|
||||
//Sort the map so weird shaped / bad inputted maps can be handled
|
||||
var/list/sortedmap = sort_map(map, minx, miny, maxx, maxy)
|
||||
|
||||
//Step 0: Calculate the amount of letters we need (26 ^ n > turf count)
|
||||
var/turfsNeeded = width * height
|
||||
var/layers = FLOOR(log(GLOB.save_file_chars.len, turfsNeeded) + 0.999,1)
|
||||
|
||||
//Step 1: Run through the area and generate file data
|
||||
var/list/header_chars = list() //The characters of the header
|
||||
var/list/header_dat = list() //The data of the header, lines up with chars
|
||||
var/header = "" //The actual header in text
|
||||
var/contents = "" //The contents in text (bit at the end)
|
||||
var/index = 1
|
||||
for(var/x in 1 to width)
|
||||
contents += "\n([x],1,1) = {\"\n"
|
||||
for(var/y in height to 1 step -1)
|
||||
//====Get turfs Data====
|
||||
var/turf/place = sortedmap[x][y]
|
||||
var/area/location
|
||||
var/list/objects
|
||||
//If there is nothing there, save as a noop (For odd shapes)
|
||||
if(!place)
|
||||
place = /turf/template_noop
|
||||
location = /area/template_noop
|
||||
objects = list()
|
||||
//Ignore things in space, must be a space turf and the area has to be empty space
|
||||
else if(istype(place, /turf/open/space) && istype(get_area(place), /area/space) && !(save_flag & SAVE_SPACE))
|
||||
place = /turf/template_noop
|
||||
location = /area/template_noop
|
||||
//Stuff to add
|
||||
else
|
||||
var/area/location_type = get_area(place)
|
||||
location = location_type.type
|
||||
objects = place
|
||||
place = place.type
|
||||
//====Saving shuttles only / non shuttles only====
|
||||
var/is_shuttle_area = istype(location, /area/shuttle)
|
||||
if((is_shuttle_area && shuttle_area_flag == SAVE_SHUTTLEAREA_IGNORE) || (!is_shuttle_area && shuttle_area_flag == SAVE_SHUTTLEAREA_ONLY))
|
||||
place = /turf/template_noop
|
||||
location = /area/template_noop
|
||||
objects = list()
|
||||
//====For toggling not saving areas and turfs====
|
||||
if(!(save_flag & SAVE_AREAS))
|
||||
location = /area/template_noop
|
||||
if(!(save_flag & SAVE_TURFS))
|
||||
place = /turf/template_noop
|
||||
//====Generate Header Character====
|
||||
var/header_char = calculate_tgm_header_index(index, layers) //The characters of the header
|
||||
var/current_header = "(\n" //The actual stuff inside the header
|
||||
//Add objects to the header file
|
||||
var/empty = TRUE
|
||||
//====SAVING OBJECTS====
|
||||
if(save_flag & SAVE_OBJECTS)
|
||||
for(var/obj/thing in objects)
|
||||
if(thing.type in obj_blacklist)
|
||||
continue
|
||||
var/metadata = generate_tgm_metadata(thing, vars_to_save)
|
||||
current_header += "[empty?"":",\n"][thing.type][metadata]"
|
||||
empty = FALSE
|
||||
//====SAVING SPECIAL DATA====
|
||||
//This is what causes lockers and machines to save stuff inside of them
|
||||
if(save_flag & SAVE_OBJECT_PROPERTIES)
|
||||
var/custom_data = thing.on_object_saved()
|
||||
current_header += "[custom_data ? ",\n[custom_data]" : ""]"
|
||||
//====SAVING MOBS====
|
||||
if(save_flag & SAVE_MOBS)
|
||||
for(var/mob/living/thing in objects)
|
||||
if(istype(thing, /mob/living/carbon)) //Ignore people, but not animals
|
||||
continue
|
||||
var/metadata = generate_tgm_metadata(thing, vars_to_save)
|
||||
current_header += "[empty?"":",\n"][thing.type][metadata]"
|
||||
empty = FALSE
|
||||
current_header += "[empty?"":",\n"][place],\n[location])\n"
|
||||
//====Fill the contents file====
|
||||
//Compression is done here
|
||||
var/position_of_header = header_dat.Find(current_header)
|
||||
if(position_of_header)
|
||||
//If the header has already been saved, change the character to the other saved header
|
||||
header_char = header_chars[position_of_header]
|
||||
else
|
||||
header += "\"[header_char]\" = [current_header]"
|
||||
header_chars += header_char
|
||||
header_dat += current_header
|
||||
index ++
|
||||
contents += "[header_char]\n"
|
||||
contents += "\"}"
|
||||
return "[header][contents]"
|
||||
|
||||
//Sorts maps in terms of their positions, so scrambled / odd shaped maps can be saved
|
||||
/proc/sort_map(list/map, minx, miny, maxx, maxy)
|
||||
var/width = maxx - minx + 1
|
||||
var/height = maxy - miny + 1
|
||||
var/allTurfs = new/list(width, height)
|
||||
for(var/turf/place in map)
|
||||
allTurfs[place.x - minx + 1][place.y - miny + 1] = place
|
||||
return allTurfs
|
||||
|
||||
//vars_to_save = list() to save all vars
|
||||
/proc/generate_tgm_metadata(atom/O, list/vars_to_save = list("pixel_x", "pixel_y", "dir", "name", "req_access", "req_access_txt", "piping_layer", "color", "icon_state", "pipe_color", "amount"))
|
||||
var/dat = ""
|
||||
var/data_to_add = list()
|
||||
for(var/V in O.vars)
|
||||
if(O.get_save_vars())
|
||||
if(!(V in O.get_save_vars()))
|
||||
continue
|
||||
else
|
||||
if(!(V in vars_to_save) && vars_to_save)
|
||||
continue
|
||||
var/value = O.vars[V]
|
||||
if(!value)
|
||||
continue
|
||||
if(value == initial(O.vars[V]) || !issaved(O.vars[V]))
|
||||
continue
|
||||
var/symbol = ""
|
||||
if(istext(value))
|
||||
symbol = "\""
|
||||
value = sanitize_simple(value, list("{"="", "}"="", "\""="", ";"="", ","=""))
|
||||
else if(isicon(value) || isfile(value))
|
||||
symbol = "'"
|
||||
else if(!(isnum(value) || ispath(value)))
|
||||
continue
|
||||
//Prevent symbols from being because otherwise you can name something [";},/obj/item/gun/energy/laser/instakill{name="da epic gun] and spawn yourself an instakill gun.
|
||||
data_to_add += "[V] = [symbol][value][symbol]"
|
||||
//Process data to add
|
||||
var/first = TRUE
|
||||
for(var/data in data_to_add)
|
||||
dat += "[first ? "" : ";\n"]\t[data]"
|
||||
first = FALSE
|
||||
if(dat)
|
||||
dat = "{\n[dat]\n\t}"
|
||||
return dat
|
||||
|
||||
/proc/calculate_tgm_header_index(index, layers)
|
||||
var/output = ""
|
||||
for(var/i in 1 to layers)
|
||||
var/l = GLOB.save_file_chars.len
|
||||
var/c = FLOOR((index-1) / (l ** (i - 1)), 1)
|
||||
c = (c % l) + 1
|
||||
output = "[GLOB.save_file_chars[c]][output]"
|
||||
return output
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user