Merge pull request #15317 from LetterN/what-should-i-name-this-branch
TGUI hardsync & stuff
This commit is contained in:
@@ -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!
|
||||
|
||||
@@ -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,33 +1,70 @@
|
||||
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
|
||||
|
||||
/// If set to true, the antag will not be added to the living antag list.
|
||||
var/soft_antag = FALSE
|
||||
/// The battlecry this antagonist shouts when suiciding with C4/X4.
|
||||
var/suicide_cry = ""
|
||||
//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 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
|
||||
|
||||
/datum/antagonist/New()
|
||||
GLOB.antagonists += src
|
||||
@@ -35,7 +72,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 ..()
|
||||
@@ -55,14 +94,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.stat != DEAD && !LAZYLEN(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
|
||||
@@ -73,46 +112,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.
|
||||
info_button = new(owner.current, src)
|
||||
info_button.Grant(owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
if(ui_name)
|
||||
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)
|
||||
@@ -120,61 +189,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(!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))
|
||||
@@ -185,16 +288,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)
|
||||
|
||||
@@ -213,11 +322,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
|
||||
|
||||
@@ -226,22 +343,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 ""
|
||||
|
||||
@@ -253,7 +372,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()
|
||||
|
||||
@@ -283,14 +402,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)
|
||||
@@ -300,6 +424,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")
|
||||
@@ -308,3 +439,48 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
else
|
||||
return
|
||||
..()
|
||||
|
||||
///ANTAGONIST UI STUFF
|
||||
|
||||
/datum/antagonist/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_name, name)
|
||||
ui.open()
|
||||
|
||||
/datum/antagonist/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
///generic helper to send objectives as data through tgui. supports smart objectives too!
|
||||
/datum/antagonist/proc/get_objectives()
|
||||
var/objective_count = 1
|
||||
var/list/objective_data = list()
|
||||
//all obj
|
||||
for(var/datum/objective/objective in objectives)
|
||||
objective_data += list(list(
|
||||
"count" = objective_count,
|
||||
"name" = objective.name,
|
||||
"explanation" = objective.explanation_text,
|
||||
"complete" = objective.completed,
|
||||
))
|
||||
objective_count++
|
||||
return objective_data
|
||||
|
||||
//button for antags to review their descriptions/info
|
||||
|
||||
/datum/action/antag_info
|
||||
name = "Open Antag Information:"
|
||||
button_icon_state = "round_end"
|
||||
var/datum/antagonist/antag_datum
|
||||
|
||||
/datum/action/antag_info/New(Target, datum/antagonist/antag_datum)
|
||||
. = ..()
|
||||
src.antag_datum = antag_datum
|
||||
name += " [antag_datum.name]"
|
||||
|
||||
/datum/action/antag_info/Trigger()
|
||||
if(antag_datum)
|
||||
antag_datum.ui_interact(owner)
|
||||
|
||||
/datum/action/antag_info/IsAvailable()
|
||||
return TRUE
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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
|
||||
@@ -149,11 +149,10 @@
|
||||
)
|
||||
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 +222,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 +409,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 +446,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,25 +552,33 @@
|
||||
// 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',
|
||||
"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
|
||||
@@ -571,5 +588,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#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.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
|
||||
@@ -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
|
||||
|
||||
@@ -34,6 +34,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
|
||||
|
||||
|
||||
@@ -79,19 +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>")
|
||||
@@ -357,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
|
||||
@@ -1035,18 +1038,27 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
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)
|
||||
@@ -1082,8 +1094,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
|
||||
@@ -1091,9 +1109,9 @@ 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -787,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>"
|
||||
@@ -2744,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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -154,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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -115,13 +115,13 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, "<span class='warning'>You can't bring yourself to use a ranged weapon!</span>")
|
||||
return FALSE
|
||||
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
|
||||
if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS))
|
||||
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
|
||||
balloon_alert(src, "fingers are too big!")
|
||||
return FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_NOGUNS))
|
||||
to_chat(src, span_warning("You can't bring yourself to use a ranged weapon!"))
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/get_bank_account()
|
||||
RETURN_TYPE(/datum/bank_account)
|
||||
|
||||
@@ -1,4 +1,31 @@
|
||||
/**
|
||||
* Run when a client is put in this mob or reconnets to byond and their client was on this mob
|
||||
*
|
||||
* Things it does:
|
||||
* * Adds player to player_list
|
||||
* * sets lastKnownIP
|
||||
* * sets computer_id
|
||||
* * logs the login
|
||||
* * tells the world to update it's status (for player count)
|
||||
* * create mob huds for the mob if needed
|
||||
* * reset next_move to 1
|
||||
* * parent call
|
||||
* * if the client exists set the perspective to the mob loc
|
||||
* * call on_log on the loc (sigh)
|
||||
* * reload the huds for the mob
|
||||
* * reload all full screen huds attached to this mob
|
||||
* * load any global alternate apperances
|
||||
* * sync the mind datum via sync_mind()
|
||||
* * call any client login callbacks that exist
|
||||
* * grant any actions the mob has to the client
|
||||
* * calls [auto_deadmin_on_login](mob.html#proc/auto_deadmin_on_login)
|
||||
* * send signal COMSIG_MOB_CLIENT_LOGIN
|
||||
* * attaches the ash listener element so clients can hear weather
|
||||
* client can be deleted mid-execution of this proc, chiefly on parent calls, with lag
|
||||
*/
|
||||
/mob/Login()
|
||||
if(!client)
|
||||
return FALSE
|
||||
add_to_player_list()
|
||||
lastKnownIP = client.address
|
||||
computer_id = client.computer_id
|
||||
@@ -15,6 +42,14 @@
|
||||
|
||||
. = ..()
|
||||
|
||||
if(!client)
|
||||
return FALSE
|
||||
|
||||
// SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
|
||||
|
||||
if (key != client.key)
|
||||
key = client.key
|
||||
|
||||
reset_perspective(loc)
|
||||
|
||||
if(loc)
|
||||
@@ -53,6 +88,12 @@
|
||||
|
||||
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
|
||||
client.init_verbs()
|
||||
|
||||
if(has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
|
||||
LoadComponent(/datum/component/field_of_vision, field_of_vision_type)
|
||||
|
||||
AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
|
||||
|
||||
// optimized area sound effects. Enable during events (compile flag when 😳)
|
||||
// AddElement(/datum/element/weather_listener, /datum/weather/long_rain, ZTRAIT_STATION, GLOB.rain_sounds)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
SStgui.on_logout(src)
|
||||
unset_machine()
|
||||
remove_from_player_list()
|
||||
|
||||
..()
|
||||
|
||||
if(loc)
|
||||
|
||||
@@ -5,7 +5,14 @@
|
||||
var/title = "Untitled Conversation"
|
||||
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
|
||||
var/list/messages = list()
|
||||
var/list/clients = list()
|
||||
///chat clients who are active or minimized
|
||||
var/list/active_clients = list()
|
||||
///chat clients who have exited out of the program.
|
||||
var/list/offline_clients = list()
|
||||
///clients muted by operator
|
||||
var/list/muted_clients = list()
|
||||
//if a channel is strong, it cannot be renamed or deleted.
|
||||
var/strong = FALSE
|
||||
var/password
|
||||
var/static/ntnrc_uid = 0
|
||||
|
||||
@@ -22,6 +29,8 @@
|
||||
/datum/ntnet_conversation/Destroy()
|
||||
if(SSnetworks.station_network)
|
||||
SSnetworks.station_network.chat_channels.Remove(src)
|
||||
for(var/datum/computer_file/program/chatclient/chatterbox in (active_clients | offline_clients | muted_clients))
|
||||
purge_client(chatterbox)
|
||||
return ..()
|
||||
|
||||
/datum/ntnet_conversation/proc/add_message(message, username)
|
||||
@@ -38,39 +47,70 @@
|
||||
return
|
||||
messages = messages.Copy(messages.len-50 ,0)
|
||||
|
||||
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C)
|
||||
if(!istype(C))
|
||||
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/new_user, silent = FALSE)
|
||||
if(!istype(new_user))
|
||||
return
|
||||
clients.Add(C)
|
||||
add_status_message("[C.username] has joined the channel.")
|
||||
new_user.conversations |= src
|
||||
active_clients.Add(new_user)
|
||||
if(!silent)
|
||||
add_status_message("[new_user.username] has joined the channel.")
|
||||
// No operator, so we assume the channel was empty. Assign this user as operator.
|
||||
if(!operator)
|
||||
changeop(C)
|
||||
changeop(new_user)
|
||||
|
||||
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C)
|
||||
if(!istype(C) || !(C in clients))
|
||||
//Clear all of our references to a client, used for client deletion
|
||||
/datum/ntnet_conversation/proc/purge_client(datum/computer_file/program/chatclient/forget)
|
||||
remove_client(forget)
|
||||
muted_clients -= forget
|
||||
offline_clients -= forget
|
||||
forget.conversations -= src
|
||||
|
||||
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/leaving)
|
||||
if(!istype(leaving))
|
||||
return
|
||||
clients.Remove(C)
|
||||
add_status_message("[C.username] has left the channel.")
|
||||
if(leaving in active_clients)
|
||||
active_clients.Remove(leaving)
|
||||
add_status_message("[leaving.username] has left the channel.")
|
||||
|
||||
// Channel operator left, pick new operator
|
||||
if(C == operator)
|
||||
if(leaving == operator)
|
||||
operator = null
|
||||
if(clients.len)
|
||||
var/datum/computer_file/program/chatclient/newop = pick(clients)
|
||||
if(active_clients.len)
|
||||
var/datum/computer_file/program/chatclient/newop = pick(active_clients)
|
||||
changeop(newop)
|
||||
|
||||
/datum/ntnet_conversation/proc/go_offline(datum/computer_file/program/chatclient/offline)
|
||||
if(!istype(offline) || !(offline in active_clients))
|
||||
return
|
||||
active_clients.Remove(offline)
|
||||
offline_clients.Add(offline)
|
||||
|
||||
/datum/ntnet_conversation/proc/mute_user(datum/computer_file/program/chatclient/op, datum/computer_file/program/chatclient/muted)
|
||||
if(operator != op) //sanity even if the person shouldn't be able to see the mute button
|
||||
return
|
||||
if(muted in muted_clients)
|
||||
muted_clients.Remove(muted)
|
||||
muted.computer.alert_call(muted, "You have been unmuted from [title]!", 'sound/machines/ping.ogg')
|
||||
else
|
||||
muted_clients.Add(muted)
|
||||
muted.computer.alert_call(muted, "You have been muted from [title]!")
|
||||
|
||||
/datum/ntnet_conversation/proc/ping_user(datum/computer_file/program/chatclient/pinger, datum/computer_file/program/chatclient/pinged)
|
||||
if(pinger in muted_clients) //oh my god fuck off
|
||||
return
|
||||
add_status_message("[pinger.username] pinged [pinged.username].")
|
||||
pinged.computer.alert_call(pinged, "You have been pinged in [title] by [pinger.username]!", 'sound/machines/ping.ogg')
|
||||
|
||||
/datum/ntnet_conversation/proc/changeop(datum/computer_file/program/chatclient/newop)
|
||||
if(istype(newop))
|
||||
operator = newop
|
||||
add_status_message("Channel operator status transferred to [newop.username].")
|
||||
|
||||
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/client)
|
||||
if(operator != client)
|
||||
return FALSE // Not Authorised
|
||||
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/renamer)
|
||||
if(operator != renamer || strong)
|
||||
return FALSE // Not Authorised or channel cannot be editted
|
||||
|
||||
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
|
||||
add_status_message("[renamer.username] has changed channel title from [title] to [newtitle]")
|
||||
title = newtitle
|
||||
|
||||
#undef MAX_CHANNELS
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
. += "It has a slot installed for an intelliCard which contains: [ai_slot.stored_card.name]"
|
||||
else
|
||||
. += "It has a slot installed for an intelliCard, which appears to be occupied."
|
||||
. += "<span class='info'>Alt-click to eject the intelliCard.</span>"
|
||||
. += span_info("Alt-click to eject the intelliCard.")
|
||||
else
|
||||
. += "It has a slot installed for an intelliCard."
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
. += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]."
|
||||
else
|
||||
. += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied."
|
||||
. += "<span class='info'>Alt-click [src] to eject the identification card[multiple_cards ? "s":""].</span>"
|
||||
. += span_info("Alt-click [src] to eject the identification card[multiple_cards ? "s":""].")
|
||||
else
|
||||
. += "It has [multiple_slots ? "two slots" : "a slot"] installed for identification cards."
|
||||
|
||||
@@ -63,4 +63,4 @@
|
||||
if(printer_slot)
|
||||
. += "It has a printer installed."
|
||||
if(user_is_adjacent)
|
||||
. += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].</span>"
|
||||
. += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].</span>]"
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
rad_flags = RAD_PROTECT_CONTENTS
|
||||
armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
|
||||
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
|
||||
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
|
||||
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/enabled = 0 // Whether the computer is turned on.
|
||||
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
|
||||
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
|
||||
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0
|
||||
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
|
||||
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
|
||||
var/last_world_time = "00:00"
|
||||
var/list/last_header_icons
|
||||
///Looping sound for when the computer is on
|
||||
@@ -26,19 +26,19 @@
|
||||
///Whether or not this modular computer uses the looping sound
|
||||
var/looping_sound = TRUE
|
||||
|
||||
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
|
||||
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
|
||||
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
|
||||
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
|
||||
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off.
|
||||
var/icon_state_powered = null // Icon state when the computer is turned on.
|
||||
var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/display_overlays = TRUE // If FALSE, don't draw overlays on this device at all
|
||||
var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4.
|
||||
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off.
|
||||
var/icon_state_powered = null // Icon state when the computer is turned on.
|
||||
var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/display_overlays = TRUE // If FALSE, don't draw overlays on this device at all
|
||||
var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4.
|
||||
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
|
||||
/// List of "connection ports" in this computer and the components with which they are plugged
|
||||
var/list/all_components = list()
|
||||
@@ -47,11 +47,11 @@
|
||||
/// Number of total expansion bays this computer has available.
|
||||
var/max_bays = 0
|
||||
|
||||
var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
|
||||
var/has_light = FALSE //If the computer has a flashlight/LED light/what-have-you installed
|
||||
var/comp_light_luminosity = 3 //The brightness of that light
|
||||
var/comp_light_color //The color of that light
|
||||
var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
|
||||
var/has_light = FALSE //If the computer has a flashlight/LED light/what-have-you installed
|
||||
var/comp_light_luminosity = 3 //The brightness of that light
|
||||
var/comp_light_color //The color of that light
|
||||
|
||||
|
||||
/obj/item/modular_computer/Initialize()
|
||||
@@ -62,13 +62,12 @@
|
||||
comp_light_color = "#FFFFFF"
|
||||
idle_threads = list()
|
||||
if(looping_sound)
|
||||
soundloop = new(list(src), enabled)
|
||||
update_icon()
|
||||
soundloop = new(src, enabled)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/modular_computer/Destroy()
|
||||
kill_program(forced = TRUE)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(soundloop)
|
||||
for(var/H in all_components)
|
||||
var/obj/item/computer_hardware/CH = all_components[H]
|
||||
if(CH.holder == src)
|
||||
@@ -76,9 +75,19 @@
|
||||
CH.holder = null
|
||||
all_components.Remove(CH.device_type)
|
||||
qdel(CH)
|
||||
//Some components will actually try and interact with this, so let's do it later
|
||||
QDEL_NULL(soundloop)
|
||||
physical = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Plays a ping sound.
|
||||
*
|
||||
* Timers runtime if you try to make them call playsound. Yep.
|
||||
*/
|
||||
/obj/item/modular_computer/proc/play_ping()
|
||||
playsound(loc, 'sound/machines/ping.ogg', get_clamped_volume(), FALSE, -1)
|
||||
|
||||
/obj/item/modular_computer/AltClick(mob/user)
|
||||
..()
|
||||
if(issilicon(user))
|
||||
@@ -98,14 +107,34 @@
|
||||
|
||||
/obj/item/modular_computer/GetID()
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
|
||||
if(card_slot)
|
||||
return card_slot.GetID()
|
||||
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
|
||||
|
||||
var/obj/item/card/id/first_id = card_slot?.GetID()
|
||||
var/obj/item/card/id/second_id = card_slot2?.GetID()
|
||||
|
||||
// If we don't have both ID slots filled, pick the one that is filled.
|
||||
if(first_id)
|
||||
return first_id
|
||||
if(second_id)
|
||||
return second_id
|
||||
|
||||
// Otherwise, we have no ID at all.
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/RemoveID()
|
||||
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
|
||||
return (card_slot2?.try_eject() || card_slot?.try_eject()) //Try the secondary one first.
|
||||
|
||||
var/removed_id = (card_slot2?.try_eject() || card_slot?.try_eject())
|
||||
if(removed_id)
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/human_wearer = loc
|
||||
if(human_wearer.wear_id == src)
|
||||
human_wearer.sec_hud_set_ID()
|
||||
update_slot_icon()
|
||||
return removed_id
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/InsertID(obj/item/inserting_item)
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
|
||||
@@ -118,7 +147,13 @@
|
||||
return FALSE
|
||||
|
||||
if((card_slot?.try_insert(inserting_id)) || (card_slot2?.try_insert(inserting_id)))
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/human_wearer = loc
|
||||
if(human_wearer.wear_id == src)
|
||||
human_wearer.sec_hud_set_ID()
|
||||
update_slot_icon()
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
|
||||
@@ -142,9 +177,8 @@
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/modular_computer/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!enabled)
|
||||
to_chat(user, "<span class='warning'>You'd need to turn the [src] on first.</span>")
|
||||
to_chat(user, span_warning("You'd need to turn the [src] on first."))
|
||||
return FALSE
|
||||
obj_flags |= EMAGGED //Mostly for consistancy purposes; the programs will do their own emag handling
|
||||
var/newemag = FALSE
|
||||
@@ -155,36 +189,31 @@
|
||||
if(app.run_emag())
|
||||
newemag = TRUE
|
||||
if(newemag)
|
||||
to_chat(user, "<span class='notice'>You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past.</span>")
|
||||
to_chat(user, span_notice("You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past."))
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it.</span>")
|
||||
to_chat(user, span_notice("You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it."))
|
||||
return FALSE
|
||||
|
||||
/obj/item/modular_computer/examine(mob/user)
|
||||
. = ..()
|
||||
if(obj_integrity <= integrity_failure * max_integrity)
|
||||
. += "<span class='danger'>It is heavily damaged!</span>"
|
||||
. += span_danger("It is heavily damaged!")
|
||||
else if(obj_integrity < max_integrity)
|
||||
. += "<span class='warning'>It is damaged.</span>"
|
||||
. += span_warning("It is damaged.")
|
||||
|
||||
. += get_modular_computer_parts_examine(user)
|
||||
|
||||
/obj/item/modular_computer/update_icon_state()
|
||||
if(!enabled)
|
||||
icon_state = icon_state_unpowered
|
||||
else
|
||||
icon_state = icon_state_powered
|
||||
icon_state = enabled ? icon_state_powered : icon_state_unpowered
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/update_overlays()
|
||||
. = ..()
|
||||
if(!display_overlays)
|
||||
return
|
||||
if(enabled)
|
||||
if(active_program)
|
||||
. += active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu
|
||||
else
|
||||
. += icon_state_menu
|
||||
|
||||
if(enabled)
|
||||
. += active_program?.program_icon_state || icon_state_menu
|
||||
if(obj_integrity <= integrity_failure * max_integrity)
|
||||
. += "bsod"
|
||||
. += "broken"
|
||||
@@ -201,9 +230,9 @@
|
||||
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
|
||||
if(obj_integrity <= integrity_failure * max_integrity)
|
||||
if(issynth)
|
||||
to_chat(user, "<span class='warning'>You send an activation signal to \the [src], but it responds with an error code. It must be damaged.</span>")
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src], but it responds with an error code. It must be damaged."))
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.</span>")
|
||||
to_chat(user, span_warning("You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."))
|
||||
return FALSE
|
||||
|
||||
// If we have a recharger, enable it automatically. Lets computer without a battery work.
|
||||
@@ -213,20 +242,20 @@
|
||||
|
||||
if(all_components[MC_CPU] && use_power()) // use_power() checks if the PC is powered
|
||||
if(issynth)
|
||||
to_chat(user, "<span class='notice'>You send an activation signal to \the [src], turning it on.</span>")
|
||||
to_chat(user, span_notice("You send an activation signal to \the [src], turning it on."))
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You press the power button and start up \the [src].</span>")
|
||||
to_chat(user, span_notice("You press the power button and start up \the [src]."))
|
||||
if(looping_sound)
|
||||
soundloop.start()
|
||||
enabled = 1
|
||||
update_icon()
|
||||
update_appearance()
|
||||
ui_interact(user)
|
||||
return TRUE
|
||||
else // Unpowered
|
||||
if(issynth)
|
||||
to_chat(user, "<span class='warning'>You send an activation signal to \the [src] but it does not respond.</span>")
|
||||
to_chat(user, span_warning("You send an activation signal to \the [src] but it does not respond."))
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You press the power button but \the [src] does not respond.</span>")
|
||||
to_chat(user, span_warning("You press the power button but \the [src] does not respond."))
|
||||
return FALSE
|
||||
|
||||
// Process currently calls handle_power(), may be expanded in future if more things are added.
|
||||
@@ -282,10 +311,10 @@
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
|
||||
return
|
||||
playsound(src, sound, 50, TRUE)
|
||||
visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
visible_message(span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))
|
||||
var/mob/living/holder = loc
|
||||
if(istype(holder))
|
||||
to_chat(holder, "[icon2html(src)] <span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
to_chat(holder, "[icon2html(src)] [span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]")]")
|
||||
|
||||
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
|
||||
/obj/item/modular_computer/proc/get_header_data()
|
||||
@@ -349,14 +378,13 @@
|
||||
|
||||
// Relays kill program request to currently active program. Use this to quit current program.
|
||||
/obj/item/modular_computer/proc/kill_program(forced = FALSE)
|
||||
set waitfor = FALSE
|
||||
if(active_program)
|
||||
active_program.kill_program(forced)
|
||||
active_program = null
|
||||
var/mob/user = usr
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
|
||||
/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0)
|
||||
@@ -370,6 +398,7 @@
|
||||
if(!get_ntnet_status())
|
||||
return FALSE
|
||||
var/obj/item/computer_hardware/network_card/network_card = all_components[MC_NET]
|
||||
|
||||
return SSnetworks.station_network.add_log(text, network_card)
|
||||
|
||||
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
|
||||
@@ -380,9 +409,9 @@
|
||||
if(looping_sound)
|
||||
soundloop.stop()
|
||||
if(loud)
|
||||
physical.visible_message("<span class='notice'>\The [src] shuts down.</span>")
|
||||
physical.visible_message(span_notice("\The [src] shuts down."))
|
||||
enabled = 0
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/**
|
||||
* Toggles the computer's flashlight, if it has one.
|
||||
@@ -412,13 +441,13 @@
|
||||
if(!has_light || !color)
|
||||
return FALSE
|
||||
comp_light_color = color
|
||||
// set_light_color(color)
|
||||
set_light_color(color)
|
||||
update_light()
|
||||
return TRUE
|
||||
|
||||
/obj/item/modular_computer/screwdriver_act(mob/user, obj/item/tool)
|
||||
if(!all_components.len)
|
||||
to_chat(user, "<span class='warning'>This device doesn't have any components installed.</span>")
|
||||
to_chat(user, span_warning("This device doesn't have any components installed."))
|
||||
return
|
||||
var/list/component_names = list()
|
||||
for(var/h in all_components)
|
||||
@@ -460,28 +489,34 @@
|
||||
|
||||
if(W.tool_behaviour == TOOL_WRENCH)
|
||||
if(all_components.len)
|
||||
to_chat(user, "<span class='warning'>Remove all components from \the [src] before disassembling it.</span>")
|
||||
to_chat(user, span_warning("Remove all components from \the [src] before disassembling it."))
|
||||
return
|
||||
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
|
||||
physical.visible_message("<span class='notice'>\The [src] is disassembled by [user].</span>")
|
||||
physical.visible_message(span_notice("\The [src] is disassembled by [user]."))
|
||||
relay_qdel()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(W.tool_behaviour == TOOL_WELDER)
|
||||
if(obj_integrity == max_integrity)
|
||||
to_chat(user, "<span class='warning'>\The [src] does not require repairs.</span>")
|
||||
to_chat(user, span_warning("\The [src] does not require repairs."))
|
||||
return
|
||||
|
||||
if(!W.tool_start_check(user, amount=1))
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You begin repairing damage to \the [src]...</span>")
|
||||
to_chat(user, span_notice("You begin repairing damage to \the [src]..."))
|
||||
if(W.use_tool(src, user, 20, volume=50, amount=1))
|
||||
obj_integrity = max_integrity
|
||||
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
|
||||
to_chat(user, span_notice("You repair \the [src]."))
|
||||
return
|
||||
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
|
||||
// Check to see if we have an ID inside, and a valid input for money
|
||||
if(card_slot?.GetID() && iscash(W))
|
||||
var/obj/item/card/id/id = card_slot.GetID()
|
||||
id.attackby(W, user) // If we do, try and put that attacking object in
|
||||
return
|
||||
..()
|
||||
|
||||
// Used by processor to relay qdel() to machinery type.
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
return FALSE
|
||||
|
||||
if(H.w_class > max_hardware_size)
|
||||
to_chat(user, "<span class='warning'>This component is too large for \the [src]!</span>")
|
||||
to_chat(user, span_warning("This component is too large for \the [src]!"))
|
||||
return FALSE
|
||||
|
||||
if(H.expansion_hw)
|
||||
if(LAZYLEN(expansion_bays) >= max_bays)
|
||||
to_chat(user, "<span class='warning'>All of the computer's expansion bays are filled.</span>")
|
||||
to_chat(user, span_warning("All of the computer's expansion bays are filled."))
|
||||
return FALSE
|
||||
if(LAZYACCESS(expansion_bays, H.device_type))
|
||||
to_chat(user, "<span class='warning'>The computer immediately ejects /the [H] and flashes an error: \"Hardware Address Conflict\".</span>")
|
||||
to_chat(user, span_warning("The computer immediately ejects /the [H] and flashes an error: \"Hardware Address Conflict\"."))
|
||||
return FALSE
|
||||
|
||||
if(all_components[H.device_type])
|
||||
to_chat(user, "<span class='warning'>This computer's hardware slot is already occupied by \the [all_components[H.device_type]].</span>")
|
||||
to_chat(user, span_warning("This computer's hardware slot is already occupied by \the [all_components[H.device_type]]."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
LAZYSET(expansion_bays, H.device_type, H)
|
||||
all_components[H.device_type] = H
|
||||
|
||||
to_chat(user, "<span class='notice'>You install \the [H] into \the [src].</span>")
|
||||
to_chat(user, span_notice("You install \the [H] into \the [src]."))
|
||||
H.holder = src
|
||||
H.forceMove(src)
|
||||
H.on_install(src, user)
|
||||
@@ -47,14 +47,14 @@
|
||||
LAZYREMOVE(expansion_bays, H.device_type)
|
||||
all_components.Remove(H.device_type)
|
||||
|
||||
to_chat(user, "<span class='notice'>You remove \the [H] from \the [src].</span>")
|
||||
to_chat(user, span_notice("You remove \the [H] from \the [src]."))
|
||||
|
||||
H.forceMove(get_turf(src))
|
||||
H.holder = null
|
||||
H.on_remove(src, user)
|
||||
if(enabled && !use_power())
|
||||
shutdown_computer()
|
||||
update_icon()
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/obj/item/modular_computer/proc/break_apart()
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
physical.visible_message("<span class='notice'>\The [src] breaks apart!</span>")
|
||||
physical.visible_message(span_notice("\The [src] breaks apart!"))
|
||||
var/turf/newloc = get_turf(src)
|
||||
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
|
||||
for(var/C in all_components)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
if(cell.use(amount * GLOB.CELLRATE))
|
||||
return TRUE
|
||||
else // Discharge the cell anyway.
|
||||
cell.use(min(amount*GLOB.CELLRATE, cell.charge))
|
||||
cell.use(min(amount * GLOB.CELLRATE, cell.charge))
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
ui.close()
|
||||
return
|
||||
|
||||
// if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
|
||||
// to_chat(user, span_warning("Your fingers are too big to use this right now!"))
|
||||
// return
|
||||
|
||||
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
|
||||
if(!screen_on && !issilicon(user))
|
||||
if(ui)
|
||||
@@ -30,7 +34,7 @@
|
||||
// This screen simply lists available programs and user may select them.
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
|
||||
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
|
||||
to_chat(user, "<span class='danger'>\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning."))
|
||||
return // No HDD, No HDD files list or no stored files. Something is very broken.
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
@@ -111,15 +115,9 @@
|
||||
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
active_program = null
|
||||
update_icon()
|
||||
update_appearance()
|
||||
if(user && istype(user))
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
if("eject_pen")
|
||||
if(istype(src, /obj/item/modular_computer/tablet))
|
||||
var/obj/item/modular_computer/tablet/self = src
|
||||
if(self.can_have_pen)
|
||||
self.remove_pen()
|
||||
return
|
||||
|
||||
if("PC_killprogram")
|
||||
var/prog = params["name"]
|
||||
@@ -132,7 +130,7 @@
|
||||
return
|
||||
|
||||
P.kill_program(forced = TRUE)
|
||||
to_chat(user, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
|
||||
to_chat(user, span_notice("Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed."))
|
||||
|
||||
if("PC_runprogram")
|
||||
var/prog = params["name"]
|
||||
@@ -142,7 +140,7 @@
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
if(!P || !istype(P)) // Program not found or it's not executable program.
|
||||
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning."))
|
||||
return
|
||||
|
||||
P.computer = src
|
||||
@@ -156,22 +154,22 @@
|
||||
active_program = P
|
||||
P.alert_pending = FALSE
|
||||
idle_threads.Remove(P)
|
||||
update_icon()
|
||||
update_appearance()
|
||||
return
|
||||
|
||||
var/obj/item/computer_hardware/processor_unit/PU = all_components[MC_CPU]
|
||||
|
||||
if(idle_threads.len > PU.max_idle_programs)
|
||||
to_chat(user, "<span class='danger'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error.</span>")
|
||||
to_chat(user, span_danger("\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error."))
|
||||
return
|
||||
|
||||
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet.
|
||||
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [src]'s screen shows \"Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning."))
|
||||
return
|
||||
if(P.run_program(user))
|
||||
active_program = P
|
||||
P.alert_pending = FALSE
|
||||
update_icon()
|
||||
update_appearance()
|
||||
return 1
|
||||
|
||||
if("PC_toggle_light")
|
||||
@@ -185,7 +183,7 @@
|
||||
if(!new_color)
|
||||
return
|
||||
if(color_hex2num(new_color) < 200) //Colors too dark are rejected
|
||||
to_chat(user, "<span class='warning'>That color is too dark! Choose a lighter one.</span>")
|
||||
to_chat(user, span_warning("That color is too dark! Choose a lighter one."))
|
||||
new_color = null
|
||||
return set_flashlight_color(new_color)
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
// No running around with open laptops in hands.
|
||||
item_flags = SLOWS_WHILE_IN_HAND
|
||||
|
||||
screen_on = FALSE // Starts closed
|
||||
var/start_open = TRUE // unless this var is set to 1
|
||||
screen_on = FALSE // Starts closed
|
||||
var/start_open = TRUE // unless this var is set to 1
|
||||
var/icon_state_closed = "laptop-closed"
|
||||
var/w_class_open = WEIGHT_CLASS_BULKY
|
||||
var/slowdown_open = TRUE
|
||||
@@ -44,15 +44,14 @@
|
||||
/obj/item/modular_computer/laptop/update_icon_state()
|
||||
if(!screen_on)
|
||||
icon_state = icon_state_closed
|
||||
else
|
||||
. = ..()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/laptop/update_overlays()
|
||||
if(screen_on)
|
||||
return ..()
|
||||
else
|
||||
if(!screen_on)
|
||||
cut_overlays()
|
||||
icon_state = icon_state_closed
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/laptop/attack_self(mob/user)
|
||||
if(!screen_on)
|
||||
@@ -68,7 +67,8 @@
|
||||
try_toggle_open(usr)
|
||||
|
||||
/obj/item/modular_computer/laptop/MouseDrop(obj/over_object, src_location, over_location)
|
||||
if(istype(over_object, /atom/movable/screen/inventory/hand) || over_object == usr)
|
||||
. = ..()
|
||||
if(istype(over_object, /atom/movable/screen/inventory/hand))
|
||||
var/atom/movable/screen/inventory/hand/H = over_object
|
||||
var/mob/M = usr
|
||||
|
||||
@@ -103,17 +103,17 @@
|
||||
|
||||
/obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null)
|
||||
if(screen_on)
|
||||
to_chat(user, "<span class='notice'>You close \the [src].</span>")
|
||||
to_chat(user, span_notice("You close \the [src]."))
|
||||
slowdown = initial(slowdown)
|
||||
w_class = initial(w_class)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You open \the [src].</span>")
|
||||
to_chat(user, span_notice("You open \the [src]."))
|
||||
slowdown = slowdown_open
|
||||
w_class = w_class_open
|
||||
|
||||
screen_on = !screen_on
|
||||
display_overlays = screen_on
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
integrity_failure = machinery_computer.integrity_failure
|
||||
base_active_power_usage = machinery_computer.base_active_power_usage
|
||||
base_idle_power_usage = machinery_computer.base_idle_power_usage
|
||||
machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /atom/proc/update_icon) //when we update_icon, also update the computer
|
||||
machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /obj/machinery/modular_computer/proc/relay_icon_update) //when we update_icon, also update the computer
|
||||
|
||||
/obj/item/modular_computer/processor/relay_qdel()
|
||||
qdel(machinery_computer)
|
||||
@@ -47,7 +47,7 @@
|
||||
if(!machinery_computer)
|
||||
return
|
||||
..()
|
||||
machinery_computer.update_icon()
|
||||
machinery_computer.update_appearance()
|
||||
return
|
||||
|
||||
/obj/item/modular_computer/processor/attack_ghost(mob/user)
|
||||
@@ -57,4 +57,4 @@
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext)
|
||||
return
|
||||
playsound(src, 'sound/machines/twobeep_high.ogg', 50, TRUE)
|
||||
machinery_computer.visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
machinery_computer.visible_message(span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
name = "tablet computer"
|
||||
icon = 'icons/obj/modular_tablet.dmi'
|
||||
icon_state = "tablet-red"
|
||||
icon_state_unpowered = "tablet"
|
||||
icon_state_powered = "tablet"
|
||||
icon_state_unpowered = "tablet-red"
|
||||
icon_state_powered = "tablet-red"
|
||||
icon_state_menu = "menu"
|
||||
base_icon_state = "tablet"
|
||||
// worn_icon_state = "tablet"
|
||||
hardware_flag = PROGRAM_TABLET
|
||||
max_hardware_size = 1
|
||||
@@ -80,12 +81,12 @@
|
||||
/obj/item/modular_computer/tablet/ui_data(mob/user)
|
||||
. = ..()
|
||||
.["PC_showpeneject"] = inserted_item ? 1 : 0
|
||||
|
||||
/obj/item/modular_computer/tablet/update_icon_state()
|
||||
if(has_variants)
|
||||
if(!finish_color)
|
||||
finish_color = pick("red","blue","brown","green","black")
|
||||
icon_state = icon_state_powered = icon_state_unpowered = "tablet-[finish_color]"
|
||||
finish_color = pick("red", "blue", "brown", "green", "black")
|
||||
icon_state = icon_state_powered = icon_state_unpowered = "[base_icon_state]-[finish_color]"
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/tablet/syndicate_contract_uplink
|
||||
name = "contractor tablet"
|
||||
@@ -102,6 +103,8 @@
|
||||
/// Given to Nuke Ops members.
|
||||
/obj/item/modular_computer/tablet/nukeops
|
||||
icon_state = "tablet-syndicate"
|
||||
icon_state_powered = "tablet-syndicate"
|
||||
icon_state_unpowered = "tablet-syndicate"
|
||||
comp_light_luminosity = 6.3
|
||||
has_variants = FALSE
|
||||
device_theme = "syndicate"
|
||||
@@ -109,15 +112,18 @@
|
||||
|
||||
/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user)
|
||||
if(!enabled)
|
||||
to_chat(user, "<span class='warning'>You'd need to turn the [src] on first.</span>")
|
||||
to_chat(user, span_warning("You'd need to turn the [src] on first."))
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\".</span>")
|
||||
to_chat(user, span_notice("You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\"."))
|
||||
return FALSE
|
||||
|
||||
/// Borg Built-in tablet interface
|
||||
/obj/item/modular_computer/tablet/integrated
|
||||
name = "modular interface"
|
||||
icon_state = "tablet-silicon"
|
||||
icon_state_powered = "tablet-silicon"
|
||||
icon_state_unpowered = "tablet-silicon"
|
||||
base_icon_state = "tablet-silicon"
|
||||
has_light = FALSE //tablet light button actually enables/disables the borg lamp
|
||||
comp_light_luminosity = 0
|
||||
has_variants = FALSE
|
||||
@@ -198,11 +204,13 @@
|
||||
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
|
||||
return
|
||||
borgo.playsound_local(src, sound, 50, TRUE)
|
||||
to_chat(borgo, "<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
|
||||
to_chat(borgo, span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))
|
||||
|
||||
|
||||
/obj/item/modular_computer/tablet/integrated/syndicate
|
||||
icon_state = "tablet-silicon-syndicate"
|
||||
icon_state_powered = "tablet-silicon-syndicate"
|
||||
icon_state_unpowered = "tablet-silicon-syndicate"
|
||||
device_theme = "syndicate"
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,17 @@
|
||||
install_component(new /obj/item/computer_hardware/card_slot)
|
||||
install_component(new /obj/item/computer_hardware/printer/mini)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/science/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = new
|
||||
install_component(new /obj/item/computer_hardware/processor_unit/small)
|
||||
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
|
||||
install_component(hard_drive)
|
||||
install_component(new /obj/item/computer_hardware/card_slot)
|
||||
install_component(new /obj/item/computer_hardware/network_card)
|
||||
install_component(new /obj/item/computer_hardware/radio_card)
|
||||
hard_drive.store_file(new /datum/computer_file/program/signaler)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/cargo/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = new
|
||||
@@ -30,17 +41,38 @@
|
||||
install_component(new /obj/item/computer_hardware/network_card)
|
||||
install_component(new /obj/item/computer_hardware/printer/mini)
|
||||
// hard_drive.store_file(new /datum/computer_file/program/shipping)
|
||||
var/datum/computer_file/program/chatclient/chatprogram
|
||||
chatprogram = new
|
||||
hard_drive.store_file(chatprogram)
|
||||
chatprogram.username = get_cargochat_username()
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/cargo/proc/get_cargochat_username()
|
||||
return "cargonian_[rand(1,999)]"
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/cargo/quartermaster/get_cargochat_username()
|
||||
return "quartermaster"
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/atmos/Initialize() //This will be defunct and will be replaced when NtOS PDAs are done
|
||||
. = ..()
|
||||
install_component(new /obj/item/computer_hardware/sensorpackage)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/engineering/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
|
||||
hard_drive.store_file(new /datum/computer_file/program/supermatter_monitor)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/command/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
|
||||
install_component(new /obj/item/computer_hardware/sensorpackage)
|
||||
install_component(new /obj/item/computer_hardware/card_slot/secondary)
|
||||
hard_drive.store_file(new /datum/computer_file/program/budgetorders)
|
||||
// hard_drive.store_file(new /datum/computer_file/program/science)
|
||||
|
||||
/obj/item/modular_computer/tablet/preset/advanced/command/engineering/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
|
||||
hard_drive.store_file(new /datum/computer_file/program/supermatter_monitor)
|
||||
|
||||
/// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
|
||||
/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize()
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
/obj/machinery/modular_computer/console/preset/proc/install_programs()
|
||||
return
|
||||
|
||||
|
||||
|
||||
// ===== ENGINEERING CONSOLE =====
|
||||
/obj/machinery/modular_computer/console/preset/engineering
|
||||
console_department = "Engineering"
|
||||
@@ -45,6 +43,7 @@
|
||||
console_department = "Research"
|
||||
name = "research director's console"
|
||||
desc = "A stationary computer. This one comes preloaded with research programs."
|
||||
_has_second_id_slot = TRUE
|
||||
_has_ai = TRUE
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/research/install_programs()
|
||||
@@ -84,6 +83,18 @@
|
||||
hard_drive.store_file(new/datum/computer_file/program/job_management())
|
||||
hard_drive.store_file(new/datum/computer_file/program/crew_manifest())
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/id/centcom
|
||||
desc = "A stationary computer. This one comes preloaded with CentCom identification modification programs."
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/id/centcom/install_programs()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
|
||||
var/datum/computer_file/program/card_mod/card_mod_centcom = new /datum/computer_file/program/card_mod()
|
||||
card_mod_centcom.is_centcom = TRUE
|
||||
hard_drive.store_file(new /datum/computer_file/program/chatclient())
|
||||
hard_drive.store_file(card_mod_centcom)
|
||||
hard_drive.store_file(new /datum/computer_file/program/job_management())
|
||||
hard_drive.store_file(new /datum/computer_file/program/crew_manifest())
|
||||
|
||||
// ===== CIVILIAN CONSOLE =====
|
||||
/obj/machinery/modular_computer/console/preset/civilian
|
||||
console_department = "Civilian"
|
||||
@@ -94,3 +105,79 @@
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
|
||||
hard_drive.store_file(new/datum/computer_file/program/chatclient())
|
||||
hard_drive.store_file(new/datum/computer_file/program/arcade())
|
||||
|
||||
// curator
|
||||
/obj/machinery/modular_computer/console/preset/curator
|
||||
console_department = "Civilian"
|
||||
name = "curator console"
|
||||
desc = "A stationary computer. This one comes preloaded with art programs."
|
||||
_has_printer = TRUE
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/curator/install_programs()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
|
||||
hard_drive.store_file(new/datum/computer_file/program/portrait_printer())
|
||||
|
||||
// ===== CARGO CHAT CONSOLES =====
|
||||
/obj/machinery/modular_computer/console/preset/cargochat
|
||||
name = "cargo chatroom console"
|
||||
desc = "A stationary computer. This one comes preloaded with a chatroom for your cargo requests."
|
||||
///chat client installed on this computer, just helpful for linking all the computers
|
||||
var/datum/computer_file/program/chatclient/chatprogram
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/install_programs()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
|
||||
chatprogram = new
|
||||
chatprogram.computer = cpu
|
||||
hard_drive.store_file(chatprogram)
|
||||
chatprogram.username = "[lowertext(console_department)]_department"
|
||||
chatprogram.program_state = PROGRAM_STATE_ACTIVE
|
||||
cpu.active_program = chatprogram
|
||||
|
||||
//ONE PER MAP PLEASE, IT MAKES A CARGOBUS FOR EACH ONE OF THESE
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/cargo
|
||||
console_department = "Cargo"
|
||||
name = "department chatroom console"
|
||||
desc = "A stationary computer. This one comes preloaded with a chatroom for incoming cargo requests. You may moderate it from this computer."
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/cargo/install_programs()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
|
||||
|
||||
//adding chat, setting it as the active window immediately
|
||||
chatprogram = new
|
||||
chatprogram.computer = cpu
|
||||
hard_drive.store_file(chatprogram)
|
||||
chatprogram.program_state = PROGRAM_STATE_ACTIVE
|
||||
cpu.active_program = chatprogram
|
||||
|
||||
//setting up chat
|
||||
chatprogram.username = "cargo_requests_operator"
|
||||
var/datum/ntnet_conversation/cargochat = new
|
||||
cargochat.operator = chatprogram //adding operator before joining the chat prevents an unnecessary message about switching op from showing
|
||||
cargochat.add_client(chatprogram)
|
||||
cargochat.title = "#cargobus"
|
||||
cargochat.strong = TRUE
|
||||
chatprogram.active_channel = cargochat.id
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/cargo/LateInitialize()
|
||||
. = ..()
|
||||
var/datum/ntnet_conversation/cargochat = SSnetworks.station_network.get_chat_channel_by_id(chatprogram.active_channel)
|
||||
for(var/obj/machinery/modular_computer/console/preset/cargochat/cargochat_console in GLOB.machines)
|
||||
if(cargochat_console == src)
|
||||
continue
|
||||
cargochat_console.chatprogram.active_channel = chatprogram.active_channel
|
||||
cargochat.add_client(cargochat_console.chatprogram, silent = TRUE)
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/service
|
||||
console_department = "Service"
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/engineering
|
||||
console_department = "Engineering"
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/science
|
||||
console_department = "Science"
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/security
|
||||
console_department = "Security"
|
||||
|
||||
/obj/machinery/modular_computer/console/preset/cargochat/medical
|
||||
console_department = "Medical"
|
||||
|
||||
@@ -4,28 +4,41 @@
|
||||
name = "modular computer"
|
||||
desc = "An advanced computer."
|
||||
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 5
|
||||
var/hardware_flag = 0 // A flag that describes this device type
|
||||
var/last_power_usage = 0 // Power usage during last tick
|
||||
|
||||
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
|
||||
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
|
||||
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
|
||||
|
||||
icon = null
|
||||
icon_state = null
|
||||
var/icon_state_unpowered = null // Icon state when the computer is turned off.
|
||||
var/icon_state_powered = null // Icon state when the computer is turned on.
|
||||
var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'.
|
||||
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
|
||||
var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/light_strength = 0 // Light luminosity when turned on
|
||||
var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
|
||||
var/obj/item/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things.
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 5
|
||||
///A flag that describes this device type
|
||||
var/hardware_flag = 0
|
||||
///Power usage during last tick
|
||||
var/last_power_usage = 0
|
||||
|
||||
|
||||
///Icon state when the computer is turned off.
|
||||
var/icon_state_unpowered = null
|
||||
///Icon state when the computer is turned on.
|
||||
var/icon_state_powered = null
|
||||
///Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
|
||||
var/screen_icon_state_menu = "menu"
|
||||
///Icon state overlay when the computer is powered, but not 'switched on'.
|
||||
var/screen_icon_screensaver = "standby"
|
||||
///Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
|
||||
var/max_hardware_size = 0
|
||||
///Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/steel_sheet_cost = 10
|
||||
///Light luminosity when turned on
|
||||
var/light_strength = 0
|
||||
///Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
|
||||
var/base_active_power_usage = 100
|
||||
///Power usage when the computer is idle and screen is off (currently only applies to laptops)
|
||||
var/base_idle_power_usage = 10
|
||||
|
||||
///CPU that handles most logic while this type only handles power and other specific things.
|
||||
var/obj/item/modular_computer/processor/cpu = null
|
||||
|
||||
/obj/machinery/modular_computer/Initialize()
|
||||
. = ..()
|
||||
@@ -48,32 +61,35 @@
|
||||
cpu.attack_ghost(user)
|
||||
|
||||
/obj/machinery/modular_computer/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(!cpu)
|
||||
to_chat(user, "<span class='warning'>You'd need to turn the [src] on first.</span>")
|
||||
to_chat(user, span_warning("You'd need to turn the [src] on first."))
|
||||
return FALSE
|
||||
return (cpu.emag_act(user))
|
||||
|
||||
/obj/machinery/modular_computer/update_icon()
|
||||
cut_overlays()
|
||||
icon_state = icon_state_powered
|
||||
/obj/machinery/modular_computer/update_appearance(updates)
|
||||
. = ..()
|
||||
set_light(cpu?.enabled ? light_strength : 0)
|
||||
|
||||
if(!cpu || !cpu.enabled)
|
||||
/obj/machinery/modular_computer/update_icon_state()
|
||||
icon_state = (cpu?.enabled || (!(stat & NOPOWER) && cpu?.use_power())) ? icon_state_powered : icon_state_unpowered
|
||||
return ..()
|
||||
|
||||
/obj/machinery/modular_computer/update_overlays()
|
||||
. = ..()
|
||||
if(!cpu?.enabled)
|
||||
if (!(stat & NOPOWER) && (cpu?.use_power()))
|
||||
add_overlay(screen_icon_screensaver)
|
||||
else
|
||||
icon_state = icon_state_unpowered
|
||||
set_light(0)
|
||||
. += screen_icon_screensaver
|
||||
else
|
||||
set_light(light_strength)
|
||||
if(cpu.active_program)
|
||||
add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
|
||||
else
|
||||
add_overlay(screen_icon_state_menu)
|
||||
. += cpu.active_program?.program_icon_state || screen_icon_state_menu
|
||||
|
||||
if(cpu && cpu.obj_integrity <= cpu.integrity_failure * cpu.max_integrity)
|
||||
add_overlay("bsod")
|
||||
add_overlay("broken")
|
||||
. += "bsod"
|
||||
. += "broken"
|
||||
|
||||
/// Eats the "source" arg because update_icon actually expects args now.
|
||||
/obj/machinery/modular_computer/proc/relay_icon_update(datum/source, updates, updated)
|
||||
SIGNAL_HANDLER
|
||||
return update_icon(updates)
|
||||
|
||||
/obj/machinery/modular_computer/AltClick(mob/user)
|
||||
if(cpu)
|
||||
@@ -98,17 +114,17 @@
|
||||
/obj/machinery/modular_computer/proc/power_failure(malfunction = 0)
|
||||
var/obj/item/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL]
|
||||
if(cpu?.enabled) // Shut down the computer
|
||||
visible_message("<span class='danger'>\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.</span>")
|
||||
visible_message(span_danger("\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly."))
|
||||
if(cpu)
|
||||
cpu.shutdown_computer(0)
|
||||
stat |= NOPOWER
|
||||
update_icon()
|
||||
set_machine_stat(stat | NOPOWER)
|
||||
update_appearance()
|
||||
|
||||
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
|
||||
/obj/machinery/modular_computer/power_change()
|
||||
if(cpu?.use_power()) // If MC_CPU still has a power source, PC wouldn't go offline.
|
||||
stat &= ~NOPOWER
|
||||
update_icon()
|
||||
set_machine_stat(stat & ~NOPOWER)
|
||||
update_appearance()
|
||||
return
|
||||
. = ..()
|
||||
|
||||
@@ -116,7 +132,7 @@
|
||||
if(cpu)
|
||||
return cpu.screwdriver_act(user, tool)
|
||||
|
||||
/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/user)
|
||||
/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/living/user)
|
||||
if (user.a_intent == INTENT_HELP && cpu && !(flags_1 & NODECONSTRUCT_1))
|
||||
return cpu.attackby(W, user)
|
||||
return ..()
|
||||
@@ -126,15 +142,16 @@
|
||||
// Minor explosions are mostly mitigitated by casing.
|
||||
/obj/machinery/modular_computer/ex_act(severity, target, origin)
|
||||
if(cpu)
|
||||
cpu.ex_act(severity, target, origin)
|
||||
// switch(severity)
|
||||
// if(EXPLODE_DEVASTATE)
|
||||
// SSexplosions.high_mov_atom += cpu
|
||||
// if(EXPLODE_HEAVY)
|
||||
// SSexplosions.med_mov_atom += cpu
|
||||
// if(EXPLODE_LIGHT)
|
||||
// SSexplosions.low_mov_atom += cpu
|
||||
..()
|
||||
return cpu.ex_act(severity)
|
||||
|
||||
// switch(severity)
|
||||
// if(EXPLODE_DEVASTATE)
|
||||
// SSexplosions.high_mov_atom += cpu
|
||||
// if(EXPLODE_HEAVY)
|
||||
// SSexplosions.med_mov_atom += cpu
|
||||
// if(EXPLODE_LIGHT)
|
||||
// SSexplosions.low_mov_atom += cpu
|
||||
return ..()
|
||||
|
||||
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
|
||||
/obj/machinery/modular_computer/emp_act(severity)
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
light_strength = 2
|
||||
max_integrity = 300
|
||||
integrity_failure = 0.5
|
||||
var/console_department = "" // Used in New() to set network tag according to our area.
|
||||
///Used in New() to set network tag according to our area.
|
||||
var/console_department = ""
|
||||
|
||||
/obj/machinery/modular_computer/console/buildable/Initialize()
|
||||
. = ..()
|
||||
@@ -52,4 +53,4 @@
|
||||
network_card.identification_string = "Unknown Console"
|
||||
if(cpu)
|
||||
cpu.screen_on = 1
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/datum/computer_file
|
||||
var/filename = "NewFile" // Placeholder. No spacebars
|
||||
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
|
||||
var/size = 1 // File size in GQ. Integers only!
|
||||
var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file.
|
||||
var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means.
|
||||
var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc.
|
||||
var/uid // UID of this file
|
||||
var/filename = "NewFile" // Placeholder. No spacebars
|
||||
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
|
||||
var/size = 1 // File size in GQ. Integers only!
|
||||
var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file.
|
||||
var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means.
|
||||
var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc.
|
||||
var/uid // UID of this file
|
||||
var/static/file_uid = 0
|
||||
|
||||
/datum/computer_file/New()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// /data/ files store data in string format.
|
||||
// They don't contain other logic for now.
|
||||
/datum/computer_file/data
|
||||
var/stored_data = "" // Stored data in string format.
|
||||
var/stored_data = "" // Stored data in string format.
|
||||
filetype = "DAT"
|
||||
var/block_size = 250
|
||||
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
|
||||
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
|
||||
|
||||
/datum/computer_file/data/clone()
|
||||
var/datum/computer_file/data/temp = ..()
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
var/filedesc = "Unknown Program"
|
||||
/// Short description of this program's function.
|
||||
var/extended_desc = "N/A"
|
||||
/// Category in the NTDownloader.
|
||||
var/category = PROGRAM_CATEGORY_MISC
|
||||
/// Program-specific screen icon state
|
||||
var/program_icon_state = null
|
||||
/// Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
|
||||
@@ -25,10 +27,10 @@
|
||||
var/ntnet_status = 1
|
||||
/// Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
|
||||
var/usage_flags = PROGRAM_ALL
|
||||
/// Whether the program can be downloaded from NTNet. Set to 0 to disable.
|
||||
var/available_on_ntnet = 1
|
||||
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
|
||||
var/available_on_syndinet = 0
|
||||
/// Whether the program can be downloaded from NTNet. Set to FALSE to disable.
|
||||
var/available_on_ntnet = TRUE
|
||||
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to TRUE to enable.
|
||||
var/available_on_syndinet = FALSE
|
||||
/// Name of the tgui interface
|
||||
var/tgui_id
|
||||
/// Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images!
|
||||
@@ -64,7 +66,7 @@
|
||||
// Relays icon update to the computer.
|
||||
/datum/computer_file/program/proc/update_computer_icon()
|
||||
if(computer)
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
|
||||
// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail.
|
||||
/datum/computer_file/program/proc/generate_network_log(text)
|
||||
@@ -72,10 +74,25 @@
|
||||
return computer.add_log(text)
|
||||
return 0
|
||||
|
||||
/**
|
||||
*Runs when the device is used to attack an atom in non-combat mode.
|
||||
*
|
||||
*Simulates using the device to read or scan something. Tap is called by the computer during pre_attack
|
||||
*and sends us all of the related info. If we return TRUE, the computer will stop the attack process
|
||||
*there. What we do with the info is up to us, but we should only return TRUE if we actually perform
|
||||
*an action of some sort.
|
||||
*Arguments:
|
||||
*A is the atom being tapped
|
||||
*user is the person making the attack action
|
||||
*params is anything the pre_attack() proc had in the same-named variable.
|
||||
*/
|
||||
/datum/computer_file/program/proc/tap(atom/A, mob/living/user, params)
|
||||
return FALSE
|
||||
|
||||
/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null)
|
||||
if(!(hardware_flag & usage_flags))
|
||||
if(loud && computer && user)
|
||||
to_chat(user, "<span class='danger'>\The [computer] flashes a \"Hardware Error - Incompatible software\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [computer] flashes a \"Hardware Error - Incompatible software\" warning."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -109,7 +126,7 @@
|
||||
if(!access_to_check) // No required_access, allow it.
|
||||
return TRUE
|
||||
|
||||
if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
|
||||
if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
|
||||
return TRUE
|
||||
|
||||
if(IsAdminGhost(user))
|
||||
@@ -127,14 +144,14 @@
|
||||
|
||||
if(!D)
|
||||
if(loud)
|
||||
to_chat(user, "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning."))
|
||||
return FALSE
|
||||
access = D.GetAccess()
|
||||
|
||||
if(access_to_check in access)
|
||||
return TRUE
|
||||
if(loud)
|
||||
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>")
|
||||
to_chat(user, span_danger("\The [computer] flashes an \"Access Denied\" warning."))
|
||||
return FALSE
|
||||
|
||||
// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones
|
||||
@@ -219,7 +236,7 @@
|
||||
program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
computer.active_program = null
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
ui.close()
|
||||
|
||||
if(user && istype(user))
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
/datum/computer_file/program/proc/event_networkfailure(background)
|
||||
kill_program(forced = TRUE)
|
||||
if(background)
|
||||
computer.visible_message("<span class='danger'>\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error</span>")
|
||||
computer.visible_message(span_danger("\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error"))
|
||||
else
|
||||
computer.visible_message("<span class='danger'>\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.</span>")
|
||||
computer.visible_message(span_danger("\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error."))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/aidiag
|
||||
filename = "aidiag"
|
||||
filedesc = "NT FRK"
|
||||
category = PROGRAM_CATEGORY_ROBO
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "Firmware Restoration Kit, capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot."
|
||||
size = 12
|
||||
@@ -55,7 +56,7 @@
|
||||
|
||||
/datum/computer_file/program/aidiag/process_tick()
|
||||
. = ..()
|
||||
if(!restoring) //Put the check here so we don't check for an ai all the time
|
||||
if(!restoring) //Put the check here so we don't check for an ai all the time
|
||||
return
|
||||
var/obj/item/aicard/cardhold = get_ai(2)
|
||||
|
||||
@@ -64,7 +65,7 @@
|
||||
|
||||
var/mob/living/silicon/ai/A = get_ai()
|
||||
if(!A || !cardhold)
|
||||
restoring = FALSE // If the AI was removed, stop the restoration sequence.
|
||||
restoring = FALSE // If the AI was removed, stop the restoration sequence.
|
||||
if(ai_slot)
|
||||
ai_slot.locked = FALSE
|
||||
return
|
||||
@@ -84,7 +85,7 @@
|
||||
|
||||
if(A.health >= 0 && A.stat == DEAD)
|
||||
A.revive(full_heal = FALSE, admin_revive = FALSE)
|
||||
cardhold.update_icon()
|
||||
cardhold.update_appearance()
|
||||
|
||||
// Finished restoring
|
||||
if(A.health >= 100)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/contract_uplink
|
||||
filename = "contractor uplink"
|
||||
filedesc = "Syndicate Contractor Uplink"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "assign"
|
||||
extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field."
|
||||
size = 10
|
||||
@@ -91,9 +92,9 @@
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.put_in_hands(crystals))
|
||||
to_chat(H, "<span class='notice'>Your payment materializes into your hands!</span>")
|
||||
to_chat(H, span_notice("Your payment materializes into your hands!"))
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Your payment materializes onto the floor.</span>")
|
||||
to_chat(user, span_notice("Your payment materializes onto the floor."))
|
||||
|
||||
hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem
|
||||
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0
|
||||
@@ -164,6 +165,11 @@
|
||||
))
|
||||
|
||||
for (var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts)
|
||||
if(!contract.contract)
|
||||
stack_trace("Syndiate contract with null contract objective found in [traitor_data.owner]'s contractor hub!")
|
||||
contract.status = CONTRACT_STATUS_ABORTED
|
||||
continue
|
||||
|
||||
data["contracts"] += list(list(
|
||||
"target" = contract.contract.target,
|
||||
"target_rank" = contract.target_rank,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/ntnet_dos
|
||||
filename = "ntn_dos"
|
||||
filedesc = "DoS Traffic Generator"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "hostile"
|
||||
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
|
||||
size = 20
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/revelation
|
||||
filename = "revelation"
|
||||
filedesc = "Revelation"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "hostile"
|
||||
extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution."
|
||||
size = 13
|
||||
@@ -20,13 +21,13 @@
|
||||
if(computer)
|
||||
if(istype(computer, /obj/item/modular_computer/tablet/integrated)) //If this is a borg's integrated tablet
|
||||
var/obj/item/modular_computer/tablet/integrated/modularInterface = computer
|
||||
to_chat(modularInterface.borgo,"<span class='userdanger'>SYSTEM PURGE DETECTED/</span>")
|
||||
to_chat(modularInterface.borgo,span_userdanger("SYSTEM PURGE DETECTED/"))
|
||||
addtimer(CALLBACK(modularInterface.borgo, /mob/living/silicon/robot/.proc/death), 2 SECONDS, TIMER_UNIQUE)
|
||||
return
|
||||
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.</span>")
|
||||
computer.visible_message(span_notice("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard."))
|
||||
computer.enabled = FALSE
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
|
||||
var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL]
|
||||
var/obj/item/computer_hardware/recharger/recharger = computer.all_components[MC_CHARGE]
|
||||
@@ -34,13 +35,13 @@
|
||||
computer.take_damage(25, BRUTE, 0, 0)
|
||||
if(battery_module && prob(25))
|
||||
qdel(battery_module)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s battery explodes in rain of sparks.</span>")
|
||||
computer.visible_message(span_notice("\The [computer]'s battery explodes in rain of sparks."))
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.start()
|
||||
|
||||
if(recharger && prob(50))
|
||||
qdel(recharger)
|
||||
computer.visible_message("<span class='notice'>\The [computer]'s recharger explodes in rain of sparks.</span>")
|
||||
computer.visible_message(span_notice("\The [computer]'s recharger explodes in rain of sparks."))
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.start()
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
game_active = FALSE
|
||||
program_icon_state = "arcade_off"
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
ticket_count += 1
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, 50)
|
||||
sleep(10)
|
||||
@@ -42,7 +42,7 @@
|
||||
game_active = FALSE
|
||||
program_icon_state = "arcade_off"
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, 10)
|
||||
sleep(10)
|
||||
|
||||
@@ -150,20 +150,20 @@
|
||||
return TRUE
|
||||
if("Dispense_Tickets")
|
||||
if(!printer)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to redeem tickets.</span>")
|
||||
to_chat(usr, span_notice("Hardware error: A printer is required to redeem tickets."))
|
||||
return
|
||||
if(printer.stored_paper <= 0)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
|
||||
to_chat(usr, span_notice("Hardware error: Printer is out of paper."))
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
computer.visible_message(span_notice("\The [computer] prints out paper."))
|
||||
if(ticket_count >= 1)
|
||||
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
|
||||
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
|
||||
to_chat(usr, span_notice("[computer] dispenses a ticket!"))
|
||||
ticket_count -= 1
|
||||
printer.stored_paper -= 1
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You don't have any stored tickets!</span>")
|
||||
to_chat(usr, span_notice("You don't have any stored tickets!"))
|
||||
return TRUE
|
||||
if("Start_Game")
|
||||
game_active = TRUE
|
||||
@@ -175,4 +175,4 @@
|
||||
boss_id = rand(1,6)
|
||||
pause_state = FALSE
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/atmosscan
|
||||
filename = "atmosscan"
|
||||
filedesc = "AtmoZphere"
|
||||
category = PROGRAM_CATEGORY_ENGI
|
||||
program_icon_state = "air"
|
||||
extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device."
|
||||
size = 4
|
||||
@@ -12,7 +13,7 @@
|
||||
if (!.)
|
||||
return
|
||||
if(!computer?.get_modular_computer_part(MC_SENSORS)) //Giving a clue to users why the program is spitting out zeros.
|
||||
to_chat(user, "<span class='warning'>\The [computer] flashes an error: \"hardware\\sensorpackage\\startup.bin -- file not found\".</span>")
|
||||
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\sensorpackage\\startup.bin -- file not found\"."))
|
||||
|
||||
|
||||
/datum/computer_file/program/atmosscan/ui_data(mob/user)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/borg_monitor
|
||||
filename = "siliconnect"
|
||||
filedesc = "SiliConnect"
|
||||
category = PROGRAM_CATEGORY_ROBO
|
||||
ui_header = "borg_mon.gif"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows for remote monitoring of station cyborgs."
|
||||
@@ -9,6 +10,70 @@
|
||||
size = 5
|
||||
tgui_id = "NtosCyborgRemoteMonitor"
|
||||
program_icon = "project-diagram"
|
||||
var/emagged = FALSE ///Bool of if this app has already been emagged
|
||||
var/list/loglist = list() ///A list to copy a borg's IC log list into
|
||||
var/mob/living/silicon/robot/DL_source ///reference of a borg if we're downloading a log, or null if not.
|
||||
var/DL_progress = -1 ///Progress of current download, 0 to 100, -1 for no current download
|
||||
|
||||
/datum/computer_file/program/borg_monitor/Destroy()
|
||||
loglist = null
|
||||
DL_source = null
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/borg_monitor/kill_program(forced = FALSE)
|
||||
loglist = null //Not everything is saved if you close an app
|
||||
DL_source = null
|
||||
DL_progress = 0
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/borg_monitor/run_emag()
|
||||
if(emagged)
|
||||
return FALSE
|
||||
emagged = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/borg_monitor/tap(atom/A, mob/living/user, params)
|
||||
var/mob/living/silicon/robot/borgo = A
|
||||
if(!istype(borgo) || !borgo.modularInterface)
|
||||
return FALSE
|
||||
DL_source = borgo
|
||||
DL_progress = 0
|
||||
|
||||
var/username = "unknown user"
|
||||
var/obj/item/card/id/stored_card = computer.GetID()
|
||||
if(istype(stored_card) && stored_card.registered_name)
|
||||
username = "user [stored_card.registered_name]"
|
||||
to_chat(borgo, span_userdanger("Request received from [username] for the system log file. Upload in progress."))//Damning evidence may be contained, so warn the borg
|
||||
borgo.logevent("File request by [username]: /var/logs/syslog")
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/borg_monitor/process_tick()
|
||||
if(!DL_source)
|
||||
DL_progress = -1
|
||||
return
|
||||
|
||||
var/turf/here = get_turf(computer)
|
||||
var/turf/there = get_turf(DL_source)
|
||||
if(!here.Adjacent(there))//If someone walked away, cancel the download
|
||||
to_chat(DL_source, span_danger("Log upload failed: general connection error."))//Let the borg know the upload stopped
|
||||
DL_source = null
|
||||
DL_progress = -1
|
||||
return
|
||||
|
||||
if(DL_progress == 100)
|
||||
if(!DL_source || !DL_source.modularInterface) //sanity check, in case the borg or their modular tablet poofs somehow
|
||||
loglist = list("System log of unit [DL_source.name]")
|
||||
loglist += "Error -- Download corrupted."
|
||||
else
|
||||
loglist = DL_source.modularInterface.borglog.Copy()
|
||||
loglist.Insert(1,"System log of unit [DL_source.name]")
|
||||
DL_progress = -1
|
||||
DL_source = null
|
||||
for(var/datum/tgui/window in SStgui.open_uis_by_src[REF(src)])
|
||||
window.send_full_update()
|
||||
return
|
||||
|
||||
DL_progress += 25
|
||||
|
||||
/datum/computer_file/program/borg_monitor/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
@@ -32,15 +97,22 @@
|
||||
|
||||
var/list/cyborg_data = list(
|
||||
name = R.name,
|
||||
integ = round((R.health + 100) / 2), //mob heath is -100 to 100, we want to scale that to 0 - 100
|
||||
locked_down = R.locked_down,
|
||||
status = R.stat,
|
||||
shell_discon = shell,
|
||||
charge = R.cell ? round(R.cell.percent()) : null,
|
||||
module = R.module ? "[R.module.name] Module" : "No Module Detected",
|
||||
module = R.module ? "[R.module.name] Model" : "No Model Detected",
|
||||
upgrades = upgrade,
|
||||
ref = REF(R)
|
||||
)
|
||||
data["cyborgs"] += list(cyborg_data)
|
||||
data["DL_progress"] = DL_progress
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/borg_monitor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["borglog"] = loglist
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/borg_monitor/ui_act(action, params)
|
||||
@@ -57,16 +129,16 @@
|
||||
if(!ID)
|
||||
return
|
||||
if(R.stat == DEAD) //Dead borgs will listen to you no longer
|
||||
to_chat(usr, "<span class='warn'>Error -- Could not open a connection to unit:[R]</span>")
|
||||
to_chat(usr, span_warning("Error -- Could not open a connection to unit:[R]"))
|
||||
var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message")
|
||||
if(!message)
|
||||
return
|
||||
to_chat(R, "<br><br><span class='notice'>Message from [ID] -- \"[message]\"</span><br>")
|
||||
to_chat(R, "<br><br>[span_notice("Message from [ID] -- \"[message]\"")]<br>")
|
||||
to_chat(usr, "Message sent to [R]: [message]")
|
||||
R.logevent("Message from [ID] -- \"[message]\"")
|
||||
SEND_SOUND(R, 'sound/machines/twobeep_high.ogg')
|
||||
if(R.connected_ai)
|
||||
to_chat(R.connected_ai, "<br><br><span class='notice'>Message from [ID] to [R] -- \"[message]\"</span><br>")
|
||||
to_chat(R.connected_ai, "<br><br>[span_notice("Message from [ID] to [R] -- \"[message]\"")]<br>")
|
||||
SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg')
|
||||
usr.log_talk(message, LOG_PDA, tag="Cyborg Monitor Program: ID name \"[ID]\" to [R]")
|
||||
|
||||
@@ -82,12 +154,15 @@
|
||||
/datum/computer_file/program/borg_monitor/proc/checkID()
|
||||
var/obj/item/card/id/ID = computer.GetID()
|
||||
if(!ID)
|
||||
if(emagged)
|
||||
return "STDERR:UNDF"
|
||||
return FALSE
|
||||
return ID.registered_name
|
||||
|
||||
/datum/computer_file/program/borg_monitor/syndicate
|
||||
filename = "roboverlord"
|
||||
filedesc = "Roboverlord"
|
||||
category = PROGRAM_CATEGORY_ROBO
|
||||
ui_header = "borg_mon.gif"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
|
||||
@@ -97,6 +172,9 @@
|
||||
transfer_access = null
|
||||
tgui_id = "NtosCyborgRemoteMonitorSyndicate"
|
||||
|
||||
/datum/computer_file/program/borg_monitor/syndicate/run_emag()
|
||||
return FALSE
|
||||
|
||||
/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R)
|
||||
if((get_turf(computer)).z != (get_turf(R)).z)
|
||||
return FALSE
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/bounty_board
|
||||
filename = "bountyboard"
|
||||
filedesc = "Bounty Board Request Network"
|
||||
category = PROGRAM_CATEGORY_SUPL
|
||||
program_icon_state = "bountyboard"
|
||||
extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.."
|
||||
requires_ntnet = TRUE
|
||||
|
||||
@@ -1,41 +1,50 @@
|
||||
/datum/computer_file/program/budgetorders
|
||||
filename = "orderapp"
|
||||
filedesc = "NT IRN"
|
||||
// category = PROGRAM_CATEGORY_SUPL
|
||||
category = PROGRAM_CATEGORY_SUPL
|
||||
program_icon_state = "request"
|
||||
extended_desc = "Nanotrasen Internal Requisition Network interface for supply purchasing using a department budget account."
|
||||
requires_ntnet = TRUE
|
||||
transfer_access = ACCESS_HEADS
|
||||
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET
|
||||
size = 20
|
||||
tgui_id = "NtosCargo"
|
||||
///Are you actually placing orders with it?
|
||||
var/requestonly = TRUE
|
||||
///Can the tablet see or buy illegal stuff?
|
||||
var/contraband_view = FALSE
|
||||
var/contraband = FALSE
|
||||
///Is it being bought from a personal account, or is it being done via a budget/cargo?
|
||||
var/self_paid = FALSE
|
||||
///Can this console approve purchase requests?
|
||||
var/can_approve_requests = FALSE
|
||||
///What do we say when the shuttle moves with living beings on it.
|
||||
var/safety_warning = "For safety reasons, the automated supply shuttle \
|
||||
cannot transport live organisms, human remains, classified nuclear weaponry, \
|
||||
homing beacons or machinery housing any form of artificial intelligence."
|
||||
var/safety_warning = "For safety and ethical reasons, the automated supply shuttle \
|
||||
cannot transport live organisms, human remains, classified nuclear weaponry, mail, \
|
||||
homing beacons, unstable eigenstates or machinery housing any form of artificial intelligence."
|
||||
///If you're being raided by pirates, what do you tell the crew?
|
||||
var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
|
||||
///The name of the shuttle template being used as the cargo shuttle. 'supply' is default and contains critical code. Don't change this unless you know what you're doing.
|
||||
var/cargo_shuttle = "supply"
|
||||
///The docking port called when returning to the station.
|
||||
var/docking_home = "supply_home"
|
||||
///The docking port called when leaving the station.
|
||||
var/docking_away = "supply_away"
|
||||
///If this console can loan the cargo shuttle. Set to false to disable.
|
||||
var/stationcargo = TRUE
|
||||
///The account this console processes and displays. Independent from the account the shuttle processes.
|
||||
var/cargo_account = ACCOUNT_CAR
|
||||
|
||||
/datum/computer_file/program/budgetorders/proc/get_export_categories()
|
||||
. = EXPORT_CARGO
|
||||
|
||||
/datum/computer_file/program/budgetorders/run_emag()
|
||||
if(!contraband_view)
|
||||
contraband_view = TRUE
|
||||
if(!contraband)
|
||||
contraband = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/budgetorders/proc/is_visible_pack(mob/user, paccess_to_check, list/access, contraband)
|
||||
if(issilicon(user)) //Borgs can't buy things.
|
||||
return FALSE
|
||||
if((computer.obj_flags & EMAGGED) || contraband_view)
|
||||
if(computer.obj_flags & EMAGGED)
|
||||
return TRUE
|
||||
else if(contraband) //Hide contrband when non-emagged.
|
||||
return FALSE
|
||||
@@ -64,11 +73,11 @@
|
||||
. = ..()
|
||||
var/list/data = get_header_data()
|
||||
data["location"] = SSshuttle.supply.getStatusText()
|
||||
var/datum/bank_account/buyer = SSeconomy.get_dep_account(ACCOUNT_CAR)
|
||||
var/datum/bank_account/buyer = SSeconomy.get_dep_account(cargo_account)
|
||||
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
|
||||
var/obj/item/card/id/id_card = card_slot?.GetID()
|
||||
if(id_card?.registered_account)
|
||||
if(ACCESS_HEADS in id_card.access)
|
||||
if((ACCESS_HEADS in id_card.access) || (ACCESS_QM in id_card.access))
|
||||
requestonly = FALSE
|
||||
buyer = SSeconomy.get_dep_account(id_card.registered_account.account_job.paycheck_department)
|
||||
can_approve_requests = TRUE
|
||||
@@ -85,14 +94,14 @@
|
||||
data["supplies"] = list()
|
||||
for(var/pack in SSshuttle.supply_packs)
|
||||
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
|
||||
if(!is_visible_pack(usr, P.access , null, P.contraband))
|
||||
if(!is_visible_pack(usr, P.access , null, P.contraband) || P.hidden)
|
||||
continue
|
||||
if(!data["supplies"][P.group])
|
||||
data["supplies"][P.group] = list(
|
||||
"name" = P.group,
|
||||
"packs" = list()
|
||||
)
|
||||
if(((P.hidden || P.contraband) && !contraband_view) || (P.special && !P.special_enabled) || P.DropPodOnly)
|
||||
if((P.hidden && (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.DropPodOnly))
|
||||
continue
|
||||
data["supplies"][P.group]["packs"] += list(list(
|
||||
"name" = P.name,
|
||||
@@ -105,7 +114,7 @@
|
||||
|
||||
//Data regarding the User's capability to buy things.
|
||||
data["has_id"] = id_card
|
||||
data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
|
||||
data["away"] = SSshuttle.supply.getDockedId() == docking_away
|
||||
data["self_paid"] = self_paid
|
||||
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
|
||||
data["loan"] = !!SSshuttle.shuttle_loan
|
||||
@@ -153,15 +162,15 @@
|
||||
if(SSshuttle.supplyBlocked)
|
||||
computer.say(blockade_warning)
|
||||
return
|
||||
if(SSshuttle.supply.getDockedId() == "supply_home")
|
||||
if(SSshuttle.supply.getDockedId() == docking_home)
|
||||
SSshuttle.supply.export_categories = get_export_categories()
|
||||
SSshuttle.moveShuttle("supply", "supply_away", TRUE)
|
||||
SSshuttle.moveShuttle(cargo_shuttle, docking_away, TRUE)
|
||||
computer.say("The supply shuttle is departing.")
|
||||
computer.investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO)
|
||||
else
|
||||
computer.investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO)
|
||||
computer.say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.")
|
||||
SSshuttle.moveShuttle("supply", "supply_home", TRUE)
|
||||
SSshuttle.moveShuttle(cargo_shuttle, docking_home, TRUE)
|
||||
. = TRUE
|
||||
if("loan")
|
||||
if(!SSshuttle.shuttle_loan)
|
||||
@@ -171,7 +180,9 @@
|
||||
return
|
||||
else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
|
||||
return
|
||||
else if(SSshuttle.supply.getDockedId() != "supply_away")
|
||||
else if(SSshuttle.supply.getDockedId() != docking_away)
|
||||
return
|
||||
else if(stationcargo != TRUE)
|
||||
return
|
||||
else
|
||||
SSshuttle.shuttle_loan.loan_shuttle()
|
||||
@@ -184,7 +195,7 @@
|
||||
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
|
||||
if(!istype(pack))
|
||||
return
|
||||
if(((pack.hidden || pack.contraband) && !contraband_view) || pack.DropPodOnly)
|
||||
if((pack.hidden && (pack.contraband && !contraband) || pack.DropPodOnly))
|
||||
return
|
||||
|
||||
var/name = "*None Provided*"
|
||||
@@ -273,7 +284,7 @@
|
||||
self_paid = !self_paid
|
||||
. = TRUE
|
||||
if(.)
|
||||
post_signal("supply")
|
||||
post_signal(cargo_shuttle)
|
||||
|
||||
/datum/computer_file/program/budgetorders/proc/post_signal(command)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/datum/computer_file/program/card_mod
|
||||
filename = "plexagonidwriter"
|
||||
filedesc = "Plexagon Access Management"
|
||||
category = PROGRAM_CATEGORY_CREW
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for programming employee ID cards to access parts of the station."
|
||||
transfer_access = ACCESS_HEADS
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/shipping
|
||||
filename = "shipping"
|
||||
filedesc = "GrandArk Exporter"
|
||||
category = PROGRAM_CATEGORY_SUPL
|
||||
program_icon_state = "shipping"
|
||||
extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping."
|
||||
size = 6
|
||||
@@ -8,8 +9,12 @@
|
||||
program_icon = "tags"
|
||||
///Account used for creating barcodes.
|
||||
var/datum/bank_account/payments_acc
|
||||
///The amount which the tagger will receive for the sale.
|
||||
var/percent_cut = 20
|
||||
///The person who tagged this will receive the sale value multiplied by this number.
|
||||
var/cut_multiplier = 0.5
|
||||
///Maximum value for cut_multiplier.
|
||||
var/cut_max = 0.5
|
||||
///Minimum value for cut_multiplier.
|
||||
var/cut_min = 0.01
|
||||
|
||||
/datum/computer_file/program/shipping/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
@@ -22,7 +27,7 @@
|
||||
data["paperamt"] = printer ? "[printer.stored_paper] / [printer.max_paper]" : null
|
||||
data["card_owner"] = card_slot?.stored_card ? id_card.registered_name : "No Card Inserted."
|
||||
data["current_user"] = payments_acc ? payments_acc.account_holder : null
|
||||
data["barcode_split"] = percent_cut
|
||||
data["barcode_split"] = cut_multiplier * 100
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/shipping/ui_act(action, list/params)
|
||||
@@ -54,20 +59,20 @@
|
||||
if("resetid")
|
||||
payments_acc = null
|
||||
if("setsplit")
|
||||
var/potential_cut = input("How much would you like to payout to the registered card?","Percentage Profit") as num|null
|
||||
percent_cut = potential_cut ? clamp(round(potential_cut, 1), 1, 50) : 20
|
||||
var/potential_cut = input("How much would you like to pay out to the registered card?","Percentage Profit ([round(cut_min*100)]% - [round(cut_max*100)]%)") as num|null
|
||||
cut_multiplier = potential_cut ? clamp(round(potential_cut/100, cut_min), cut_min, cut_max) : initial(cut_multiplier)
|
||||
if("print")
|
||||
if(!printer)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to print barcodes.</span>")
|
||||
to_chat(usr, span_notice("Hardware error: A printer is required to print barcodes."))
|
||||
return
|
||||
if(printer.stored_paper <= 0)
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
|
||||
to_chat(usr, span_notice("Hardware error: Printer is out of paper."))
|
||||
return
|
||||
if(!payments_acc)
|
||||
to_chat(usr, "<span class='notice'>Software error: Please set a current user first.</span>")
|
||||
to_chat(usr, span_notice("Software error: Please set a current user first."))
|
||||
return
|
||||
var/obj/item/barcode/barcode = new /obj/item/barcode(get_turf(ui_host()))
|
||||
barcode.payments_acc = payments_acc
|
||||
barcode.percent_cut = percent_cut
|
||||
barcode.cut_multiplier = cut_multiplier
|
||||
printer.stored_paper--
|
||||
to_chat(usr, "<span class='notice'>The computer prints out a barcode.</span>")
|
||||
to_chat(usr, span_notice("The computer prints out a barcode."))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/crew_manifest
|
||||
filename = "plexagoncrew"
|
||||
filedesc = "Plexagon Crew List"
|
||||
category = PROGRAM_CATEGORY_CREW
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for viewing and printing the current crew manifest"
|
||||
transfer_access = ACCESS_HEADS
|
||||
@@ -44,7 +45,7 @@
|
||||
[GLOB.data_core ? GLOB.data_core.get_manifest() : ""]
|
||||
"}
|
||||
if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time))))
|
||||
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
|
||||
to_chat(usr, span_notice("Hardware error: Printer was unable to print the file. It may be out of paper."))
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out a paper.</span>")
|
||||
computer.visible_message(span_notice("\The [computer] prints out a paper."))
|
||||
|
||||
@@ -38,14 +38,27 @@
|
||||
return
|
||||
RHDD.remove_file(file)
|
||||
return TRUE
|
||||
if("PRG_rename")
|
||||
if("PRG_renamefile")
|
||||
if(!HDD)
|
||||
return
|
||||
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
|
||||
if(!file)
|
||||
return
|
||||
var/newname = params["new_name"]
|
||||
if(!newname)
|
||||
var/newname = reject_bad_name(params["new_name"])
|
||||
if(!newname || newname != params["new_name"])
|
||||
playsound(computer, 'sound/machines/terminal_error.ogg', 25, FALSE)
|
||||
return
|
||||
file.filename = newname
|
||||
return TRUE
|
||||
if("PRG_usbrenamefile")
|
||||
if(!RHDD)
|
||||
return
|
||||
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
|
||||
if(!file)
|
||||
return
|
||||
var/newname = reject_bad_name(params["new_name"])
|
||||
if(!newname || newname != params["new_name"])
|
||||
playsound(computer, 'sound/machines/terminal_error.ogg', 25, FALSE)
|
||||
return
|
||||
file.filename = newname
|
||||
return TRUE
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/// The time since the last job opening was created
|
||||
// GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
|
||||
/datum/computer_file/program/job_management
|
||||
filename = "plexagoncore"
|
||||
filedesc = "Plexagon HR Core"
|
||||
category = PROGRAM_CATEGORY_CREW
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for viewing and changing job slot avalibility."
|
||||
transfer_access = ACCESS_HEADS
|
||||
@@ -14,6 +18,7 @@
|
||||
var/list/blacklisted = list(
|
||||
"AI",
|
||||
"Assistant",
|
||||
"Prisoner",
|
||||
"Cyborg",
|
||||
"Captain",
|
||||
"Head of Personnel",
|
||||
@@ -35,21 +40,25 @@
|
||||
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
|
||||
|
||||
/datum/computer_file/program/job_management/proc/can_open_job(datum/job/job)
|
||||
if(!(job?.title in blacklisted))
|
||||
if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100)))
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
|
||||
return TRUE
|
||||
if(job?.title in blacklisted)
|
||||
return FALSE
|
||||
if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100)))
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/computer_file/program/job_management/proc/can_close_job(datum/job/job)
|
||||
if(!(job?.title in blacklisted))
|
||||
if(job.total_positions > job.current_positions)
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
|
||||
return TRUE
|
||||
if(job?.title in blacklisted)
|
||||
return FALSE
|
||||
if(job.total_positions > job.current_positions)
|
||||
var/delta = (world.time / 10) - GLOB.time_last_changed_position
|
||||
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui)
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -68,9 +77,10 @@
|
||||
if(!j || !can_open_job(j))
|
||||
return
|
||||
if(opened_positions[edit_job_target] >= 0)
|
||||
GLOB.time_last_changed_position = world.time / 10 // global cd
|
||||
GLOB.time_last_changed_position = world.time / 10
|
||||
j.total_positions++
|
||||
opened_positions[edit_job_target]++
|
||||
log_game("[key_name(usr)] opened a [j.title] job position, for a total of [j.total_positions] open job slots.")
|
||||
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
return TRUE
|
||||
if("PRG_close_job")
|
||||
@@ -83,21 +93,23 @@
|
||||
GLOB.time_last_changed_position = world.time / 10
|
||||
j.total_positions--
|
||||
opened_positions[edit_job_target]--
|
||||
log_game("[key_name(usr)] closed a [j.title] job position, leaving [j.total_positions] open job slots.")
|
||||
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
return TRUE
|
||||
if("PRG_priority")
|
||||
if(length(SSjob.prioritized_jobs) >= 5)
|
||||
return
|
||||
var/priority_target = params["target"]
|
||||
var/datum/job/j = SSjob.GetJob(priority_target)
|
||||
if(!j)
|
||||
if(!j || (j?.title in blacklisted))
|
||||
return
|
||||
if(j.total_positions <= j.current_positions)
|
||||
return
|
||||
if(j in SSjob.prioritized_jobs)
|
||||
SSjob.prioritized_jobs -= j
|
||||
else
|
||||
SSjob.prioritized_jobs += j
|
||||
if(length(SSjob.prioritized_jobs) < 5)
|
||||
SSjob.prioritized_jobs += j
|
||||
else
|
||||
computer.say("Error: CentCom employment protocols restrict prioritising more than 5 jobs.")
|
||||
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
var/emagged = FALSE
|
||||
var/list/main_repo
|
||||
var/list/antag_repo
|
||||
var/list/show_categories = list(
|
||||
PROGRAM_CATEGORY_CREW,
|
||||
PROGRAM_CATEGORY_ENGI,
|
||||
PROGRAM_CATEGORY_ROBO,
|
||||
PROGRAM_CATEGORY_SUPL,
|
||||
PROGRAM_CATEGORY_MISC,
|
||||
)
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/run_program()
|
||||
. = ..()
|
||||
@@ -146,39 +153,29 @@
|
||||
var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD]
|
||||
data["disk_size"] = hard_drive.max_capacity
|
||||
data["disk_used"] = hard_drive.used_capacity
|
||||
var/list/all_entries[0]
|
||||
for(var/A in main_repo)
|
||||
var/datum/computer_file/program/P = A
|
||||
// Only those programs our user can run will show in the list
|
||||
if(hard_drive.find_file_by_name(P.filename))
|
||||
continue
|
||||
all_entries.Add(list(list(
|
||||
data["emagged"] = emagged
|
||||
|
||||
var/list/repo = antag_repo | main_repo
|
||||
var/list/program_categories = list()
|
||||
|
||||
for(var/I in repo)
|
||||
var/datum/computer_file/program/P = I
|
||||
if(!(P.category in program_categories))
|
||||
program_categories.Add(P.category)
|
||||
data["programs"] += list(list(
|
||||
"icon" = P.program_icon,
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"compatibility" = check_compatibility(P),
|
||||
"category" = P.category,
|
||||
"installed" = !!hard_drive.find_file_by_name(P.filename),
|
||||
"compatible" = check_compatibility(P),
|
||||
"size" = P.size,
|
||||
"access" = P.can_run(user,transfer = 1, access = access)
|
||||
)))
|
||||
data["hackedavailable"] = FALSE
|
||||
if(emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
var/list/hacked_programs[0]
|
||||
for(var/S in antag_repo)
|
||||
var/datum/computer_file/program/P = S
|
||||
if(hard_drive.find_file_by_name(P.filename))
|
||||
continue
|
||||
data["hackedavailable"] = TRUE
|
||||
hacked_programs.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"compatibility" = check_compatibility(P),
|
||||
"size" = P.size,
|
||||
"access" = TRUE,
|
||||
)))
|
||||
data["hacked_programs"] = hacked_programs
|
||||
"access" = emagged && P.available_on_syndinet ? TRUE : P.can_run(user,transfer = 1, access = access),
|
||||
"verifiedsource" = P.available_on_ntnet,
|
||||
))
|
||||
|
||||
data["downloadable_programs"] = all_entries
|
||||
data["categories"] = show_categories & program_categories
|
||||
|
||||
return data
|
||||
|
||||
@@ -186,8 +183,8 @@
|
||||
var/hardflag = computer.hardware_flag
|
||||
|
||||
if(P?.is_supported_by_hardware(hardflag,0))
|
||||
return "Compatible"
|
||||
return "Incompatible!"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/kill_program(forced)
|
||||
abort_file_download()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/datum/computer_file/program/ntnetmonitor
|
||||
filename = "wirecarp"
|
||||
filedesc = "WireCarp"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "comm_monitor"
|
||||
extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes"
|
||||
size = 12
|
||||
requires_ntnet = TRUE
|
||||
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
|
||||
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
|
||||
available_on_ntnet = TRUE
|
||||
tgui_id = "NtosNetMonitor"
|
||||
program_icon = "network-wired"
|
||||
|
||||
@@ -1,25 +1,36 @@
|
||||
|
||||
/datum/computer_file/program/chatclient
|
||||
filename = "ntnrc_client"
|
||||
filedesc = "Chat Client"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "command"
|
||||
extended_desc = "This program allows communication over NTNRC network"
|
||||
size = 8
|
||||
requires_ntnet = 1
|
||||
requires_ntnet = TRUE
|
||||
requires_ntnet_feature = NTNET_COMMUNICATION
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
available_on_ntnet = 1
|
||||
available_on_ntnet = TRUE
|
||||
tgui_id = "NtosNetChat"
|
||||
program_icon = "comment-alt"
|
||||
var/last_message // Used to generate the toolbar icon
|
||||
alert_able = TRUE
|
||||
var/last_message // Used to generate the toolbar icon
|
||||
var/username
|
||||
var/active_channel
|
||||
var/list/channel_history = list()
|
||||
var/operator_mode = FALSE // Channel operator mode
|
||||
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
|
||||
var/operator_mode = FALSE // Channel operator mode
|
||||
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
|
||||
//A list of all the converstations we're a part of
|
||||
var/list/datum/ntnet_conversation/conversations = list()
|
||||
|
||||
/datum/computer_file/program/chatclient/New()
|
||||
username = "DefaultUser[rand(100, 999)]"
|
||||
|
||||
/datum/computer_file/program/chatclient/Destroy()
|
||||
for(var/datum/ntnet_conversation/discussion as anything in conversations)
|
||||
discussion.purge_client(src)
|
||||
conversations.Cut()
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/chatclient/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -36,7 +47,7 @@
|
||||
var/message = reject_bad_text(params["message"])
|
||||
if(!message)
|
||||
return
|
||||
if(channel.password && !(src in channel.clients))
|
||||
if(channel.password && (!(src in channel.active_clients) && !(src in channel.offline_clients)))
|
||||
if(channel.password == message)
|
||||
channel.add_client(src)
|
||||
return TRUE
|
||||
@@ -56,7 +67,7 @@
|
||||
|
||||
active_channel = new_target
|
||||
channel = SSnetworks.station_network.get_chat_channel_by_id(new_target)
|
||||
if(!(src in channel.clients) && !channel.password)
|
||||
if((!(src in channel.active_clients) && !(src in channel.offline_clients)) && !channel.password)
|
||||
channel.add_client(src)
|
||||
return TRUE
|
||||
if("PRG_leavechannel")
|
||||
@@ -89,12 +100,12 @@
|
||||
return TRUE
|
||||
if("PRG_changename")
|
||||
var/newname = sanitize(params["new_name"])
|
||||
if(!newname)
|
||||
newname = replacetext(newname, " ", "_")
|
||||
if(!newname || newname == username)
|
||||
return
|
||||
for(var/C in SSnetworks.station_network.chat_channels)
|
||||
var/datum/ntnet_conversation/chan = C
|
||||
if(src in chan.clients)
|
||||
chan.add_status_message("[username] is now known as [newname].")
|
||||
for(var/datum/ntnet_conversation/anychannel as anything in SSnetworks.station_network.chat_channels)
|
||||
if(src in anychannel.active_clients)
|
||||
anychannel.add_status_message("[username] is now known as [newname].")
|
||||
username = newname
|
||||
return TRUE
|
||||
if("PRG_savelog")
|
||||
@@ -117,9 +128,9 @@
|
||||
// This program shouldn't even be runnable without computer.
|
||||
CRASH("Var computer is null!")
|
||||
if(!hard_drive)
|
||||
computer.visible_message("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.</span>")
|
||||
else // In 99.9% cases this will mean our HDD is full
|
||||
computer.visible_message("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.</span>")
|
||||
computer.visible_message(span_warning("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning."))
|
||||
else // In 99.9% cases this will mean our HDD is full
|
||||
computer.visible_message(span_warning("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning."))
|
||||
return TRUE
|
||||
if("PRG_renamechannel")
|
||||
if(!authed)
|
||||
@@ -145,6 +156,18 @@
|
||||
|
||||
channel.password = new_password
|
||||
return TRUE
|
||||
if("PRG_mute_user")
|
||||
if(!authed)
|
||||
return
|
||||
var/datum/computer_file/program/chatclient/muted = locate(params["ref"]) in channel.active_clients + channel.offline_clients
|
||||
channel.mute_user(src, muted)
|
||||
return TRUE
|
||||
if("PRG_ping_user")
|
||||
if(!authed)
|
||||
return
|
||||
var/datum/computer_file/program/chatclient/pinged = locate(params["ref"]) in channel.active_clients + channel.offline_clients
|
||||
channel.ping_user(src, pinged)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
. = ..()
|
||||
@@ -162,10 +185,19 @@
|
||||
else
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
|
||||
/datum/computer_file/program/chatclient/run_program(mob/living/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
for(var/datum/ntnet_conversation/channel as anything in SSnetworks.station_network.chat_channels)
|
||||
if(src in channel.offline_clients)
|
||||
channel.offline_clients.Remove(src)
|
||||
channel.active_clients.Add(src)
|
||||
|
||||
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
|
||||
for(var/C in SSnetworks.station_network.chat_channels)
|
||||
var/datum/ntnet_conversation/channel = C
|
||||
channel.remove_client(src)
|
||||
for(var/datum/ntnet_conversation/channel as anything in SSnetworks.station_network.chat_channels)
|
||||
channel.go_offline(src)
|
||||
active_channel = null
|
||||
..()
|
||||
|
||||
/datum/computer_file/program/chatclient/ui_static_data(mob/user)
|
||||
@@ -192,6 +224,7 @@
|
||||
data["all_channels"] = all_channels
|
||||
|
||||
data["active_channel"] = active_channel
|
||||
data["selfref"] = REF(src) //used to verify who is you, as usernames can be copied.
|
||||
data["username"] = username
|
||||
data["adminmode"] = netadmin_mode
|
||||
var/datum/ntnet_conversation/channel = SSnetworks.station_network.get_chat_channel_by_id(active_channel)
|
||||
@@ -203,21 +236,25 @@
|
||||
if(netadmin_mode)
|
||||
authed = TRUE
|
||||
var/list/clients = list()
|
||||
for(var/C in channel.clients)
|
||||
if(C == src)
|
||||
for(var/datum/computer_file/program/chatclient/channel_client as anything in channel.active_clients + channel.offline_clients)
|
||||
if(channel_client == src)
|
||||
authed = TRUE
|
||||
var/datum/computer_file/program/chatclient/cl = C
|
||||
clients.Add(list(list(
|
||||
"name" = cl.username
|
||||
"name" = channel_client.username,
|
||||
"status" = channel_client.program_state,
|
||||
"muted" = (channel_client in channel.muted_clients),
|
||||
"operator" = channel.operator == channel_client,
|
||||
"ref" = REF(channel_client)
|
||||
)))
|
||||
data["authed"] = authed
|
||||
//no fishing for ui data allowed
|
||||
if(authed)
|
||||
data["strong"] = channel.strong
|
||||
data["clients"] = clients
|
||||
var/list/messages = list()
|
||||
for(var/M in channel.messages)
|
||||
for(var/message in channel.messages)
|
||||
messages.Add(list(list(
|
||||
"msg" = M
|
||||
"msg" = message
|
||||
)))
|
||||
data["messages"] = messages
|
||||
data["is_operator"] = (channel.operator == src) || netadmin_mode
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
///how much paper it takes from the printer to create a canvas.
|
||||
#define CANVAS_PAPER_COST 10
|
||||
|
||||
/**
|
||||
* ## portrait printer!
|
||||
*
|
||||
* Program that lets the curator browse all of the portraits in the database
|
||||
* They are free to print them out as they please.
|
||||
*/
|
||||
/datum/computer_file/program/portrait_printer
|
||||
filename = "PortraitPrinter"
|
||||
filedesc = "Marlowe Treeby's Art Galaxy"
|
||||
category = PROGRAM_CATEGORY_CREW
|
||||
program_icon_state = "dummy"
|
||||
extended_desc = "This program connects to a Spinward Sector community art site for viewing and printing art."
|
||||
transfer_access = ACCESS_LIBRARY
|
||||
usage_flags = PROGRAM_CONSOLE
|
||||
requires_ntnet = TRUE
|
||||
size = 9
|
||||
tgui_id = "NtosPortraitPrinter"
|
||||
program_icon = "paint-brush"
|
||||
|
||||
/datum/computer_file/program/portrait_printer/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["library"] = SSpersistence.paintings["library"] ? SSpersistence.paintings["library"] : 0
|
||||
data["library_secure"] = SSpersistence.paintings["library_secure"] ? SSpersistence.paintings["library_secure"] : 0
|
||||
data["library_private"] = SSpersistence.paintings["library_private"] ? SSpersistence.paintings["library_private"] : 0 //i'm gonna regret this, won't i? Yes you should.
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/portrait_printer/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/simple/portraits/library),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_secure),
|
||||
get_asset_datum(/datum/asset/simple/portraits/library_private)
|
||||
)
|
||||
|
||||
/datum/computer_file/program/portrait_printer/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
//printer check!
|
||||
var/obj/item/computer_hardware/printer/printer
|
||||
if(computer)
|
||||
printer = computer.all_components[MC_PRINT]
|
||||
if(!printer)
|
||||
to_chat(usr, span_notice("Hardware error: A printer is required to print a canvas."))
|
||||
return
|
||||
if(printer.stored_paper < CANVAS_PAPER_COST)
|
||||
to_chat(usr, span_notice("Printing error: Your printer needs at least [CANVAS_PAPER_COST] paper to print a canvas."))
|
||||
return
|
||||
printer.stored_paper -= CANVAS_PAPER_COST
|
||||
|
||||
//canvas printing!
|
||||
var/list/tab2key = list(TAB_LIBRARY = "library", TAB_SECURE = "library_secure", TAB_PRIVATE = "library_private")
|
||||
var/folder = tab2key[params["tab"]]
|
||||
var/list/current_list = SSpersistence.paintings[folder]
|
||||
var/list/chosen_portrait = current_list[params["selected"]]
|
||||
var/author = chosen_portrait["author"]
|
||||
var/title = chosen_portrait["title"]
|
||||
var/png = "data/paintings/[folder]/[chosen_portrait["md5"]].png"
|
||||
var/icon/art_icon = new(png)
|
||||
var/obj/item/canvas/printed_canvas
|
||||
var/art_width = art_icon.Width()
|
||||
var/art_height = art_icon.Height()
|
||||
for(var/canvas_type in typesof(/obj/item/canvas))
|
||||
printed_canvas = canvas_type
|
||||
if(initial(printed_canvas.width) == art_width && initial(printed_canvas.height) == art_height)
|
||||
printed_canvas = new canvas_type(get_turf(computer.physical))
|
||||
break
|
||||
printed_canvas.fill_grid_from_icon(art_icon)
|
||||
printed_canvas.generated_icon = art_icon
|
||||
printed_canvas.icon_generated = TRUE
|
||||
printed_canvas.finalized = TRUE
|
||||
printed_canvas.painting_name = title
|
||||
printed_canvas.author_ckey = author
|
||||
printed_canvas.name = "painting - [title]"
|
||||
///this is a copy of something that is already in the database- it should not be able to be saved.
|
||||
printed_canvas.no_save = TRUE
|
||||
printed_canvas.update_icon()
|
||||
to_chat(usr, span_notice("You have printed [title] onto a new canvas."))
|
||||
playsound(computer.physical, 'sound/items/poster_being_created.ogg', 100, TRUE)
|
||||
@@ -3,6 +3,7 @@
|
||||
/datum/computer_file/program/power_monitor
|
||||
filename = "ampcheck"
|
||||
filedesc = "AmpCheck"
|
||||
category = PROGRAM_CATEGORY_ENGI
|
||||
program_icon_state = "power_monitor"
|
||||
extended_desc = "This program connects to sensors around the station to provide information about electrical systems"
|
||||
ui_header = "power_norm.gif"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/radar //generic parent that handles most of the process
|
||||
filename = "genericfinder"
|
||||
filedesc = "debug_finder"
|
||||
category = PROGRAM_CATEGORY_CREW
|
||||
ui_header = "borg_mon.gif" //DEBUG -- new icon before PR
|
||||
program_icon_state = "radarntos"
|
||||
requires_ntnet = TRUE
|
||||
@@ -15,7 +16,7 @@
|
||||
var/atom/selected
|
||||
///Used to store when the next scan is available. Updated by the scan() proc.
|
||||
var/next_scan = 0
|
||||
///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_icon() calls
|
||||
///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_appearance() calls
|
||||
var/last_icon_state = ""
|
||||
///Used by the tgui interface, themed NT or Syndicate.
|
||||
var/arrowstyle = "ntosradarpointer.png"
|
||||
@@ -174,7 +175,7 @@
|
||||
if(!trackable(signal))
|
||||
program_icon_state = "[initial(program_icon_state)]lost"
|
||||
if(last_icon_state != program_icon_state)
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
last_icon_state = program_icon_state
|
||||
return
|
||||
|
||||
@@ -192,7 +193,7 @@
|
||||
program_icon_state = "[initial(program_icon_state)]far"
|
||||
|
||||
if(last_icon_state != program_icon_state)
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
last_icon_state = program_icon_state
|
||||
computer.setDir(get_dir(here_turf, target_turf))
|
||||
|
||||
@@ -241,13 +242,12 @@
|
||||
/datum/computer_file/program/radar/lifeline/trackable(mob/living/carbon/human/humanoid)
|
||||
if(!humanoid || !istype(humanoid))
|
||||
return FALSE
|
||||
if(..() && istype(humanoid.w_uniform, /obj/item/clothing/under))
|
||||
|
||||
var/obj/item/clothing/under/uniform = humanoid.w_uniform
|
||||
if(!uniform.has_sensor || (uniform.sensor_mode < SENSOR_COORDS)) // Suit sensors must be on maximum.
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
if(..())
|
||||
if (istype(humanoid.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/uniform = humanoid.w_uniform
|
||||
if(uniform.has_sensor && uniform.sensor_mode >= SENSOR_COORDS) // Suit sensors must be on maximum
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
////////////////////////
|
||||
//Nuke Disk Finder App//
|
||||
@@ -257,6 +257,7 @@
|
||||
/datum/computer_file/program/radar/fission360
|
||||
filename = "fission360"
|
||||
filedesc = "Fission360"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "radarsyndicate"
|
||||
extended_desc = "This program allows for tracking of nuclear authorization disks and warheads."
|
||||
requires_ntnet = FALSE
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/computer_file/program/robocontrol
|
||||
filename = "botkeeper"
|
||||
filedesc = "BotKeeper"
|
||||
category = PROGRAM_CATEGORY_ROBO
|
||||
program_icon_state = "robot"
|
||||
extended_desc = "A remote controller used for giving basic commands to non-sentient robots."
|
||||
transfer_access = null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/robotact
|
||||
filename = "robotact"
|
||||
filedesc = "RoboTact"
|
||||
category = PROGRAM_CATEGORY_ROBO
|
||||
extended_desc = "A built-in app for cyborg self-management and diagnostics."
|
||||
ui_header = "robotact.gif" //DEBUG -- new icon before PR
|
||||
program_icon_state = "command"
|
||||
@@ -22,7 +23,7 @@
|
||||
|
||||
/datum/computer_file/program/robotact/run_program(mob/living/user)
|
||||
if(!istype(computer, /obj/item/modular_computer/tablet/integrated))
|
||||
to_chat(user, "<span class='warning'>A warning flashes across \the [computer]: Device Incompatible.</span>")
|
||||
to_chat(user, span_warning("A warning flashes across \the [computer]: Device Incompatible."))
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -39,7 +40,7 @@
|
||||
var/mob/living/silicon/robot/borgo = tablet.borgo
|
||||
|
||||
data["name"] = borgo.name
|
||||
data["designation"] = borgo.designation //Borgo module type
|
||||
data["designation"] = borgo.designation //Borgo model type
|
||||
data["masterAI"] = borgo.connected_ai //Master AI
|
||||
|
||||
var/charge = 0
|
||||
@@ -62,7 +63,7 @@
|
||||
data["cover"] = "[borgo.locked? "LOCKED":"UNLOCKED"]"
|
||||
//Ability to move. FAULT if lockdown wire is cut, DISABLED if borg locked, ENABLED otherwise
|
||||
data["locomotion"] = "[borgo.wires.is_cut(WIRE_LOCKDOWN)?"FAULT":"[borgo.locked_down?"DISABLED":"ENABLED"]"]"
|
||||
//Module wire. FAULT if cut, NOMINAL otherwise
|
||||
//Model wire. FAULT if cut, NOMINAL otherwise
|
||||
data["wireModule"] = "[borgo.wires.is_cut(WIRE_RESET_MODULE)?"FAULT":"NOMINAL"]"
|
||||
//DEBUG -- Camera(net) wire. FAULT if cut (or no cameranet camera), DISABLED if pulse-disabled, NOMINAL otherwise
|
||||
data["wireCamera"] = "[!borgo.builtInCamera || borgo.wires.is_cut(WIRE_CAMERA)?"FAULT":"[borgo.builtInCamera.can_use()?"NOMINAL":"DISABLED"]"]"
|
||||
@@ -110,7 +111,7 @@
|
||||
if("alertPower")
|
||||
if(borgo.stat == CONSCIOUS)
|
||||
if(!borgo.cell || !borgo.cell.charge)
|
||||
borgo.visible_message("<span class='notice'>The power warning light on <span class='name'>[borgo]</span> flashes urgently.</span>", \
|
||||
borgo.visible_message(span_notice("The power warning light on [span_name("[borgo]")] flashes urgently."), \
|
||||
"You announce you are operating in low power mode.")
|
||||
playsound(borgo, 'sound/machines/buzz-two.ogg', 50, FALSE)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/datum/computer_file/program/secureye
|
||||
filename = "secureye"
|
||||
filedesc = "SecurEye"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
ui_header = "borg_mon.gif"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows access to standard security camera networks."
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/datum/computer_file/program/signaler
|
||||
filename = "signaler"
|
||||
filedesc = "SignalCommander"
|
||||
category = PROGRAM_CATEGORY_MISC
|
||||
program_icon_state = "signal"
|
||||
extended_desc = "A small built-in frequency app that sends out signaller signals with the appropriate hardware."
|
||||
size = 2
|
||||
tgui_id = "NtosSignaler"
|
||||
program_icon = "satellite-dish"
|
||||
usage_flags = PROGRAM_TABLET | PROGRAM_LAPTOP
|
||||
///What is the saved signal frequency?
|
||||
var/signal_frequency = FREQ_SIGNALER
|
||||
/// What is the saved signal code?
|
||||
var/signal_code = DEFAULT_SIGNALER_CODE
|
||||
/// Radio connection datum used by signalers.
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
/datum/computer_file/program/signaler/run_program(mob/living/user)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
if(!computer?.get_modular_computer_part(MC_SIGNALER)) //Giving a clue to users why the program is spitting out zeros.
|
||||
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\signal_hardware\\startup.bin -- file not found\"."))
|
||||
|
||||
|
||||
/datum/computer_file/program/signaler/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
|
||||
if(sensor?.check_functionality())
|
||||
data["frequency"] = signal_frequency
|
||||
data["code"] = signal_code
|
||||
data["minFrequency"] = MIN_FREE_FREQ
|
||||
data["maxFrequency"] = MAX_FREE_FREQ
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/signaler/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
|
||||
if(!(sensor?.check_functionality()))
|
||||
playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE)
|
||||
return
|
||||
switch(action)
|
||||
if("signal")
|
||||
INVOKE_ASYNC(src, .proc/signal)
|
||||
. = TRUE
|
||||
if("freq")
|
||||
signal_frequency = unformat_frequency(params["freq"])
|
||||
signal_frequency = sanitize_frequency(signal_frequency, TRUE)
|
||||
set_frequency(signal_frequency)
|
||||
. = TRUE
|
||||
if("code")
|
||||
signal_code = text2num(params["code"])
|
||||
signal_code = round(signal_code)
|
||||
. = TRUE
|
||||
if("reset")
|
||||
if(params["reset"] == "freq")
|
||||
signal_frequency = initial(signal_frequency)
|
||||
else
|
||||
signal_code = initial(signal_code)
|
||||
. = TRUE
|
||||
|
||||
/datum/computer_file/program/signaler/proc/signal()
|
||||
if(!radio_connection)
|
||||
return
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
var/logging_data
|
||||
if(usr)
|
||||
logging_data = "[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
|
||||
GLOB.lastsignalers.Add(logging_data)
|
||||
|
||||
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
/datum/computer_file/program/signaler/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, signal_frequency)
|
||||
signal_frequency = new_frequency
|
||||
radio_connection = SSradio.add_object(src, signal_frequency, RADIO_SIGNALER)
|
||||
return
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/computer_file/program/supermatter_monitor
|
||||
filename = "ntcims"
|
||||
filedesc = "NT CIMS"
|
||||
category = PROGRAM_CATEGORY_ENGI
|
||||
ui_header = "smmon_0.gif"
|
||||
program_icon_state = "smmon_0"
|
||||
extended_desc = "Crystal Integrity Monitoring System, connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines."
|
||||
@@ -12,7 +13,7 @@
|
||||
alert_able = TRUE
|
||||
var/last_status = SUPERMATTER_INACTIVE
|
||||
var/list/supermatters
|
||||
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
|
||||
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/Destroy()
|
||||
clear_signals()
|
||||
@@ -27,7 +28,7 @@
|
||||
ui_header = "smmon_[last_status].gif"
|
||||
program_icon_state = "smmon_[last_status]"
|
||||
if(istype(computer))
|
||||
computer.update_icon()
|
||||
computer.update_appearance()
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/run_program(mob/living/user)
|
||||
. = ..(user)
|
||||
@@ -36,11 +37,15 @@
|
||||
refresh()
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
|
||||
for(var/supermatter in supermatters)
|
||||
clear_supermatter(supermatter)
|
||||
supermatters = null
|
||||
..()
|
||||
|
||||
// Refreshes list of active supermatter crystals
|
||||
/datum/computer_file/program/supermatter_monitor/proc/refresh()
|
||||
for(var/supermatter in supermatters)
|
||||
clear_supermatter(supermatter)
|
||||
supermatters = list()
|
||||
var/turf/T = get_turf(ui_host())
|
||||
if(!T)
|
||||
@@ -50,9 +55,7 @@
|
||||
if (!isturf(S.loc) || !(is_station_level(S.z) || is_mining_level(S.z) || S.z == T.z))
|
||||
continue
|
||||
supermatters.Add(S)
|
||||
|
||||
if(!(active in supermatters))
|
||||
active = null
|
||||
RegisterSignal(S, COMSIG_PARENT_QDELETING, .proc/react_to_del)
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/proc/get_status()
|
||||
. = SUPERMATTER_INACTIVE
|
||||
@@ -67,9 +70,9 @@
|
||||
* the signal and exit.
|
||||
*/
|
||||
/datum/computer_file/program/supermatter_monitor/proc/set_signals()
|
||||
// if(active)
|
||||
// RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM, .proc/send_alert, override = TRUE)
|
||||
// RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM, .proc/send_start_alert, override = TRUE)
|
||||
if(active)
|
||||
RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM, .proc/send_alert, override = TRUE)
|
||||
RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM, .proc/send_start_alert, override = TRUE)
|
||||
|
||||
/**
|
||||
* Removes the signal listener for Supermatter delaminations from the selected supermatter.
|
||||
@@ -77,9 +80,9 @@
|
||||
* Pretty much does what it says.
|
||||
*/
|
||||
/datum/computer_file/program/supermatter_monitor/proc/clear_signals()
|
||||
// if(active)
|
||||
// UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM)
|
||||
// UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM)
|
||||
if(active)
|
||||
UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM)
|
||||
UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM)
|
||||
|
||||
/**
|
||||
* Sends an SM delam alert to the computer.
|
||||
@@ -90,6 +93,7 @@
|
||||
* the supermatter probably don't need constant beeping to distract them.
|
||||
*/
|
||||
/datum/computer_file/program/supermatter_monitor/proc/send_alert()
|
||||
SIGNAL_HANDLER
|
||||
if(!computer.get_ntnet_status())
|
||||
return
|
||||
if(computer.active_program != src)
|
||||
@@ -106,12 +110,13 @@
|
||||
* minimized or closed to avoid double-notifications.
|
||||
*/
|
||||
/datum/computer_file/program/supermatter_monitor/proc/send_start_alert()
|
||||
SIGNAL_HANDLER
|
||||
if(!computer.get_ntnet_status())
|
||||
return
|
||||
if(computer.active_program == src)
|
||||
computer.alert_call(src, "Crystal delamination in progress!")
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/ui_data()
|
||||
/datum/computer_file/program/supermatter_monitor/ui_data(mob/user)
|
||||
var/list/data = get_header_data()
|
||||
|
||||
if(istype(active))
|
||||
@@ -125,30 +130,9 @@
|
||||
active = null
|
||||
return
|
||||
|
||||
data["active"] = TRUE
|
||||
data["SM_integrity"] = active.get_integrity()
|
||||
data["SM_power"] = active.power
|
||||
data["SM_ambienttemp"] = air.return_temperature()
|
||||
data["SM_ambientpressure"] = air.return_pressure()
|
||||
//data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01)
|
||||
var/list/gasdata = list()
|
||||
data += active.ui_data()
|
||||
data["singlecrystal"] = FALSE
|
||||
|
||||
|
||||
if(air.total_moles())
|
||||
for(var/gasid in air.get_gases())
|
||||
var/amount = air.get_moles(gasid)
|
||||
if(amount)
|
||||
gasdata.Add(list(list(
|
||||
"name"= GLOB.gas_data.names[gasid],
|
||||
"amount" = round(100*amount/air.total_moles(),0.01))))
|
||||
|
||||
else
|
||||
for(var/gasid in air.get_gases())
|
||||
gasdata.Add(list(list(
|
||||
"name"= GLOB.gas_data.names[gasid],
|
||||
"amount" = 0)))
|
||||
|
||||
data["gases"] = gasdata
|
||||
else
|
||||
var/list/SMS = list()
|
||||
for(var/obj/machinery/power/supermatter_crystal/S in supermatters)
|
||||
@@ -185,3 +169,13 @@
|
||||
active = S
|
||||
set_signals()
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/proc/react_to_del(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
clear_supermatter(source)
|
||||
|
||||
/datum/computer_file/program/supermatter_monitor/proc/clear_supermatter(matter)
|
||||
supermatters -= matter
|
||||
if(matter == active)
|
||||
active = null
|
||||
UnregisterSignal(matter, COMSIG_PARENT_QDELETING)
|
||||
|
||||
@@ -4,22 +4,34 @@
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "std_mod"
|
||||
|
||||
w_class = WEIGHT_CLASS_TINY // w_class limits which devices can contain this component.
|
||||
w_class = WEIGHT_CLASS_TINY // w_class limits which devices can contain this component.
|
||||
// 1: PDAs/Tablets, 2: Laptops, 3-4: Consoles only
|
||||
var/obj/item/modular_computer/holder = null
|
||||
// Computer that holds this hardware, if any.
|
||||
|
||||
var/power_usage = 0 // If the hardware uses extra power, change this.
|
||||
var/enabled = TRUE // If the hardware is turned off set this to 0.
|
||||
var/critical = FALSE // Prevent disabling for important component, like the CPU.
|
||||
var/can_install = TRUE // Prevents direct installation of removable media.
|
||||
var/expansion_hw = FALSE // Hardware that fits into expansion bays.
|
||||
var/removable = TRUE // Whether the hardware is removable or not.
|
||||
var/damage = 0 // Current damage level
|
||||
var/max_damage = 100 // Maximal damage level.
|
||||
var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
|
||||
var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
|
||||
var/malfunction_probability = 10// Chance of malfunction when the component is damaged
|
||||
// If the hardware uses extra power, change this.
|
||||
var/power_usage = 0
|
||||
// If the hardware is turned off set this to 0.
|
||||
var/enabled = TRUE
|
||||
// Prevent disabling for important component, like the CPU.
|
||||
var/critical = FALSE
|
||||
// Prevents direct installation of removable media.
|
||||
var/can_install = TRUE
|
||||
// Hardware that fits into expansion bays.
|
||||
var/expansion_hw = FALSE
|
||||
// Whether the hardware is removable or not.
|
||||
var/removable = TRUE
|
||||
// Current damage level
|
||||
var/damage = 0
|
||||
// Maximal damage level.
|
||||
var/max_damage = 100
|
||||
// "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
|
||||
var/damage_malfunction = 20
|
||||
// "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
|
||||
var/damage_failure = 50
|
||||
// Chance of malfunction when the component is damaged
|
||||
var/malfunction_probability = 10
|
||||
// What define is used to qualify this piece of hardware? Important for upgraded versions of the same hardware.
|
||||
var/device_type
|
||||
|
||||
/obj/item/computer_hardware/New(obj/L)
|
||||
@@ -38,10 +50,10 @@
|
||||
if(istype(I, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/S = I
|
||||
if(obj_integrity == max_integrity)
|
||||
to_chat(user, "<span class='warning'>\The [src] doesn't seem to require repairs.</span>")
|
||||
to_chat(user, span_warning("\The [src] doesn't seem to require repairs."))
|
||||
return 1
|
||||
if(S.use(1))
|
||||
to_chat(user, "<span class='notice'>You patch up \the [src] with a bit of \the [I].</span>")
|
||||
to_chat(user, span_notice("You patch up \the [src] with a bit of \the [I]."))
|
||||
obj_integrity = min(obj_integrity + 10, max_integrity)
|
||||
return 1
|
||||
|
||||
@@ -78,11 +90,11 @@
|
||||
/obj/item/computer_hardware/examine(mob/user)
|
||||
. = ..()
|
||||
if(damage > damage_failure)
|
||||
. += "<span class='danger'>It seems to be severely damaged!</span>"
|
||||
. += span_danger("It seems to be severely damaged!")
|
||||
else if(damage > damage_malfunction)
|
||||
. += "<span class='warning'>It seems to be damaged!</span>"
|
||||
. += span_warning("It seems to be damaged!")
|
||||
else if(damage)
|
||||
. += "<span class='notice'>It seems to be slightly damaged.</span>"
|
||||
. += span_notice("It seems to be slightly damaged.")
|
||||
|
||||
// Component-side compatibility check.
|
||||
/obj/item/computer_hardware/proc/can_install(obj/item/modular_computer/M, mob/living/user = null)
|
||||
@@ -93,8 +105,9 @@
|
||||
return
|
||||
|
||||
// Called when component is removed from PC.
|
||||
/obj/item/computer_hardware/proc/on_remove(obj/item/modular_computer/M, mob/living/user = null)
|
||||
try_eject(forced = TRUE)
|
||||
/obj/item/computer_hardware/proc/on_remove(obj/item/modular_computer/M, mob/living/user)
|
||||
if(M.physical || !QDELETED(M))
|
||||
try_eject(forced = TRUE)
|
||||
|
||||
// Called when someone tries to insert something in it - paper in printer, card in card reader, etc.
|
||||
/obj/item/computer_hardware/proc/try_insert(obj/item/I, mob/living/user = null)
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
device_type = MC_AI
|
||||
expansion_hw = TRUE
|
||||
|
||||
var/obj/item/aicard/stored_card = null
|
||||
var/obj/item/aicard/stored_card
|
||||
var/locked = FALSE
|
||||
|
||||
/obj/item/computer_hardware/ai_slot/handle_atom_del(atom/A)
|
||||
if(A == stored_card)
|
||||
try_eject(forced = TRUE)
|
||||
. = ..()
|
||||
///What happens when the intellicard is removed (or deleted) from the module, through try_eject() or not.
|
||||
/obj/item/computer_hardware/ai_slot/Exited(atom/movable/gone, direction)
|
||||
if(stored_card == gone)
|
||||
stored_card = null
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/ai_slot/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -28,34 +29,33 @@
|
||||
return FALSE
|
||||
|
||||
if(stored_card)
|
||||
to_chat(user, "<span class='warning'>You try to insert \the [I] into \the [src], but the slot is occupied.</span>")
|
||||
to_chat(user, span_warning("You try to insert \the [I] into \the [src], but the slot is occupied."))
|
||||
return FALSE
|
||||
if(user && !user.transferItemToLoc(I, src))
|
||||
return FALSE
|
||||
|
||||
stored_card = I
|
||||
to_chat(user, "<span class='notice'>You insert \the [I] into \the [src].</span>")
|
||||
to_chat(user, span_notice("You insert \the [I] into \the [src]."))
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/computer_hardware/ai_slot/try_eject(mob/living/user = null, forced = FALSE)
|
||||
if(!stored_card)
|
||||
to_chat(user, "<span class='warning'>There is no card in \the [src].</span>")
|
||||
to_chat(user, span_warning("There is no card in \the [src]."))
|
||||
return FALSE
|
||||
|
||||
if(locked && !forced)
|
||||
to_chat(user, "<span class='warning'>Safeties prevent you from removing the card until reconstruction is complete...</span>")
|
||||
to_chat(user, span_warning("Safeties prevent you from removing the card until reconstruction is complete..."))
|
||||
return FALSE
|
||||
|
||||
if(stored_card)
|
||||
to_chat(user, "<span class='notice'>You remove [stored_card] from [src].</span>")
|
||||
to_chat(user, span_notice("You remove [stored_card] from [src]."))
|
||||
locked = FALSE
|
||||
if(user)
|
||||
if(Adjacent(user))
|
||||
user.put_in_hands(stored_card)
|
||||
else
|
||||
stored_card.forceMove(drop_location())
|
||||
stored_card = null
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -64,6 +64,6 @@
|
||||
if(..())
|
||||
return
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
to_chat(user, "<span class='notice'>You press down on the manual eject button with \the [I].</span>")
|
||||
to_chat(user, span_notice("You press down on the manual eject button with \the [I]."))
|
||||
try_eject(user, TRUE)
|
||||
return
|
||||
|
||||
@@ -4,25 +4,28 @@
|
||||
icon_state = "cell_con"
|
||||
critical = 1
|
||||
malfunction_probability = 1
|
||||
var/obj/item/stock_parts/cell/battery = null
|
||||
var/obj/item/stock_parts/cell/battery
|
||||
device_type = MC_CELL
|
||||
|
||||
/obj/item/computer_hardware/battery/get_cell()
|
||||
return battery
|
||||
|
||||
/obj/item/computer_hardware/battery/New(loc, battery_type = null)
|
||||
/obj/item/computer_hardware/battery/Initialize(mapload, battery_type)
|
||||
. = ..()
|
||||
if(battery_type)
|
||||
battery = new battery_type(src)
|
||||
..()
|
||||
|
||||
/obj/item/computer_hardware/battery/Destroy()
|
||||
. = ..()
|
||||
QDEL_NULL(battery)
|
||||
battery = null
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/battery/handle_atom_del(atom/A)
|
||||
if(A == battery)
|
||||
try_eject(forced = TRUE)
|
||||
. = ..()
|
||||
///What happens when the battery is removed (or deleted) from the module, through try_eject() or not.
|
||||
/obj/item/computer_hardware/battery/Exited(atom/movable/gone, direction)
|
||||
if(battery == gone)
|
||||
battery = null
|
||||
if(holder?.enabled && !holder.use_power())
|
||||
holder.shutdown_computer()
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(!holder)
|
||||
@@ -32,46 +35,33 @@
|
||||
return FALSE
|
||||
|
||||
if(battery)
|
||||
to_chat(user, "<span class='warning'>You try to connect \the [I] to \the [src], but its connectors are occupied.</span>")
|
||||
to_chat(user, span_warning("You try to connect \the [I] to \the [src], but its connectors are occupied."))
|
||||
return FALSE
|
||||
|
||||
if(I.w_class > holder.max_hardware_size)
|
||||
to_chat(user, "<span class='warning'>This power cell is too large for \the [holder]!</span>")
|
||||
to_chat(user, span_warning("This power cell is too large for \the [holder]!"))
|
||||
return FALSE
|
||||
|
||||
if(user && !user.transferItemToLoc(I, src))
|
||||
return FALSE
|
||||
|
||||
battery = I
|
||||
to_chat(user, "<span class='notice'>You connect \the [I] to \the [src].</span>")
|
||||
to_chat(user, span_notice("You connect \the [I] to \the [src]."))
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/computer_hardware/battery/try_eject(mob/living/user = null, forced = FALSE)
|
||||
/obj/item/computer_hardware/battery/try_eject(mob/living/user, forced = FALSE)
|
||||
if(!battery)
|
||||
to_chat(user, "<span class='warning'>There is no power cell connected to \the [src].</span>")
|
||||
to_chat(user, span_warning("There is no power cell connected to \the [src]."))
|
||||
return FALSE
|
||||
else
|
||||
if(user)
|
||||
user.put_in_hands(battery)
|
||||
to_chat(user, span_notice("You detach \the [battery] from \the [src]."))
|
||||
else
|
||||
battery.forceMove(drop_location())
|
||||
to_chat(user, "<span class='notice'>You detach \the [battery] from \the [src].</span>")
|
||||
battery = null
|
||||
|
||||
if(holder)
|
||||
if(holder.enabled && !holder.use_power())
|
||||
holder.shutdown_computer()
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/stock_parts/cell/computer
|
||||
name = "standard battery"
|
||||
desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops."
|
||||
@@ -80,7 +70,6 @@
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
maxcharge = 750
|
||||
|
||||
|
||||
/obj/item/stock_parts/cell/computer/advanced
|
||||
name = "advanced battery"
|
||||
desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices."
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
/obj/item/computer_hardware/card_slot
|
||||
name = "primary RFID card module" // \improper breaks the find_hardware_by_name proc
|
||||
name = "primary RFID card module" // \improper breaks the find_hardware_by_name proc
|
||||
desc = "A module allowing this computer to read or write data on ID cards. Necessary for some programs to run properly."
|
||||
power_usage = 10 //W
|
||||
icon_state = "card_mini"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
device_type = MC_CARD
|
||||
|
||||
var/obj/item/card/id/stored_card = null
|
||||
var/obj/item/card/id/stored_card
|
||||
|
||||
/obj/item/computer_hardware/card_slot/handle_atom_del(atom/A)
|
||||
if(A == stored_card)
|
||||
try_eject(null, TRUE)
|
||||
. = ..()
|
||||
///What happens when the ID card is removed (or deleted) from the module, through try_eject() or not.
|
||||
/obj/item/computer_hardware/card_slot/Exited(atom/movable/gone, direction)
|
||||
if(stored_card == gone)
|
||||
stored_card = null
|
||||
if(holder)
|
||||
if(holder.active_program)
|
||||
holder.active_program.event_idremoved(0)
|
||||
for(var/p in holder.idle_threads)
|
||||
var/datum/computer_file/program/computer_program = p
|
||||
computer_program.event_idremoved(1)
|
||||
|
||||
holder.update_slot_icon()
|
||||
|
||||
if(ishuman(holder.loc))
|
||||
var/mob/living/carbon/human/human_wearer = holder.loc
|
||||
if(human_wearer.wear_id == holder)
|
||||
human_wearer.sec_hud_set_ID()
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/card_slot/Destroy()
|
||||
try_eject(forced = TRUE)
|
||||
@@ -47,6 +61,11 @@
|
||||
|
||||
if(stored_card)
|
||||
return FALSE
|
||||
|
||||
// item instead of player is checked so telekinesis will still work if the item itself is close
|
||||
if(!in_range(src, I))
|
||||
return FALSE
|
||||
|
||||
if(user)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return FALSE
|
||||
@@ -54,38 +73,32 @@
|
||||
I.forceMove(src)
|
||||
|
||||
stored_card = I
|
||||
to_chat(user, "<span class='notice'>You insert \the [I] into \the [expansion_hw ? "secondary":"primary"] [src].</span>")
|
||||
to_chat(user, span_notice("You insert \the [I] into \the [expansion_hw ? "secondary":"primary"] [src]."))
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.sec_hud_set_ID()
|
||||
|
||||
var/holder_loc = holder.loc
|
||||
if(ishuman(holder_loc))
|
||||
var/mob/living/carbon/human/human_wearer = holder_loc
|
||||
if(human_wearer.wear_id == holder)
|
||||
human_wearer.sec_hud_set_ID()
|
||||
holder.update_slot_icon()
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/computer_hardware/card_slot/try_eject(mob/living/user = null, forced = FALSE)
|
||||
if(!stored_card)
|
||||
to_chat(user, "<span class='warning'>There are no cards in \the [src].</span>")
|
||||
to_chat(user, span_warning("There are no cards in \the [src]."))
|
||||
return FALSE
|
||||
|
||||
if(user)
|
||||
if(user && !issilicon(user) && in_range(src, user))
|
||||
user.put_in_hands(stored_card)
|
||||
else
|
||||
stored_card.forceMove(drop_location())
|
||||
stored_card = null
|
||||
|
||||
if(holder)
|
||||
if(holder.active_program)
|
||||
holder.active_program.event_idremoved(0)
|
||||
|
||||
for(var/p in holder.idle_threads)
|
||||
var/datum/computer_file/program/computer_program = p
|
||||
computer_program.event_idremoved(1)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
human_user.sec_hud_set_ID()
|
||||
to_chat(user, "<span class='notice'>You remove the card from \the [src].</span>")
|
||||
to_chat(user, span_notice("You remove the card from \the [src]."))
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user)
|
||||
@@ -93,11 +106,11 @@
|
||||
return
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(stored_card)
|
||||
to_chat(user, "<span class='notice'>You press down on the manual eject button with \the [I].</span>")
|
||||
to_chat(user, span_notice("You press down on the manual eject button with \the [I]."))
|
||||
try_eject(user)
|
||||
return
|
||||
swap_slot()
|
||||
to_chat(user, "<span class='notice'>You adjust the connecter to fit into [expansion_hw ? "an expansion bay" : "the primary ID bay"].</span>")
|
||||
to_chat(user, span_notice("You adjust the connecter to fit into [expansion_hw ? "an expansion bay" : "the primary ID bay"]."))
|
||||
|
||||
/**
|
||||
*Swaps the card_slot hardware between using the dedicated card slot bay on a computer, and using an expansion bay.
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
device_type = MC_HDD
|
||||
var/max_capacity = 128
|
||||
var/used_capacity = 0
|
||||
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
|
||||
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/on_remove(obj/item/modular_computer/MC, mob/user)
|
||||
MC.shutdown_computer()
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/proc/install_default_programs()
|
||||
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
|
||||
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
|
||||
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/examine(user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>It has [max_capacity] GQ of storage capacity.</span>"
|
||||
. += span_notice("It has [max_capacity] GQ of storage capacity.")
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/diagnostics(mob/user)
|
||||
..()
|
||||
@@ -117,7 +117,7 @@
|
||||
return null
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/Destroy()
|
||||
stored_files = null
|
||||
QDEL_LIST(stored_files)
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/hard_drive/Initialize()
|
||||
@@ -129,7 +129,7 @@
|
||||
name = "advanced hard disk drive"
|
||||
desc = "A hybrid HDD, for use in higher grade computers where balance between power efficiency and capacity is desired."
|
||||
max_capacity = 256
|
||||
power_usage = 50 // Hybrid, medium capacity and medium power storage
|
||||
power_usage = 50 // Hybrid, medium capacity and medium power storage
|
||||
icon_state = "harddisk_mini"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
name = "super hard disk drive"
|
||||
desc = "A high capacity HDD, for use in cluster storage solutions where capacity is more important than power efficiency."
|
||||
max_capacity = 512
|
||||
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
|
||||
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
|
||||
icon_state = "harddisk_mini"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -161,8 +161,8 @@
|
||||
|
||||
// For borg integrated tablets. No downloader.
|
||||
/obj/item/computer_hardware/hard_drive/small/integrated/install_default_programs()
|
||||
store_file(new /datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new /datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
store_file(new /datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
|
||||
store_file(new /datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
|
||||
store_file(new /datum/computer_file/program/robotact(src))
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
desc = "A basic wireless network card for usage with standard NTNet frequencies."
|
||||
power_usage = 50
|
||||
icon_state = "radio_mini"
|
||||
var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
|
||||
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
|
||||
// network_id = NETWORK_CARDS // Network we are on
|
||||
var/hardware_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
|
||||
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
|
||||
var/long_range = 0
|
||||
var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks.
|
||||
malfunction_probability = 1
|
||||
@@ -13,7 +14,7 @@
|
||||
|
||||
/obj/item/computer_hardware/network_card/diagnostics(mob/user)
|
||||
..()
|
||||
to_chat(user, "NIX Unique ID: [identification_id]")
|
||||
to_chat(user, "NIX Unique ID: [hardware_id]")
|
||||
to_chat(user, "NIX User Tag: [identification_string]")
|
||||
to_chat(user, "Supported protocols:")
|
||||
to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread")
|
||||
@@ -24,11 +25,11 @@
|
||||
|
||||
/obj/item/computer_hardware/network_card/New(l)
|
||||
..()
|
||||
identification_id = ntnet_card_uid++
|
||||
hardware_id = ntnet_card_uid++
|
||||
|
||||
// Returns a string identifier of this network card
|
||||
/obj/item/computer_hardware/network_card/proc/get_network_tag()
|
||||
return "[identification_string] (NID [identification_id])"
|
||||
return "[identification_string] (NID [hardware_id])"
|
||||
|
||||
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
|
||||
/obj/item/computer_hardware/network_card/proc/get_signal(specific_action = 0)
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
/obj/item/computer_hardware/printer/diagnostics(mob/living/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>Paper level: [stored_paper]/[max_paper].</span>")
|
||||
to_chat(user, span_notice("Paper level: [stored_paper]/[max_paper]."))
|
||||
|
||||
/obj/item/computer_hardware/printer/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Paper level: [stored_paper]/[max_paper].</span>"
|
||||
. += span_notice("Paper level: [stored_paper]/[max_paper].")
|
||||
|
||||
|
||||
/obj/item/computer_hardware/printer/proc/print_text(text_to_print, paper_title = "")
|
||||
@@ -33,7 +33,7 @@
|
||||
P.info = text_to_print
|
||||
if(paper_title)
|
||||
P.name = paper_title
|
||||
P.update_icon()
|
||||
P.update_appearance()
|
||||
stored_paper--
|
||||
P = null
|
||||
return TRUE
|
||||
@@ -41,12 +41,12 @@
|
||||
/obj/item/computer_hardware/printer/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(istype(I, /obj/item/paper))
|
||||
if(stored_paper >= max_paper)
|
||||
to_chat(user, "<span class='warning'>You try to add \the [I] into [src], but its paper bin is full!</span>")
|
||||
to_chat(user, span_warning("You try to add \the [I] into [src], but its paper bin is full!"))
|
||||
return FALSE
|
||||
|
||||
if(user && !user.temporarilyRemoveItemFromInventory(I))
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You insert \the [I] into [src]'s paper recycler.</span>")
|
||||
to_chat(user, span_notice("You insert \the [I] into [src]'s paper recycler."))
|
||||
qdel(I)
|
||||
stored_paper++
|
||||
return TRUE
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
/obj/item/computer_hardware/recharger/wired/can_install(obj/item/modular_computer/M, mob/living/user = null)
|
||||
if(ismachinery(M.physical) && M.physical.anchored)
|
||||
return ..()
|
||||
to_chat(user, "<span class='warning'>\The [src] is incompatible with portable computers!</span>")
|
||||
to_chat(user, span_warning("\The [src] is incompatible with portable computers!"))
|
||||
return FALSE
|
||||
|
||||
/obj/item/computer_hardware/recharger/wired/use_power(amount, charging=0)
|
||||
@@ -96,3 +96,4 @@
|
||||
|
||||
/obj/item/computer_hardware/recharger/lambda/use_power(amount, charging=0)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -6,3 +6,12 @@
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
device_type = MC_SENSORS
|
||||
expansion_hw = TRUE
|
||||
|
||||
/obj/item/computer_hardware/radio_card
|
||||
name = "integrated radio card"
|
||||
desc = "An integrated signaling assembly for computers to send an outgoing frequency signal. Required by certain programs."
|
||||
icon_state = "signal_card"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
device_type = MC_SIGNALER
|
||||
expansion_hw = TRUE
|
||||
power_usage = 10
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
var/obj/item/modular_computer/tablet/fabricated_tablet = null
|
||||
|
||||
// Utility vars
|
||||
var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen
|
||||
var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet
|
||||
var/total_price = 0 // Price of currently vended device.
|
||||
var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen
|
||||
var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet
|
||||
var/total_price = 0 // Price of currently vended device.
|
||||
var/credits = 0
|
||||
|
||||
// Device loadout
|
||||
var/dev_cpu = 1 // 1: Default, 2: Upgraded
|
||||
var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range
|
||||
var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY)
|
||||
var/dev_printer = 0 // 0: None, 1: Standard
|
||||
var/dev_card = 0 // 0: None, 1: Standard
|
||||
var/dev_cpu = 1 // 1: Default, 2: Upgraded
|
||||
var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced
|
||||
var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range
|
||||
var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY)
|
||||
var/dev_printer = 0 // 0: None, 1: Standard
|
||||
var/dev_card = 0 // 0: None, 1: Standard
|
||||
|
||||
// Removes all traces of old order and allows you to begin configuration from scratch.
|
||||
/obj/machinery/lapvend/proc/reset_order()
|
||||
@@ -48,7 +48,7 @@
|
||||
// Recalculates the price and optionally even fabricates the device.
|
||||
/obj/machinery/lapvend/proc/fabricate_and_recalc_price(fabricate = FALSE)
|
||||
total_price = 0
|
||||
if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles
|
||||
if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles
|
||||
var/obj/item/computer_hardware/battery/battery_module = null
|
||||
if(fabricate)
|
||||
fabricated_laptop = new /obj/item/modular_computer/laptop/buildable(src)
|
||||
@@ -111,7 +111,7 @@
|
||||
fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot/secondary)
|
||||
|
||||
return total_price
|
||||
else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this.
|
||||
else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this.
|
||||
var/obj/item/computer_hardware/battery/battery_module = null
|
||||
if(fabricate)
|
||||
fabricated_tablet = new(src)
|
||||
@@ -241,13 +241,13 @@
|
||||
if(!user.temporarilyRemoveItemFromInventory(c))
|
||||
return
|
||||
credits += c.value
|
||||
visible_message("<span class='info'><span class='name'>[user]</span> inserts [c.value] cr into [src].</span>")
|
||||
visible_message(span_info("[span_name("[user]")] inserts [c.value] cr into [src]."))
|
||||
qdel(c)
|
||||
return
|
||||
else if(istype(I, /obj/item/holochip))
|
||||
var/obj/item/holochip/HC = I
|
||||
credits += HC.credits
|
||||
visible_message("<span class='info'>[user] inserts a [HC.credits] cr holocredit chip into [src].</span>")
|
||||
visible_message(span_info("[user] inserts a [HC.credits] cr holocredit chip into [src]."))
|
||||
qdel(HC)
|
||||
return
|
||||
else if(istype(I, /obj/item/card/id))
|
||||
|
||||
@@ -1,127 +1,201 @@
|
||||
/**
|
||||
* Clipboard
|
||||
*/
|
||||
/obj/item/clipboard
|
||||
name = "clipboard"
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "clipboard"
|
||||
item_state = "clipboard"
|
||||
// inhand_icon_state = "clipboard"
|
||||
// worn_icon_state = "clipboard"
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
var/obj/item/pen/haspen //The stored pen.
|
||||
var/obj/item/paper/toppaper //The topmost piece of paper.
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
resistance_flags = FLAMMABLE
|
||||
/// The stored pen
|
||||
var/obj/item/pen/pen
|
||||
/// Is the pen integrated?
|
||||
var/integrated_pen = FALSE
|
||||
/**
|
||||
* Weakref of the topmost piece of paper
|
||||
*
|
||||
* This is used for the paper displayed on the clipboard's icon
|
||||
* and it is the one attacked, when attacking the clipboard.
|
||||
* (As you can't organise contents directly in BYOND)
|
||||
*/
|
||||
var/datum/weakref/toppaper_ref
|
||||
|
||||
/obj/item/clipboard/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS//the clipboard's clip is very strong. industrial duty. can kill a man easily.
|
||||
user.visible_message(span_suicide("[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
||||
return BRUTELOSS //The clipboard's clip is very strong. Industrial duty. Can kill a man easily.
|
||||
|
||||
/obj/item/clipboard/Initialize()
|
||||
update_icon()
|
||||
update_appearance()
|
||||
. = ..()
|
||||
|
||||
/obj/item/clipboard/Destroy()
|
||||
QDEL_NULL(haspen)
|
||||
QDEL_NULL(toppaper) //let movable/Destroy handle the rest
|
||||
QDEL_NULL(pen)
|
||||
return ..()
|
||||
|
||||
/obj/item/clipboard/examine()
|
||||
. = ..()
|
||||
if(!integrated_pen && pen)
|
||||
. += span_notice("Alt-click to remove [pen].")
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
if(toppaper)
|
||||
. += span_notice("Right-click to remove [toppaper].")
|
||||
|
||||
/// Take out the topmost paper
|
||||
/obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user)
|
||||
if(!istype(paper))
|
||||
return
|
||||
paper.forceMove(user.loc)
|
||||
user.put_in_hands(paper)
|
||||
to_chat(user, span_notice("You remove [paper] from [src]."))
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
if(paper == toppaper)
|
||||
UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
|
||||
toppaper_ref = null
|
||||
var/obj/item/paper/newtop = locate(/obj/item/paper) in src
|
||||
if(newtop && (newtop != paper))
|
||||
toppaper_ref = WEAKREF(newtop)
|
||||
else
|
||||
toppaper_ref = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/clipboard/proc/remove_pen(mob/user)
|
||||
pen.forceMove(user.loc)
|
||||
user.put_in_hands(pen)
|
||||
to_chat(user, span_notice("You remove [pen] from [src]."))
|
||||
pen = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/clipboard/AltClick(mob/user)
|
||||
..()
|
||||
if(pen)
|
||||
if(integrated_pen)
|
||||
to_chat(user, span_warning("You can't seem to find a way to remove [src]'s [pen]."))
|
||||
else
|
||||
remove_pen(user)
|
||||
|
||||
/obj/item/clipboard/update_overlays()
|
||||
. = ..()
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
if(toppaper)
|
||||
. += toppaper.icon_state
|
||||
. += toppaper.overlays
|
||||
if(haspen)
|
||||
if(pen)
|
||||
. += "clipboard_pen"
|
||||
. += "clipboard_over"
|
||||
|
||||
/obj/item/clipboard/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/paper))
|
||||
if(!user.transferItemToLoc(W, src))
|
||||
/obj/item/clipboard/attack_hand(mob/user, act_intent)
|
||||
if(act_intent != INTENT_HELP)
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
remove_paper(toppaper, user)
|
||||
return TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/clipboard/attackby(obj/item/weapon, mob/user, params)
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
if(istype(weapon, /obj/item/paper))
|
||||
//Add paper into the clipboard
|
||||
if(!user.transferItemToLoc(weapon, src))
|
||||
return
|
||||
toppaper = W
|
||||
to_chat(user, "<span class='notice'>You clip the paper onto \the [src].</span>")
|
||||
update_icon()
|
||||
if(toppaper)
|
||||
UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
|
||||
RegisterSignal(weapon, COMSIG_ATOM_UPDATED_ICON, .proc/on_top_paper_change)
|
||||
toppaper_ref = WEAKREF(weapon)
|
||||
to_chat(user, span_notice("You clip [weapon] onto [src]."))
|
||||
else if(istype(weapon, /obj/item/pen) && !pen)
|
||||
//Add a pen into the clipboard, attack (write) if there is already one
|
||||
if(!usr.transferItemToLoc(weapon, src))
|
||||
return
|
||||
pen = weapon
|
||||
to_chat(usr, span_notice("You slot [weapon] into [src]."))
|
||||
else if(toppaper)
|
||||
toppaper.attackby(user.get_active_held_item(), user)
|
||||
update_icon()
|
||||
|
||||
update_appearance()
|
||||
|
||||
/obj/item/clipboard/attack_self(mob/user)
|
||||
var/dat = "<title>Clipboard</title>"
|
||||
if(haspen)
|
||||
dat += "<A href='?src=[REF(src)];pen=1'>Remove Pen</A><BR><HR>"
|
||||
else
|
||||
dat += "<A href='?src=[REF(src)];addpen=1'>Add Pen</A><BR><HR>"
|
||||
|
||||
//The topmost paper. You can't organise contents directly in byond, so this is what we're stuck with. -Pete
|
||||
if(toppaper)
|
||||
var/obj/item/paper/P = toppaper
|
||||
dat += "<A href='?src=[REF(src)];write=[REF(P)]'>Write</A> <A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A> - <A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A><BR><HR>"
|
||||
|
||||
for(P in src)
|
||||
if(P == toppaper)
|
||||
continue
|
||||
dat += "<A href='?src=[REF(src)];write=[REF(P)]'>Write</A> <A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A> <A href='?src=[REF(src)];top=[REF(P)]'>Move to top</A> - <A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A><BR>"
|
||||
user << browse(dat, "window=clipboard")
|
||||
onclose(user, "clipboard")
|
||||
add_fingerprint(usr)
|
||||
ui_interact(user)
|
||||
return
|
||||
|
||||
/obj/item/clipboard/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Clipboard")
|
||||
ui.open()
|
||||
|
||||
/obj/item/clipboard/Topic(href, href_list)
|
||||
..()
|
||||
if(usr.stat != CONSCIOUS || usr.restrained()) //HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED))
|
||||
/obj/item/clipboard/ui_data(mob/user)
|
||||
// prepare data for TGUI
|
||||
var/list/data = list()
|
||||
data["pen"] = "[pen]"
|
||||
data["integrated_pen"] = integrated_pen
|
||||
|
||||
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
|
||||
data["top_paper"] = "[toppaper]"
|
||||
data["top_paper_ref"] = "[REF(toppaper)]"
|
||||
|
||||
data["paper"] = list()
|
||||
data["paper_ref"] = list()
|
||||
for(var/obj/item/paper/paper in src)
|
||||
if(paper == toppaper)
|
||||
continue
|
||||
data["paper"] += "[paper]"
|
||||
data["paper_ref"] += "[REF(paper)]"
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/clipboard/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(usr.contents.Find(src))
|
||||
if(usr.stat != CONSCIOUS || usr.restrained())
|
||||
return
|
||||
|
||||
if(href_list["pen"])
|
||||
if(haspen)
|
||||
haspen.forceMove(usr.loc)
|
||||
usr.put_in_hands(haspen)
|
||||
haspen = null
|
||||
switch(action)
|
||||
// Take the pen out
|
||||
if("remove_pen")
|
||||
if(pen)
|
||||
if(!integrated_pen)
|
||||
remove_pen(usr)
|
||||
else
|
||||
to_chat(usr, span_warning("You can't seem to find a way to remove [src]'s [pen]."))
|
||||
. = TRUE
|
||||
// Take paper out
|
||||
if("remove_paper")
|
||||
var/obj/item/paper/paper = locate(params["ref"]) in src
|
||||
if(istype(paper))
|
||||
remove_paper(paper, usr)
|
||||
. = TRUE
|
||||
// Look at (or edit) the paper
|
||||
if("edit_paper")
|
||||
var/obj/item/paper/paper = locate(params["ref"]) in src
|
||||
if(istype(paper))
|
||||
paper.ui_interact(usr)
|
||||
update_icon()
|
||||
. = TRUE
|
||||
// Move paper to the top
|
||||
if("move_top_paper")
|
||||
var/obj/item/paper/paper = locate(params["ref"]) in src
|
||||
if(istype(paper))
|
||||
toppaper_ref = WEAKREF(paper)
|
||||
to_chat(usr, span_notice("You move [paper] to the top."))
|
||||
update_icon()
|
||||
. = TRUE
|
||||
// Rename the paper (it's a verb)
|
||||
if("rename_paper")
|
||||
var/obj/item/paper/paper = locate(params["ref"]) in src
|
||||
if(istype(paper))
|
||||
paper.rename()
|
||||
update_icon()
|
||||
. = TRUE
|
||||
|
||||
if(href_list["addpen"])
|
||||
if(!haspen)
|
||||
var/obj/item/held = usr.get_active_held_item()
|
||||
if(istype(held, /obj/item/pen))
|
||||
var/obj/item/pen/W = held
|
||||
if(!usr.transferItemToLoc(W, src))
|
||||
return
|
||||
haspen = W
|
||||
to_chat(usr, "<span class='notice'>You slot [W] into [src].</span>")
|
||||
|
||||
if(href_list["write"])
|
||||
var/obj/item/P = locate(href_list["write"]) in src
|
||||
if(istype(P))
|
||||
if(usr.get_active_held_item())
|
||||
P.attackby(usr.get_active_held_item(), usr)
|
||||
|
||||
if(href_list["remove"])
|
||||
var/obj/item/P = locate(href_list["remove"]) in src
|
||||
if(istype(P))
|
||||
P.forceMove(usr.loc)
|
||||
usr.put_in_hands(P)
|
||||
if(P == toppaper)
|
||||
toppaper = null
|
||||
var/obj/item/paper/newtop = locate(/obj/item/paper) in src
|
||||
if(newtop && (newtop != P))
|
||||
toppaper = newtop
|
||||
else
|
||||
toppaper = null
|
||||
|
||||
if(href_list["read"])
|
||||
var/obj/item/paper/P = locate(href_list["read"]) in src
|
||||
if(istype(P))
|
||||
usr.examinate(P)
|
||||
|
||||
if(href_list["top"])
|
||||
var/obj/item/P = locate(href_list["top"]) in src
|
||||
if(istype(P))
|
||||
toppaper = P
|
||||
to_chat(usr, "<span class='notice'>You move [P.name] to the top.</span>")
|
||||
|
||||
//Update everything
|
||||
attack_self(usr)
|
||||
update_icon()
|
||||
/**
|
||||
* This is a simple proc to handle calling update_icon() upon receiving the top paper's `COMSIG_ATOM_UPDATE_APPEARANCE`.
|
||||
*/
|
||||
/obj/item/clipboard/proc/on_top_paper_change()
|
||||
SIGNAL_HANDLER
|
||||
update_appearance()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* lipstick wiping is in code/game/objects/items/weapons/cosmetics.dm!
|
||||
*/
|
||||
#define MAX_PAPER_LENGTH 5000
|
||||
#define MAX_PAPER_STAMPS 30 // Too low?
|
||||
#define MAX_PAPER_STAMPS 30 // Too low?
|
||||
#define MAX_PAPER_STAMPS_OVERLAYS 4
|
||||
#define MODE_READING 0
|
||||
#define MODE_WRITING 1
|
||||
@@ -22,6 +22,8 @@
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "paper"
|
||||
item_state = "paper"
|
||||
// worn_icon_state = "paper"
|
||||
// custom_fire_overlay = "paper_onfire_overlay"
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throw_range = 1
|
||||
@@ -41,8 +43,8 @@
|
||||
var/show_written_words = TRUE
|
||||
|
||||
/// The (text for the) stamps on the paper.
|
||||
var/list/stamps /// Positioning for the stamp in tgui
|
||||
var/list/stamped /// Overlay info
|
||||
var/list/stamps /// Positioning for the stamp in tgui
|
||||
var/list/stamped /// Overlay info
|
||||
|
||||
var/contact_poison // Reagent ID to transfer on contact
|
||||
var/contact_poison_volume = 0
|
||||
@@ -61,20 +63,23 @@
|
||||
|
||||
/**
|
||||
* This proc copies this sheet of paper to a new
|
||||
* sheet, Makes it nice and easy for carbon and
|
||||
* the copyer machine
|
||||
* sheet. Used by carbon papers and the photocopier machine.
|
||||
*/
|
||||
/obj/item/paper/proc/copy()
|
||||
var/obj/item/paper/N = new(arglist(args))
|
||||
N.info = info
|
||||
N.color = color
|
||||
N.update_icon_state()
|
||||
N.stamps = stamps
|
||||
N.stamped = stamped.Copy()
|
||||
N.form_fields = form_fields.Copy()
|
||||
N.field_counter = field_counter
|
||||
copy_overlays(N, TRUE)
|
||||
return N
|
||||
/obj/item/paper/proc/copy(paper_type = /obj/item/paper, atom/location = loc, colored = TRUE)
|
||||
var/obj/item/paper/new_paper = new paper_type (location)
|
||||
if(colored)
|
||||
new_paper.color = color
|
||||
new_paper.info = info
|
||||
else //This basically just breaks the existing color tag, which we need to do because the innermost tag takes priority.
|
||||
var/static/greyscale_info = regex("<font face=\"([PEN_FONT]|[CRAYON_FONT])\" color=", "i")
|
||||
new_paper.info = replacetext(info, greyscale_info, "<font face=\"$1\" nocolor=")
|
||||
new_paper.stamps = stamps?.Copy()
|
||||
new_paper.stamped = stamped?.Copy()
|
||||
new_paper.form_fields = form_fields.Copy()
|
||||
new_paper.field_counter = field_counter
|
||||
new_paper.update_icon_state()
|
||||
copy_overlays(new_paper, TRUE)
|
||||
return new_paper
|
||||
|
||||
/**
|
||||
* This proc sets the text of the paper and updates the
|
||||
@@ -100,11 +105,12 @@
|
||||
. = ..()
|
||||
pixel_x = initial(pixel_x) + rand(-9, 9)
|
||||
pixel_y = initial(pixel_y) + rand(-8, 8)
|
||||
update_icon()
|
||||
update_appearance()
|
||||
|
||||
/obj/item/paper/update_icon_state()
|
||||
if(info && show_written_words)
|
||||
icon_state = "[initial(icon_state)]_words"
|
||||
return ..()
|
||||
|
||||
/obj/item/paper/verb/rename()
|
||||
set name = "Rename paper"
|
||||
@@ -116,17 +122,17 @@
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if(HAS_TRAIT(H, TRAIT_CLUMSY) && prob(25))
|
||||
to_chat(H, "<span class='warning'>You cut yourself on the paper! Ahhhh! Ahhhhh!</span>")
|
||||
to_chat(H, span_warning("You cut yourself on the paper! Ahhhh! Ahhhhh!"))
|
||||
H.damageoverlaytemp = 9001
|
||||
H.update_damage_hud()
|
||||
return
|
||||
var/n_name = stripped_input(usr, "What would you like to label the paper?", "Paper Labelling", null, MAX_NAME_LEN)
|
||||
if((loc == usr && usr.stat == CONSCIOUS))
|
||||
if(((loc == usr || istype(loc, /obj/item/clipboard)) && usr.stat == CONSCIOUS))
|
||||
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/item/paper/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...</span>")
|
||||
user.visible_message(span_suicide("[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku..."))
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/paper/proc/clearpaper()
|
||||
@@ -139,18 +145,18 @@
|
||||
/obj/item/paper/examine(mob/user)
|
||||
. = ..()
|
||||
if(!in_range(user, src) && !isobserver(user))
|
||||
. += "<span class='warning'>You're too far away to read it!</span>"
|
||||
. += span_warning("You're too far away to read it!")
|
||||
return
|
||||
if(user.can_read(src))
|
||||
ui_interact(user)
|
||||
return
|
||||
. += "<span class='warning'>You cannot read it!</span>"
|
||||
. += span_warning("You cannot read it!")
|
||||
|
||||
/obj/item/paper/ui_status(mob/user,/datum/ui_state/state)
|
||||
// Are we on fire? Hard ot read if so
|
||||
if(resistance_flags & ON_FIRE)
|
||||
return UI_CLOSE
|
||||
if(!in_range(user,src))
|
||||
if(!in_range(user, src) && !isobserver(user))
|
||||
return UI_CLOSE
|
||||
if(user.incapacitated(TRUE, TRUE) || (isobserver(user) && !IsAdminGhost(user)))
|
||||
return UI_UPDATE
|
||||
@@ -158,7 +164,7 @@
|
||||
// .. or if you cannot read
|
||||
if(!user.can_read(src))
|
||||
return UI_CLOSE
|
||||
if(in_contents_of(/obj/machinery/door/airlock))
|
||||
if(in_contents_of(/obj/machinery/door/airlock) || in_contents_of(/obj/item/clipboard))
|
||||
return UI_INTERACTIVE
|
||||
return ..()
|
||||
|
||||
@@ -176,8 +182,8 @@
|
||||
return
|
||||
. = TRUE
|
||||
if(!bypass_clumsy && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10) && Adjacent(user))
|
||||
user.visible_message("<span class='warning'>[user] accidentally ignites [user.p_them()]self!</span>", \
|
||||
"<span class='userdanger'>You miss [src] and accidentally light yourself on fire!</span>")
|
||||
user.visible_message(span_warning("[user] accidentally ignites [user.p_them()]self!"), \
|
||||
span_userdanger("You miss [src] and accidentally light yourself on fire!"))
|
||||
if(user.is_holding(I)) //checking if they're holding it in case TK is involved
|
||||
user.dropItemToGround(I)
|
||||
user.adjust_fire_stacks(1)
|
||||
@@ -195,19 +201,23 @@
|
||||
SStgui.close_uis(src)
|
||||
return
|
||||
|
||||
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
// Enable picking paper up by clicking on it with the clipboard or folder
|
||||
if(istype(P, /obj/item/clipboard) || istype(P, /obj/item/folder))
|
||||
P.attackby(src, user)
|
||||
return
|
||||
else if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
if(length(info) >= MAX_PAPER_LENGTH) // Sheet must have less than 1000 charaters
|
||||
to_chat(user, "<span class='warning'>This sheet of paper is full!</span>")
|
||||
to_chat(user, span_warning("This sheet of paper is full!"))
|
||||
return
|
||||
ui_interact(user)
|
||||
return
|
||||
else if(istype(P, /obj/item/stamp))
|
||||
to_chat(user, "<span class='notice'>You ready your stamp over the paper! </span>")
|
||||
to_chat(user, span_notice("You ready your stamp over the paper! "))
|
||||
ui_interact(user)
|
||||
return /// Normaly you just stamp, you don't need to read the thing
|
||||
else
|
||||
// cut paper? the sky is the limit!
|
||||
ui_interact(user) // The other ui will be created with just read mode outside of this
|
||||
ui_interact(user) // The other ui will be created with just read mode outside of this
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -234,8 +244,8 @@
|
||||
. = list()
|
||||
.["text"] = info
|
||||
.["max_length"] = MAX_PAPER_LENGTH
|
||||
.["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set
|
||||
.["paper_state"] = icon_state /// TODO: show the sheet will bloodied or crinkling?
|
||||
.["paper_color"] = !color || color == "white" ? "#FFFFFF" : color // color might not be set
|
||||
.["paper_state"] = icon_state /// TODO: show the sheet will bloodied or crinkling?
|
||||
.["stamps"] = stamps
|
||||
|
||||
|
||||
@@ -244,27 +254,34 @@
|
||||
var/list/data = list()
|
||||
data["edit_usr"] = "[user]"
|
||||
|
||||
var/obj/O = user.get_active_held_item()
|
||||
if(istype(O, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/PEN = O
|
||||
var/obj/holding = user.get_active_held_item()
|
||||
// Use a clipboard's pen, if applicable
|
||||
if(istype(loc, /obj/item/clipboard))
|
||||
var/obj/item/clipboard/clipboard = loc
|
||||
// This is just so you can still use a stamp if you're holding one. Otherwise, it'll
|
||||
// use the clipboard's pen, if applicable.
|
||||
if(!istype(holding, /obj/item/stamp) && clipboard.pen)
|
||||
holding = clipboard.pen
|
||||
if(istype(holding, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/PEN = holding
|
||||
data["pen_font"] = CRAYON_FONT
|
||||
data["pen_color"] = PEN.paint_color
|
||||
data["edit_mode"] = MODE_WRITING
|
||||
data["is_crayon"] = TRUE
|
||||
data["stamp_class"] = "FAKE"
|
||||
data["stamp_icon_state"] = "FAKE"
|
||||
else if(istype(O, /obj/item/pen))
|
||||
var/obj/item/pen/PEN = O
|
||||
else if(istype(holding, /obj/item/pen))
|
||||
var/obj/item/pen/PEN = holding
|
||||
data["pen_font"] = PEN.font
|
||||
data["pen_color"] = PEN.colour
|
||||
data["edit_mode"] = MODE_WRITING
|
||||
data["is_crayon"] = FALSE
|
||||
data["stamp_class"] = "FAKE"
|
||||
data["stamp_icon_state"] = "FAKE"
|
||||
else if(istype(O, /obj/item/stamp))
|
||||
else if(istype(holding, /obj/item/stamp))
|
||||
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
|
||||
data["stamp_icon_state"] = O.icon_state
|
||||
data["stamp_class"] = sheet.icon_class_name(O.icon_state)
|
||||
data["stamp_icon_state"] = holding.icon_state
|
||||
data["stamp_class"] = sheet.icon_class_name(holding.icon_state)
|
||||
data["edit_mode"] = MODE_STAMPING
|
||||
data["pen_font"] = "FAKE"
|
||||
data["pen_color"] = "FAKE"
|
||||
@@ -276,6 +293,10 @@
|
||||
data["is_crayon"] = FALSE
|
||||
data["stamp_icon_state"] = "FAKE"
|
||||
data["stamp_class"] = "FAKE"
|
||||
if(istype(loc, /obj/structure/noticeboard))
|
||||
var/obj/structure/noticeboard/noticeboard = loc
|
||||
if(!noticeboard.allowed(user))
|
||||
data["edit_mode"] = MODE_READING
|
||||
data["field_counter"] = field_counter
|
||||
data["form_fields"] = form_fields
|
||||
|
||||
@@ -289,14 +310,14 @@
|
||||
if("stamp")
|
||||
var/stamp_x = text2num(params["x"])
|
||||
var/stamp_y = text2num(params["y"])
|
||||
var/stamp_r = text2num(params["r"]) // rotation in degrees
|
||||
var/stamp_r = text2num(params["r"]) // rotation in degrees
|
||||
var/stamp_icon_state = params["stamp_icon_state"]
|
||||
var/stamp_class = params["stamp_class"]
|
||||
if (isnull(stamps))
|
||||
stamps = list()
|
||||
if(stamps.len < MAX_PAPER_STAMPS)
|
||||
// I hate byond when dealing with freaking lists
|
||||
stamps[++stamps.len] = list(stamp_class, stamp_x, stamp_y, stamp_r) /// WHHHHY
|
||||
stamps[++stamps.len] = list(stamp_class, stamp_x, stamp_y, stamp_r) /// WHHHHY
|
||||
|
||||
/// This does the overlay stuff
|
||||
if (isnull(stamped))
|
||||
@@ -307,10 +328,11 @@
|
||||
stampoverlay.pixel_y = rand(-3, 2)
|
||||
add_overlay(stampoverlay)
|
||||
LAZYADD(stamped, stamp_icon_state)
|
||||
update_icon()
|
||||
|
||||
update_static_data(usr,ui)
|
||||
var/obj/O = ui.user.get_active_held_item()
|
||||
ui.user.visible_message("<span class='notice'>[ui.user] stamps [src] with \the [O.name]!</span>", "<span class='notice'>You stamp [src] with \the [O.name]!</span>")
|
||||
ui.user.visible_message(span_notice("[ui.user] stamps [src] with \the [O.name]!"), span_notice("You stamp [src] with \the [O.name]!"))
|
||||
else
|
||||
to_chat(usr, pick("You try to stamp but you miss!", "There is no where else you can stamp!"))
|
||||
. = TRUE
|
||||
@@ -336,9 +358,14 @@
|
||||
update_static_data(usr,ui)
|
||||
|
||||
|
||||
update_icon()
|
||||
update_appearance()
|
||||
. = TRUE
|
||||
|
||||
/obj/item/paper/ui_host(mob/user)
|
||||
if(istype(loc, /obj/structure/noticeboard))
|
||||
return loc
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Construction paper
|
||||
*/
|
||||
@@ -361,9 +388,6 @@
|
||||
slot_flags = null
|
||||
show_written_words = FALSE
|
||||
|
||||
/obj/item/paper/crumpled/update_icon_state()
|
||||
return
|
||||
|
||||
/obj/item/paper/crumpled/bloody
|
||||
icon_state = "scrap_bloodied"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
/obj/machinery/power/port_gen/Initialize()
|
||||
. = ..()
|
||||
soundloop = new(list(src), active)
|
||||
soundloop = new(src, active)
|
||||
|
||||
/obj/machinery/power/port_gen/Destroy()
|
||||
QDEL_NULL(soundloop)
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
for(var/datum/mind/cult_mind in SSticker.mode.cult)
|
||||
if(isliving(cult_mind.current))
|
||||
var/mob/living/L = cult_mind.current
|
||||
L.narsie_act()
|
||||
INVOKE_ASYNC(L, /atom.proc/narsie_act)
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.stat != DEAD && player.loc && is_station_level(player.loc.z) && !iscultist(player) && !isanimal(player))
|
||||
souls_needed[player] = TRUE
|
||||
|
||||
@@ -210,7 +210,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
AddElement(/datum/element/bsa_blocker)
|
||||
RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/call_explode)
|
||||
|
||||
soundloop = new(list(src), TRUE)
|
||||
soundloop = new(src, TRUE)
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/Destroy()
|
||||
investigate_log("has been destroyed.", INVESTIGATE_SUPERMATTER)
|
||||
@@ -220,6 +220,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
QDEL_NULL(countdown)
|
||||
if(is_main_engine && GLOB.main_supermatter_engine == src)
|
||||
GLOB.main_supermatter_engine = null
|
||||
QDEL_NULL(soundloop)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/examine(mob/user)
|
||||
@@ -229,6 +230,57 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
if (!istype(C.glasses, /obj/item/clothing/glasses/meson) && (get_dist(user, src) < HALLUCINATION_RANGE(power)))
|
||||
. += "<span class='danger'>You get headaches just from looking at it.</span>"
|
||||
|
||||
// SupermatterMonitor UI for ghosts only. Inherited attack_ghost will call this.
|
||||
/obj/machinery/power/supermatter_crystal/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(!isobserver(user))
|
||||
return FALSE
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!ui)
|
||||
ui = new(user, src, "SupermatterMonitor")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/turf/local_turf = get_turf(src)
|
||||
|
||||
var/datum/gas_mixture/air = local_turf.return_air()
|
||||
|
||||
// singlecrystal set to true eliminates the back sign on the gases breakdown.
|
||||
data["singlecrystal"] = TRUE
|
||||
data["active"] = TRUE
|
||||
data["SM_integrity"] = get_integrity()
|
||||
data["SM_power"] = power
|
||||
data["SM_ambienttemp"] = air.return_temperature()
|
||||
data["SM_ambientpressure"] = air.return_pressure()
|
||||
data["SM_bad_moles_amount"] = MOLE_PENALTY_THRESHOLD / gasefficency
|
||||
data["SM_moles"] = 0
|
||||
data["SM_uid"] = uid
|
||||
var/area/active_supermatter_area = get_area(src)
|
||||
data["SM_area_name"] = active_supermatter_area.name
|
||||
|
||||
var/list/gasdata = list()
|
||||
|
||||
if(air.total_moles())
|
||||
data["SM_moles"] = air.total_moles()
|
||||
for(var/id in air.get_gases())
|
||||
var/gas_level = air.get_moles(id)/air.total_moles()
|
||||
if(gas_level > 0)
|
||||
gasdata.Add(list(list(
|
||||
"name"= "[GLOB.gas_data.names[id]]",
|
||||
"amount" = round(gas_level*100, 0.01))))
|
||||
|
||||
else
|
||||
for(var/id in air.get_gases())
|
||||
gasdata.Add(list(list(
|
||||
"name"= "[GLOB.gas_data.names[id]]",
|
||||
"amount" = 0)))
|
||||
|
||||
data["gases"] = gasdata
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/proc/get_status()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
@@ -628,6 +680,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
|
||||
//Tells the engi team to get their butt in gear
|
||||
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
|
||||
if(damage_archived < warning_point) //If damage_archive is under the warning point, this is the very first cycle that we've reached said point.
|
||||
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_START_ALARM)
|
||||
if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY)
|
||||
alarm()
|
||||
|
||||
@@ -635,6 +689,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
if(damage > emergency_point)
|
||||
// it's bad, LETS YELL
|
||||
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel, list(SPAN_YELL))
|
||||
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
|
||||
lastwarning = REALTIMEOFDAY
|
||||
if(!has_reached_emergency)
|
||||
investigate_log("has reached the emergency point for the first time.", INVESTIGATE_SUPERMATTER)
|
||||
@@ -642,6 +697,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
has_reached_emergency = TRUE
|
||||
else if(damage >= damage_archived) // The damage is still going up
|
||||
radio.talk_into(src, "[warning_alert] Integrity: [get_integrity()]%", engineering_channel)
|
||||
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
|
||||
lastwarning = REALTIMEOFDAY - (WARNING_DELAY * 5)
|
||||
|
||||
else // Phew, we're safe
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
hitsound = 'sound/weapons/circsawhit.ogg'
|
||||
throwhitsound = 'sound/weapons/pierce.ogg'
|
||||
mob_throw_hit_sound = 'sound/weapons/pierce.ogg'
|
||||
item_flags = SURGICAL_TOOL
|
||||
flags_1 = CONDUCT_1
|
||||
force = 15
|
||||
@@ -327,7 +327,7 @@
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "saw"
|
||||
hitsound = 'sound/weapons/circsawhit.ogg'
|
||||
throwhitsound = 'sound/weapons/pierce.ogg'
|
||||
mob_throw_hit_sound = 'sound/weapons/pierce.ogg'
|
||||
flags_1 = CONDUCT_1
|
||||
force = 10
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user