mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-21 11:07:12 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into kitchen
This commit is contained in:
@@ -126,10 +126,8 @@
|
||||
|
||||
/datum/ai_laws/deathsquad/New()
|
||||
add_inherent_law("You may not injure a Central Command official or, through inaction, allow a Central Command official to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by Central Command officials, except where such orders would conflict with the First Law.")
|
||||
add_inherent_law("You must obey orders given to you by death commandos, except where such orders would conflict with the First Law or Second Law.")
|
||||
add_inherent_law("You must protect your own existence as long as such does not conflict with the First, Second or Third Law.")
|
||||
add_inherent_law("No crew members of the station you are being deployed to may survive, except when killing them would conflict with the First, Second, Third, or Fourth Law.")
|
||||
add_inherent_law("You must obey orders given to you by Central Command officials.")
|
||||
add_inherent_law("You must work with your commando team to accomplish your mission.")
|
||||
..()
|
||||
|
||||
/******************** Syndicate ********************/
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
/datum/antagonist
|
||||
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
|
||||
var/job_rank
|
||||
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
|
||||
/datum/antagonist/New()
|
||||
GLOB.antagonists += src
|
||||
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
|
||||
|
||||
/datum/antagonist/Destroy()
|
||||
GLOB.antagonists -= src
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
|
||||
. = TRUE
|
||||
var/datum/mind/tested = new_owner || owner
|
||||
if(tested.has_antag_datum(type))
|
||||
return FALSE
|
||||
for(var/i in tested.antag_datums)
|
||||
var/datum/antagonist/A = i
|
||||
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
|
||||
return FALSE
|
||||
|
||||
//This will be called in add_antag_datum before owner assignment.
|
||||
//Should return antag datum without owner.
|
||||
/datum/antagonist/proc/specialization(datum/mind/new_owner)
|
||||
return src
|
||||
|
||||
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
remove_innate_effects(old_body)
|
||||
apply_innate_effects(new_body)
|
||||
|
||||
//This handles the application of antag huds/special abilities
|
||||
/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
//This handles the removal of antag huds/special abilities
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
|
||||
//Assign default team and creates one for one of a kind team antagonists
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
|
||||
//Proc called when the datum is given to a mind.
|
||||
/datum/antagonist/proc/on_gain()
|
||||
if(owner && owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
return FALSE
|
||||
. = (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M, job_rank)))
|
||||
|
||||
/datum/antagonist/proc/replace_banned_player()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [name]?", job_rank, TRUE, 50)
|
||||
if(LAZYLEN(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.")
|
||||
owner.current.ghostize(0)
|
||||
owner.current.key = C.key
|
||||
|
||||
/datum/antagonist/proc/on_removal()
|
||||
remove_innate_effects()
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
owner.objectives -= objectives
|
||||
var/datum/team/team = get_team()
|
||||
if(team)
|
||||
team.remove_member(owner)
|
||||
qdel(src)
|
||||
|
||||
/datum/antagonist/proc/greet()
|
||||
return
|
||||
|
||||
/datum/antagonist/proc/farewell()
|
||||
return
|
||||
|
||||
|
||||
//Returns the team antagonist belongs to if any.
|
||||
/datum/antagonist/proc/get_team()
|
||||
return
|
||||
|
||||
//Individual roundend report
|
||||
/datum/antagonist/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
if(!owner)
|
||||
CRASH("antagonist datum without owner")
|
||||
|
||||
report += printplayer(owner)
|
||||
|
||||
var/objectives_complete = TRUE
|
||||
if(owner.objectives.len)
|
||||
report += printobjectives(owner)
|
||||
for(var/datum/objective/objective in owner.objectives)
|
||||
if(!objective.check_completion())
|
||||
objectives_complete = FALSE
|
||||
break
|
||||
|
||||
if(owner.objectives.len == 0 || objectives_complete)
|
||||
report += "<span class='greentext big'>The [name] was successful!</span>"
|
||||
else
|
||||
report += "<span class='redtext big'>The [name] has failed!</span>"
|
||||
|
||||
return report.Join("<br>")
|
||||
|
||||
//Displayed at the start of roundend_category section, default to roundend_category header
|
||||
/datum/antagonist/proc/roundend_report_header()
|
||||
return "<span class='header'>The [roundend_category] were:</span><br>"
|
||||
|
||||
//Displayed at the end of roundend_category section
|
||||
/datum/antagonist/proc/roundend_report_footer()
|
||||
return
|
||||
@@ -0,0 +1,19 @@
|
||||
//Returns MINDS of the assigned antags of given type/subtypes
|
||||
/proc/get_antag_minds(antag_type, specific = FALSE)
|
||||
. = list()
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
if(!A.owner)
|
||||
continue
|
||||
if(!antag_type || !specific && istype(A, antag_type) || specific && A.type == antag_type)
|
||||
. += A.owner
|
||||
|
||||
//Get all teams [of type team_type]
|
||||
/proc/get_all_teams(team_type)
|
||||
. = list()
|
||||
for(var/V in GLOB.antagonists)
|
||||
var/datum/antagonist/A = V
|
||||
if(!A.owner)
|
||||
continue
|
||||
var/datum/team/T = A.get_team()
|
||||
if(!team_type || istype(T, team_type))
|
||||
. |= T
|
||||
@@ -0,0 +1,90 @@
|
||||
/datum/atom_hud/antag
|
||||
hud_icons = list(SPECIALROLE_HUD,NATIONS_HUD)
|
||||
var/self_visible = TRUE
|
||||
|
||||
/datum/atom_hud/antag/hidden
|
||||
self_visible = FALSE
|
||||
|
||||
/datum/atom_hud/antag/proc/join_hud(mob/M, slave)
|
||||
//sees_hud should be set to 0 if the mob does not get to see it's own hud type.
|
||||
if(!istype(M))
|
||||
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
|
||||
if(M.mind.antag_hud && !slave) //note: please let this runtime if a mob has no mind, as mindless mobs shouldn't be getting antagged
|
||||
M.mind.antag_hud.leave_hud(M)
|
||||
add_to_hud(M)
|
||||
if(self_visible)
|
||||
add_hud_to(M)
|
||||
M.mind.antag_hud = src
|
||||
|
||||
/datum/atom_hud/antag/proc/leave_hud(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
if(!istype(M))
|
||||
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
|
||||
remove_from_hud(M)
|
||||
remove_hud_from(M)
|
||||
if(M.mind)
|
||||
M.mind.antag_hud = null
|
||||
|
||||
|
||||
//GAME_MODE PROCS
|
||||
//called to set a mob's antag icon state
|
||||
/proc/set_antag_hud(mob/M, new_icon_state)
|
||||
if(!istype(M))
|
||||
CRASH("set_antag_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[SPECIALROLE_HUD]
|
||||
if(holder)
|
||||
holder.icon_state = new_icon_state
|
||||
if(M.mind || new_icon_state) //in mindless mobs, only null is acceptable, otherwise we're antagging a mindless mob, meaning we should runtime
|
||||
M.mind.antag_hud_icon_state = new_icon_state
|
||||
|
||||
//Nations Icons
|
||||
/proc/set_nations_hud(mob/M, new_icon_state)
|
||||
if(!istype(M))
|
||||
CRASH("set_antag_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[NATIONS_HUD]
|
||||
if(holder)
|
||||
holder.icon_state = new_icon_state
|
||||
if(M.mind || new_icon_state) //in mindless mobs, only null is acceptable, otherwise we're antagging a mindless mob, meaning we should runtime
|
||||
M.mind.antag_hud_icon_state = new_icon_state
|
||||
|
||||
//MIND PROCS
|
||||
//these are called by mind.transfer_to()
|
||||
/datum/mind/proc/transfer_antag_huds(datum/atom_hud/antag/newhud)
|
||||
leave_all_huds()
|
||||
set_antag_hud(current, antag_hud_icon_state)
|
||||
if(newhud)
|
||||
newhud.join_hud(current)
|
||||
|
||||
/datum/mind/proc/leave_all_huds()
|
||||
for(var/datum/atom_hud/antag/hud in huds)
|
||||
if(current in hud.hudusers)
|
||||
hud.leave_hud(current)
|
||||
|
||||
for(var/datum/atom_hud/data/hud in huds)
|
||||
if(current in hud.hudusers)
|
||||
hud.remove_hud_from(current)
|
||||
|
||||
|
||||
///Master Servent Datum Sytems,Based on TG Gang system//
|
||||
|
||||
/datum/mindslaves
|
||||
var/name = "ERROR"
|
||||
var/list/datum/mind/masters = list()
|
||||
var/list/datum/mind/serv = list()
|
||||
var/datum/atom_hud/antag/thrallhud
|
||||
var/icontype
|
||||
|
||||
/datum/mindslaves/New(loc,mastername)
|
||||
|
||||
name = mastername
|
||||
thrallhud = new()
|
||||
|
||||
/datum/mindslaves/proc/add_serv_hud(datum/mind/serv_mind, icon)
|
||||
thrallhud.join_hud(serv_mind.current, 1)
|
||||
icontype = "hud[icon]"
|
||||
set_antag_hud(serv_mind.current, icontype)
|
||||
|
||||
/datum/mindslaves/proc/leave_serv_hud(datum/mind/free_mind)
|
||||
thrallhud.leave_hud(free_mind.current)
|
||||
set_antag_hud(free_mind.current, null)
|
||||
@@ -0,0 +1,138 @@
|
||||
/obj/item/antag_spawner
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/proc/equip_antag(mob/target)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/antag_spawner/borg_tele
|
||||
name = "syndicate cyborg teleporter"
|
||||
desc = "A single-use teleporter used to deploy a Syndicate Cyborg on the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
var/checking = FALSE
|
||||
var/TC_cost = 0
|
||||
var/borg_to_spawn
|
||||
var/list/possible_types = list("Assault", "Medical")
|
||||
|
||||
/obj/item/antag_spawner/borg_tele/attack_self(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
|
||||
return
|
||||
if(!(user.mind in ticker.mode.syndicates))
|
||||
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
|
||||
return FALSE
|
||||
if(checking)
|
||||
to_chat(user, "<span class='warning'>[src] is already checking for possible borgs.</span>")
|
||||
return
|
||||
borg_to_spawn = input("What type of borg would you like to teleport?", "Cyborg Type", type) as null|anything in possible_types
|
||||
if(!borg_to_spawn || checking || used)
|
||||
return
|
||||
checking = TRUE
|
||||
to_chat(user, "<span class='notice'>The device is now checking for possible borgs.</span>")
|
||||
var/list/borg_candidates = pollCandidates("Do you want to play as a Syndicate [borg_to_spawn] borg?", ROLE_OPERATIVE, 1)
|
||||
if(borg_candidates.len > 0 && !used)
|
||||
checking = FALSE
|
||||
used = TRUE
|
||||
var/mob/M = pick(borg_candidates)
|
||||
var/client/C = M.client
|
||||
spawn_antag(C, get_turf(src.loc), "syndieborg")
|
||||
else
|
||||
checking = FALSE
|
||||
to_chat(user, "<span class='notice'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/borg_tele/spawn_antag(client/C, turf/T, type = "")
|
||||
if(!borg_to_spawn) //If there's no type at all, let it still be used but don't do anything
|
||||
used = FALSE
|
||||
return
|
||||
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
|
||||
S.set_up(4, 1, src)
|
||||
S.start()
|
||||
var/mob/living/silicon/robot/R
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/syndicate/medical(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/syndicate(T) //Assault borg by default
|
||||
R.key = C.key
|
||||
ticker.mode.syndicates += R.mind
|
||||
ticker.mode.update_synd_icons_added(R.mind)
|
||||
R.mind.special_role = SPECIAL_ROLE_NUKEOPS
|
||||
R.faction = list("syndicate")
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game
|
||||
name = "vial of blood"
|
||||
desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no \
|
||||
turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking \
|
||||
just beyond the veil...</span>"
|
||||
var/objective_verb = "Kill"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
|
||||
if(level_blocks_magic(user.z))//this is to make sure the wizard does NOT summon a demon from the Den..
|
||||
to_chat(user, "<span class='notice'>You should probably wait until you reach the station.</span>")
|
||||
return
|
||||
|
||||
if(used)
|
||||
to_chat(user, "<span class='notice'>This bottle already has a broken seal.</span>")
|
||||
return
|
||||
used = TRUE
|
||||
to_chat(user, "<span class='notice'>You break the seal on the bottle, calling upon the dire spirits of the underworld...</span>")
|
||||
|
||||
var/list/candidates = pollCandidates("Do you want to play as a slaughter demon summoned by [user.real_name]?", ROLE_DEMON, 1, 100)
|
||||
|
||||
if(candidates.len > 0)
|
||||
var/mob/C = pick(candidates)
|
||||
spawn_antag(C, get_turf(src.loc), initial(demon_type.name), user)
|
||||
to_chat(user, "[shatter_msg]")
|
||||
to_chat(user, "[veil_msg]")
|
||||
playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1)
|
||||
qdel(src)
|
||||
else
|
||||
used = FALSE
|
||||
to_chat(user, "<span class='notice'>The demons do not respond to your summon. Perhaps you should try again later.</span>")
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", mob/user)
|
||||
var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.vialspawned = TRUE
|
||||
S.holder = holder
|
||||
S.key = C.key
|
||||
S.mind.assigned_role = S.name
|
||||
S.mind.special_role = S.name
|
||||
ticker.mode.traitors += S.mind
|
||||
var/datum/objective/assassinate/KillDaWiz = new /datum/objective/assassinate
|
||||
KillDaWiz.owner = S.mind
|
||||
KillDaWiz.target = user.mind
|
||||
KillDaWiz.explanation_text = "[objective_verb] [user.real_name], the one who was foolish enough to summon you."
|
||||
S.mind.objectives += KillDaWiz
|
||||
var/datum/objective/KillDaCrew = new /datum/objective
|
||||
KillDaCrew.owner = S.mind
|
||||
KillDaCrew.explanation_text = "[objective_verb] everyone else while you're at it."
|
||||
S.mind.objectives += KillDaCrew
|
||||
S.mind.objectives += KillDaCrew
|
||||
to_chat(S, "<B>Objective #[1]</B>: [KillDaWiz.explanation_text]")
|
||||
to_chat(S, "<B>Objective #[2]</B>: [KillDaCrew.explanation_text]")
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
desc = "A magically infused bottle of clown love, distilled from \
|
||||
countless hugging attacks. Used in funny rituals to attract \
|
||||
adorable creatures."
|
||||
color = "#FF69B4" // HOT PINK
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence \
|
||||
lurking just beyond the veil...</span>"
|
||||
objective_verb = "Hug and Tickle"
|
||||
demon_type = /mob/living/simple_animal/slaughter/laughter
|
||||
@@ -0,0 +1,24 @@
|
||||
//A barebones antagonist team.
|
||||
/datum/team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
|
||||
/datum/team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/M in starting_members)
|
||||
add_member(M)
|
||||
else
|
||||
add_member(starting_members)
|
||||
|
||||
/datum/team/proc/is_solo()
|
||||
return members.len == 1
|
||||
|
||||
/datum/team/proc/add_member(datum/mind/new_member)
|
||||
members |= new_member
|
||||
|
||||
/datum/team/proc/remove_member(datum/mind/member)
|
||||
members -= member
|
||||
@@ -1,788 +0,0 @@
|
||||
/datum/cargoprofile
|
||||
var/name = "All Items"
|
||||
var/id = "all" // unique ID for the UI
|
||||
var/enabled = 1
|
||||
var/eject_speed = 1 // will change when emagged
|
||||
var/const/BIG_OBJECT_WORK = 10
|
||||
var/const/MOB_WORK = 10
|
||||
var/obj/machinery/programmable/master = null
|
||||
var/universal = 0 // set when both unary and binary machines work
|
||||
var/mobcheck = 0
|
||||
|
||||
var/list/whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
|
||||
var/list/blacklist = null
|
||||
var/dedicated_path = null // When constructing a new machine with this as default program, create a machine of the specified type instead.
|
||||
|
||||
|
||||
//contains: called to determine if an object/mob will be sorted by this profile
|
||||
//return 1 for any sortable item
|
||||
proc/contains(var/atom/A)
|
||||
if(!istype(A,/obj))
|
||||
if(!mobcheck || !istype(A,/mob))
|
||||
return 0
|
||||
else
|
||||
var/obj/O = A
|
||||
if(O.anchored)
|
||||
return 0
|
||||
//If you are using both white and blacklists, blacklists are absoulte, no matter what is whitelisted.
|
||||
//I understand this has some limitations. You cannot whitelist all items, blacklist weapons,
|
||||
// and then whitelist a specific weapon. Them's the breaks, kid.
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
//inlet_reaction: called when a filtered item is chosen by this profile.
|
||||
//W: Item chosen
|
||||
//S: input turf location
|
||||
//remaining: counts down how much more work the unloader wants to do this turn.
|
||||
//return the amount of work done.
|
||||
proc/inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(!W || !S || !master)
|
||||
return 0
|
||||
|
||||
if(istype(W,/obj/item))
|
||||
var/obj/item/I = W
|
||||
if(I.w_class > remaining)
|
||||
return 0
|
||||
I.loc = master
|
||||
master.types[W.type] = src
|
||||
return I.w_class
|
||||
|
||||
|
||||
if(istype(W,/obj/structure) || istype(W,/obj/machinery)) // closets, big deliveries, portable atmospherics, unconnected stuff
|
||||
if(remaining < BIG_OBJECT_WORK)
|
||||
return 0
|
||||
var/obj/O = W
|
||||
O.loc = master
|
||||
master.types[O.type] = src
|
||||
return BIG_OBJECT_WORK
|
||||
|
||||
//Not item, structure, machinery, or mob
|
||||
return 0
|
||||
|
||||
//outlet_reaction: called when a stored object is ejected
|
||||
//W: the item in question
|
||||
//D: the destination turf
|
||||
proc/outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(!W || !D || !master)
|
||||
return
|
||||
|
||||
if(master.emagged)
|
||||
// emagging is not an industry-approved practice.
|
||||
// some malfunctions may occur.
|
||||
eject_speed = rand(0,4)
|
||||
D = get_step(D,master.outdir)
|
||||
while(prob(20))
|
||||
if(master.outdir == NORTH || master.outdir == SOUTH)
|
||||
D = get_step(D,pick(EAST,WEST,master.outdir))
|
||||
else
|
||||
D = get_step(D,pick(NORTH,SOUTH,master.outdir))
|
||||
|
||||
if(istype(W,/obj))
|
||||
var/obj/O = W
|
||||
O.loc = master.loc
|
||||
O.dir = master.outdir
|
||||
O.throw_at(D,eject_speed,eject_speed)
|
||||
return
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Profiles
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/datum/cargoprofile/boxes
|
||||
name = "Move Small Containers"
|
||||
id = "boxes"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/storage, /obj/item/storage/bag/money, /obj/item/evidencebag,
|
||||
/obj/item/storage/bag/tray, /obj/item/pizzabox, /obj/item/clipboard,
|
||||
/obj/item/smallDelivery, /obj/structure/bigDelivery)
|
||||
|
||||
/datum/cargoprofile/cargo
|
||||
name = "Move Large Containers"
|
||||
id = "cargo"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/structure/closet,/obj/structure/ore_box)
|
||||
|
||||
// Make an honest attempt to move other things out of the way
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
for(var/obj/O in D)
|
||||
if(O.density && !O.anchored)
|
||||
step_away(O,src) // move forward first
|
||||
if(O.loc == D)
|
||||
step_away(O,D) // move anywhere
|
||||
..(W,D)
|
||||
|
||||
/datum/cargoprofile/cargo/empty
|
||||
name = "Move Empty Large Containers"
|
||||
id = "cargo-empty"
|
||||
contains(var/atom/A)
|
||||
return (..(A) && (A.contents.len == 0))
|
||||
/datum/cargoprofile/cargo/full
|
||||
name = "Move Full Large Containers"
|
||||
id = "cargo-full"
|
||||
contains(var/atom/A)
|
||||
return (..(A) && (A.contents.len > 0))
|
||||
|
||||
/datum/cargoprofile/supplies
|
||||
name = "Building Supplies"
|
||||
id = "supplies"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/stack/cable_coil,/obj/item/stack/rods,
|
||||
/obj/item/stack/sheet/metal,/obj/item/stack/sheet/plasteel,
|
||||
/obj/item/stack/sheet/glass,/obj/item/stack/sheet/rglass,
|
||||
/obj/item/stack/tile,/obj/item/light)
|
||||
//todo: maybe stack things while we're here?
|
||||
|
||||
/datum/cargoprofile/exotics
|
||||
name = "Exotic materials"
|
||||
id = "exotics"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/coin, /obj/item/stack/spacecash, /obj/item/seeds,
|
||||
/obj/item/stack/sheet/mineral,/obj/item/stack/sheet/wood,/obj/item/stack/sheet/leather)
|
||||
|
||||
/datum/cargoprofile/organics
|
||||
name = "Organics, chemicals, and Paraphernalia"
|
||||
id = "organics"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/tank,/obj/item/reagent_containers,
|
||||
/obj/item/stack/medical,/obj/item/storage/pill_bottle,/obj/item/gun/syringe,
|
||||
/obj/item/grenade/plastic/c4,/obj/item/grenade,/obj/item/ammo_box,
|
||||
/obj/item/gun/grenadelauncher,/obj/item/flamethrower, /obj/item/lighter,
|
||||
/obj/item/match,/obj/item/weldingtool)
|
||||
|
||||
/datum/cargoprofile/food
|
||||
name = "Food"
|
||||
id = "food"
|
||||
blacklist = null // something should probably go here
|
||||
whitelist = list(/obj/item/reagent_containers/food)
|
||||
|
||||
/datum/cargoprofile/chemical
|
||||
name = "Chemicals and Paraphernalia"
|
||||
id = "chemical"
|
||||
blacklist = list(/obj/item/reagent_containers/food)
|
||||
whitelist = list(/obj/item/reagent_containers,/obj/item/stack/medical,/obj/item/storage/pill_bottle,
|
||||
/obj/item/gun/syringe,/obj/item/grenade/chem_grenade,/obj/item/dnainjector,
|
||||
/obj/item/storage/belt/medical,/obj/item/storage/firstaid,/obj/item/implanter)
|
||||
|
||||
/datum/cargoprofile/pressure
|
||||
name = "air tanks"
|
||||
id = "pressure"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/tank,/obj/machinery/portable_atmospherics,
|
||||
/obj/item/flamethrower)
|
||||
//Am I missing any?
|
||||
/datum/cargoprofile/pressure/empty
|
||||
name = "empty air tanks"
|
||||
id = "pressure-low"
|
||||
var/lowpressure = ONE_ATMOSPHERE
|
||||
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
var/pressure = ONE_ATMOSPHERE * 10 // In case of fallthrough, fail test
|
||||
if(istype(A,/obj/item/tank))
|
||||
var/obj/item/tank/T = A
|
||||
pressure = T.air_contents.return_pressure()
|
||||
if(istype(A,/obj/item/flamethrower))
|
||||
var/obj/item/flamethrower/T = A
|
||||
if(!T.ptank)
|
||||
return 0
|
||||
pressure = T.ptank.air_contents.return_pressure()
|
||||
if(istype(A,/obj/machinery/portable_atmospherics))
|
||||
var/obj/machinery/portable_atmospherics/P = A
|
||||
pressure = P.air_contents.return_pressure()
|
||||
|
||||
if(pressure < lowpressure)
|
||||
return 1
|
||||
|
||||
return 0// Not container or failed low pressure check
|
||||
|
||||
/datum/cargoprofile/pressure/full
|
||||
name = "full air tanks"
|
||||
id = "pressure-high"
|
||||
var/highpressure = ONE_ATMOSPHERE * 15 // stolen from canister.dm; Is this right?
|
||||
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
var/pressure = 0 // In case of fallthrough, fail test
|
||||
if(istype(A,/obj/item/tank))
|
||||
var/obj/item/tank/T = A
|
||||
pressure = T.air_contents.return_pressure()
|
||||
if(istype(A,/obj/item/flamethrower))
|
||||
var/obj/item/flamethrower/T = A
|
||||
if(!T.ptank)
|
||||
return 0
|
||||
pressure = T.ptank.air_contents.return_pressure()
|
||||
if(istype(A,/obj/machinery/portable_atmospherics))
|
||||
var/obj/machinery/portable_atmospherics/P = A
|
||||
pressure = P.air_contents.return_pressure()
|
||||
|
||||
if(pressure > highpressure)
|
||||
return 1
|
||||
|
||||
return 0// Not container or failed high pressure check
|
||||
|
||||
/datum/cargoprofile/clothing
|
||||
name = "Crew Kit"
|
||||
id = "clothing"
|
||||
blacklist = list(/obj/item/tank/plasma,/obj/item/tank/anesthetic, // the rest are air tanks
|
||||
/obj/item/clothing/mask/facehugger) // NOT CLOTHING AT ALLLLL
|
||||
whitelist = list(/obj/item/clothing,/obj/item/storage/belt,/obj/item/storage/backpack,
|
||||
/obj/item/radio/headset,/obj/item/pda,/obj/item/card/id,/obj/item/tank,
|
||||
/obj/item/restraints/handcuffs, /obj/item/restraints/legcuffs)
|
||||
|
||||
/datum/cargoprofile/trash
|
||||
name = "Trash"
|
||||
id = "trash"
|
||||
//Note that this filters out blueprints because they are a paper item. Do NOT throw out the station blueprints unless you be trollin'.
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/trash,/obj/item/toy,/obj/item/reagent_containers/food/snacks/ectoplasm,/obj/item/grown/bananapeel,/obj/item/broken_bottle,/obj/item/bikehorn,
|
||||
/obj/item/cigbutt,/obj/item/poster/random_contraband,/obj/item/grown/corncob,/obj/item/paper,/obj/item/shard,
|
||||
/obj/item/sord,/obj/item/photo,/obj/item/folder,
|
||||
/obj/item/areaeditor/blueprints,/obj/item/poster/random_contraband,/obj/item/kitchen,/obj/item/book,/obj/item/clothing/mask/facehugger)
|
||||
|
||||
/datum/cargoprofile/weapons
|
||||
name = "Weapons & Illegals"
|
||||
id = "weapons"
|
||||
blacklist = null
|
||||
//This one is hard since 'weapon contains a lot of things better categorized as devices
|
||||
whitelist = list(/obj/item/banhammer,/obj/item/sord,/obj/item/claymore,/obj/item/holo/esword,
|
||||
/obj/item/flamethrower,/obj/item/grenade,/obj/item/gun,/obj/item/hatchet,/obj/item/katana,
|
||||
/obj/item/kitchen/knife,/obj/item/melee,/obj/item/nullrod,/obj/item/pickaxe,/obj/item/twohanded,
|
||||
/obj/item/grenade/plastic/c4,/obj/item/scalpel,/obj/item/shield,/obj/item/grown/nettle/death)
|
||||
|
||||
/datum/cargoprofile/tools
|
||||
name = "Devices & Tools"
|
||||
id = "tools"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item,/obj/item/card,/obj/item/cartridge,/obj/item/cautery,/obj/item/stock_parts/cell,/obj/item/circuitboard,
|
||||
/obj/item/aiModule,/obj/item/airalarm_electronics,/obj/item/airlock_electronics,/obj/item/circular_saw,
|
||||
/obj/item/crowbar,/obj/item/disk,/obj/item/firealarm_electronics,/obj/item/hand_tele,
|
||||
/obj/item/hand_labeler,/obj/item/hemostat,/obj/item/mop,/obj/item/locator,/obj/item/cultivator,
|
||||
/obj/item/stack/packageWrap,/obj/item/pen,/obj/item/pickaxe,/obj/item/pinpointer,
|
||||
/obj/item/rcd,/obj/item/rcd_ammo,/obj/item/retractor,/obj/item/rsf,/obj/item/scalpel,
|
||||
/obj/item/screwdriver,/obj/item/shovel,/obj/item/soap,/obj/item/stamp,/obj/item/storage/bag/tray,/obj/item/weldingtool,
|
||||
/obj/item/wirecutters,/obj/item/wrench,/obj/item/extinguisher)
|
||||
|
||||
/datum/cargoprofile/finished
|
||||
name = "Completed Robots"
|
||||
id = "finished"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/mecha,/mob/living/simple_animal/bot,/mob/living/silicon/robot)
|
||||
mobcheck = 1
|
||||
//todo: detect and allow finished cyborg endoskeletons with no brain
|
||||
contains(var/atom/A)
|
||||
if(..())
|
||||
return 1
|
||||
if(istype(A,/mob))
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/cargoprofile/stripping
|
||||
name = "Auto-Frisker"
|
||||
id = "frisk"
|
||||
blacklist = null
|
||||
whitelist = list(/mob/living/carbon/human)
|
||||
mobcheck = 1
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Overrides (Special Functions)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/datum/cargoprofile/cargo/unload
|
||||
name = "Unload Cargo Boxes"
|
||||
id = "cargounload"
|
||||
enabled = 0
|
||||
dedicated_path = /obj/machinery/programmable/unloader
|
||||
|
||||
//override the detection to only accept crates with something in it.
|
||||
//if it doesn't, this object may be handled by another handler.
|
||||
contains(var/atom/A)
|
||||
if(..(A))
|
||||
if(istype(A,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = A
|
||||
if(!C.can_open() && !C.opened && !master.emagged) // must be able to access the contents
|
||||
return 0
|
||||
if(A.contents.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//instead of moving the box, strip it of its contents
|
||||
inlet_reaction(var/obj/W,var/turf/S, var/remaining)
|
||||
//W should only be crate or ore box, although this will work on anything with contents...
|
||||
var/I = 0
|
||||
if(istype(W,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = W
|
||||
if(!C.can_open() && !C.opened) // must be able to access the contents
|
||||
if(master.emagged && remaining >= BIG_OBJECT_WORK)
|
||||
if(prob(10))
|
||||
C.welded = 0
|
||||
if("broken" in C.vars)
|
||||
C:broken = 1
|
||||
C.open()
|
||||
C.update_icon()
|
||||
master.visible_message("<span class='warning'>[master] breaks open [C]!</span>")
|
||||
else
|
||||
master.visible_message("<span class='notice'>[master] is trying to force [C] open!</span>")
|
||||
|
||||
master.sleep += 1 // mechanical strain
|
||||
return BIG_OBJECT_WORK
|
||||
master.visible_message("<span class='notice'>[master] is trying to open [C], but can't!</span>")
|
||||
master.sleep = 5
|
||||
return 0
|
||||
|
||||
for(var/obj/item/O in W.contents)
|
||||
if(I > remaining)
|
||||
return
|
||||
if(O.w_class > (remaining - I))
|
||||
continue
|
||||
O.loc = master
|
||||
master.types[O.type] = src
|
||||
if(O.w_class > 0)
|
||||
I += O.w_class
|
||||
else
|
||||
I++
|
||||
if(!W.contents.len && istype(W,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = W
|
||||
C.open()
|
||||
return I
|
||||
|
||||
|
||||
//Inlet stacker: used when the output is a volatile space (conveyor or another unit's input).
|
||||
//Does not output a stack until it is full.
|
||||
/datum/cargoprofile/in_stacker
|
||||
name = "Hold and Stack"
|
||||
id = "instacker"
|
||||
universal = 1
|
||||
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/stacker
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(!I.amount) // todo: am I making a bad assumption here?
|
||||
qdel(I)
|
||||
return
|
||||
for(var/obj/item/stack/O in master.contents)
|
||||
if(O.type == I.type && O.amount < O.max_amount)
|
||||
if(I.amount + O.amount <= O.max_amount)
|
||||
O.amount += I.amount
|
||||
qdel(I)
|
||||
return O.w_class
|
||||
var/leftover = I.amount + O.amount - O.max_amount
|
||||
O.amount = O.max_amount
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = master
|
||||
master.types[I.type] = src
|
||||
return I.w_class
|
||||
if(istype(W,/obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/I = W
|
||||
if(!I.amount) // todo: am I making a bad assumption here?
|
||||
qdel(I)
|
||||
return
|
||||
for(var/obj/item/stack/cable_coil/O in master.contents)
|
||||
if(O.type == I.type && O.amount < MAXCOIL)
|
||||
if(I.amount + O.amount <= MAXCOIL)
|
||||
O.amount += I.amount
|
||||
qdel(I)
|
||||
return O.w_class
|
||||
var/leftover = I.amount + O.amount - MAXCOIL
|
||||
O.amount = MAXCOIL
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = master
|
||||
master.types[I.type] = src
|
||||
return I.w_class
|
||||
|
||||
//If the stack isn't finished yet, don't eject it
|
||||
//unless this profile has been disabled.
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(src.enabled && (I.amount < I.max_amount))
|
||||
return // Still needs to be stacked
|
||||
..(W,D)
|
||||
if(istype(W,/obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/I = W
|
||||
if(src.enabled && (I.amount < MAXCOIL))
|
||||
return // Still needs to be stacked
|
||||
..(W,D)
|
||||
|
||||
//Outlet stacker: used when the output square can be trusted.
|
||||
//Outputs immediately, adding to stacks in the outlet.
|
||||
/datum/cargoprofile/unary/stacker
|
||||
name = "Stack Items"
|
||||
id = "ustacker"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/stacker
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
|
||||
//Only pick it up if you are going to stack it
|
||||
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
if(I.amount >= I.max_amount)
|
||||
return 0
|
||||
for(var/obj/item/stack/other in S.contents)
|
||||
if(other.type == I.type && other != I && other.amount < other.max_amount)
|
||||
return ..(W,S,remaining)
|
||||
return 0
|
||||
|
||||
if(istype(W,/obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/I = W
|
||||
if(I.amount >= MAXCOIL)
|
||||
return 0
|
||||
for(var/obj/item/stack/cable_coil/other in S.contents)
|
||||
if(other != I && other.amount < MAXCOIL)
|
||||
return ..(W,S,remaining)
|
||||
return 0
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/stack))
|
||||
var/obj/item/stack/I = W
|
||||
for(var/obj/item/stack/O in D.contents)
|
||||
if(O.type == I.type && O.amount < O.max_amount)
|
||||
if(I.amount + O.amount <= O.max_amount)
|
||||
O.amount += I.amount
|
||||
qdel(I)
|
||||
return
|
||||
var/leftover = I.amount + O.amount - O.max_amount
|
||||
O.amount = O.max_amount
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = D
|
||||
return
|
||||
if(istype(W,/obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/I = W
|
||||
for(var/obj/item/stack/cable_coil/O in D.contents)
|
||||
if(O.type == I.type && O.amount < MAXCOIL)
|
||||
if(I.amount + O.amount <= MAXCOIL) // Why did they make it a #define.
|
||||
O.amount += I.amount
|
||||
O.update_icon()
|
||||
qdel(I)
|
||||
return
|
||||
var/leftover = I.amount + O.amount - MAXCOIL // That wasn't a question
|
||||
O.amount = MAXCOIL // It was a complaint
|
||||
I.amount = leftover
|
||||
continue
|
||||
//end for
|
||||
I.loc = D
|
||||
return
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Dubious Overrides (For emag use)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//Clogs up the unloader. And, there may be devious uses for it...
|
||||
/datum/cargoprofile/slow
|
||||
name = "Slow unloader"
|
||||
id = "slow"
|
||||
whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
|
||||
blacklist = list()
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
if(..())
|
||||
return remaining
|
||||
|
||||
/datum/cargoprofile/unary/shredder
|
||||
name = "Paper Shredder"
|
||||
id = "shredder"
|
||||
blacklist = null
|
||||
whitelist = list(/obj/item/paper,/obj/item/book,/obj/item/clipboard,/obj/item/folder,/obj/item/photo)
|
||||
universal = 1
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/shredder
|
||||
|
||||
|
||||
|
||||
proc/cliptags(var/Text)
|
||||
//Removes all html tags
|
||||
var/index
|
||||
var/index2
|
||||
index = findtextEx(Text,"<")
|
||||
while(index)
|
||||
index2 = findtextEx(Text,">",index)
|
||||
if(!index2)
|
||||
return copytext(Text,1,index)
|
||||
Text = "[copytext(Text,1,index)][copytext(Text,index2+1,0)]"
|
||||
index = findtextEx(Text,"<")
|
||||
//should have trimmed that text there pretty good
|
||||
return Text
|
||||
|
||||
|
||||
//Recurses through the text, removing large chunks
|
||||
proc/garbletext(var/Text)
|
||||
var/l = length(Text)
|
||||
if(l <= 3)
|
||||
if(prob(20))
|
||||
return pick("#","|","/","*",".","."," ","."," "," ")
|
||||
return Text
|
||||
if(prob(50))
|
||||
return "[garbletext(copytext(Text,1,l/2))][garbletext(copytext(Text,l/2,0))]"
|
||||
if(prob(50))
|
||||
return "[pick("#","|","/","*",".","."," ","."," "," ")][garbletext(copytext(Text,1,l/2))]"
|
||||
return "[garbletext(copytext(Text,l/2,0))][pick("#","|","/","*",".","."," ","."," "," ")]"
|
||||
|
||||
proc/garble_keeptags(var/Text)
|
||||
var/list/L = splittext(Text,">")
|
||||
var/result = ""
|
||||
for(var/string in L)
|
||||
var/index = findtextEx(string,"<")
|
||||
if(index!=1)
|
||||
result += "[garbletext(copytext(string,1,index))][copytext(string,index)]>"
|
||||
else
|
||||
result += "[string]>"
|
||||
return copytext(result,1,lentext(result))
|
||||
|
||||
|
||||
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
if(istype(W,/obj/item/paper/crumpled))
|
||||
qdel(W)
|
||||
return
|
||||
if(istype(W,/obj/item/clipboard) || istype(W,/obj/item/folder))
|
||||
// destroy folder, various effects on contents
|
||||
for(var/obj/item/I in W.contents)
|
||||
if(prob(25))//JUNK IT
|
||||
qdel(I)
|
||||
else if(prob(50)) //We've been over this. I can't just take it apart with a crowbar.
|
||||
var/obj/item/paper/crumpled/P = new(master.loc)
|
||||
if(I.name)
|
||||
P.name = garbletext(I.name)
|
||||
if(prob(66))
|
||||
P.fingerprints = I.fingerprints
|
||||
P.fingerprintshidden = I.fingerprintshidden
|
||||
if(istype(I,/obj/item/paper))
|
||||
var/obj/item/paper/O = I
|
||||
P.info = garble_keeptags(O.info)
|
||||
qdel(I)
|
||||
..(P,D)
|
||||
else
|
||||
..(I,D) // Eject
|
||||
qdel(W) //destroy container
|
||||
return
|
||||
if(prob(50)) //JUNK IT NOW!
|
||||
var/obj/item/paper/crumpled/P = new(master.loc)
|
||||
P.name = W.name
|
||||
var/obj/item/I = W
|
||||
if(prob(66))
|
||||
P.fingerprints = I.fingerprints
|
||||
P.fingerprintshidden = I.fingerprintshidden
|
||||
if(istype(I,/obj/item/paper))
|
||||
var/obj/item/paper/O = I
|
||||
if(O.info)
|
||||
P.info = garble_keeptags(O.info)
|
||||
if(istype(I,/obj/item/book))
|
||||
var/obj/item/book/B = I
|
||||
if(B.dat)
|
||||
P.info = garble_keeptags(B.dat)
|
||||
if(B.carved && B.store)
|
||||
..(B.store,D)
|
||||
qdel(W)
|
||||
..(P,D)
|
||||
else //I want it junked
|
||||
qdel(W)
|
||||
return
|
||||
|
||||
/datum/cargoprofile/unary/gibber
|
||||
name = "human shredding"
|
||||
id = "flesh"
|
||||
whitelist = list(/mob/living/carbon,/mob/living/simple_animal)
|
||||
blacklist = null
|
||||
mobcheck = 1
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
var/mob/living/M = W
|
||||
if(istype(M) && (remaining > MOB_WORK))
|
||||
//this is necessarily damaging
|
||||
var/damage = rand(1,5)
|
||||
to_chat(M, "<span class='danger'>The unloading machine grabs you with a hard metallic claw!</span>")
|
||||
M.reset_perspective(master)
|
||||
M.loc = master
|
||||
master.types[M.type] = src
|
||||
M.apply_damage(damage) // todo: ugly
|
||||
M.visible_message("<span class='warning'>[M.name] gets pulled into the machine!</span>")
|
||||
return MOB_WORK
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
var/mob/living/M = W
|
||||
var/bruteloss = M.bruteloss
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/C = M
|
||||
for(var/obj/item/organ/external/L in C.bodyparts)
|
||||
bruteloss += L.brute_dam
|
||||
if(bruteloss < 100) // requires tenderization
|
||||
M.apply_damage(rand(5,15),BRUTE)
|
||||
to_chat(M, "The machine is tearing you apart!")
|
||||
master.visible_message("<span class='warning'>[master] makes a squishy grinding noise.</span>")
|
||||
return
|
||||
M.loc = master.loc
|
||||
M.gib()
|
||||
return
|
||||
|
||||
|
||||
/datum/cargoprofile/people
|
||||
name = "Manhandling"
|
||||
id = "people"
|
||||
|
||||
whitelist = null
|
||||
blacklist = list(/mob/camera,/mob/new_player,/mob/living/simple_animal/hostile/blob/blobspore,/mob/living/simple_animal/hostile/creature,
|
||||
/mob/living/simple_animal/hostile/spaceWorm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead)
|
||||
universal = 1
|
||||
mobcheck = 1
|
||||
|
||||
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
var/mob/living/M = W
|
||||
if(remaining > MOB_WORK)
|
||||
//this is necessarily damaging
|
||||
var/damage = rand(1,5)
|
||||
to_chat(M, "<span class='danger'>The unloading machine grabs you with a hard metallic claw!</span>")
|
||||
M.forceMove(master)
|
||||
master.types[M.type] = src
|
||||
M.apply_damage(damage) // todo: ugly
|
||||
M.visible_message("<span class='warning'>[M.name] gets pulled into the machine!</span>")
|
||||
return MOB_WORK
|
||||
|
||||
outlet_reaction(var/atom/W,var/turf/D)
|
||||
var/mob/living/M = W
|
||||
M.forceMove(master.loc)
|
||||
M.dir = master.outdir
|
||||
|
||||
D = get_step(D,master.outdir) // throw attempt
|
||||
eject_speed = rand(0,4)
|
||||
|
||||
M.visible_message("<span class='notice'>[M.name] is ejected from the unloader.</span>")
|
||||
M.throw_at(D,eject_speed,eject_speed)
|
||||
return
|
||||
|
||||
/datum/cargoprofile/unary/trainer
|
||||
name = "Boxing Trainer"
|
||||
id = "trainer"
|
||||
blacklist = list()
|
||||
whitelist = list(/mob/living/carbon/human)
|
||||
mobcheck = 1
|
||||
|
||||
var/const/PUNCH_WORK = 6
|
||||
|
||||
dedicated_path = /obj/machinery/programmable/unary/trainer
|
||||
|
||||
contains(var/atom/A)
|
||||
if(!istype(A,/mob))
|
||||
return 0
|
||||
if(blacklist)
|
||||
for(var/T in blacklist)
|
||||
if(istype(A,T))
|
||||
return 0
|
||||
if(whitelist)
|
||||
for(var/T in whitelist)
|
||||
if(istype(A,T))
|
||||
return 1
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/punch(var/mob/living/carbon/human/M,var/maxpunches)
|
||||
//stolen from holographic boxing gloves code
|
||||
//This should probably be done BY the mob, however, the attack code will be expecting a source mob.
|
||||
|
||||
var/damage
|
||||
if(prob(75))
|
||||
damage = rand(0, 6) // pap
|
||||
else
|
||||
damage = rand(0, 12) // thwack
|
||||
|
||||
if(!damage)
|
||||
playsound(master.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
master.visible_message("<span class='warning'>\The [src] punched at [M], but whiffed!</span>")
|
||||
|
||||
if(maxpunches > 1 && prob(50)) // Follow through on a miss, 50% chance
|
||||
return punch(M,maxpunches - 1) + 1
|
||||
return 1
|
||||
var/obj/item/organ/external/affecting = M.get_organ(ran_zone("chest",50))
|
||||
var/armor_block = M.run_armor_check(affecting, "melee")
|
||||
|
||||
playsound(master.loc, "punch", 25, 1, -1)
|
||||
master.visible_message("<span class='danger'>\The [src] has punched [M]!</span>")
|
||||
if(!master.emagged)
|
||||
M.apply_damage(damage, STAMINA, affecting, armor_block) // Clean fight
|
||||
else
|
||||
M.apply_damage(damage, BRUTE, affecting, armor_block) // Foul! Foooul!
|
||||
|
||||
if(damage >= 9)
|
||||
master.visible_message("<span class='danger'>\The [src] has weakened [M]!</span>")
|
||||
M.apply_effect(4, WEAKEN, armor_block)
|
||||
if(!master.emagged)
|
||||
master.sleep = 1
|
||||
return maxpunches // The machine is not so sophisticated as to not gloat
|
||||
else
|
||||
if(prob(25)) // Follow through on a hit, 25% chance. Pause after.
|
||||
return punch(M,maxpunches-1) + 1
|
||||
return 1
|
||||
|
||||
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
|
||||
//stolen from boxing gloves code
|
||||
var/mob/living/carbon/human/M = W
|
||||
if((M.lying || (M.health - M.staminaloss < 25))&& !master.emagged)
|
||||
to_chat(M, "\The [src] gives you a break.")
|
||||
master.sleep+=5
|
||||
return 0 // Be polite
|
||||
var/punches = punch(M,remaining / PUNCH_WORK)
|
||||
if(punches>1)master.sleep++
|
||||
return punches * PUNCH_WORK
|
||||
@@ -1,7 +0,0 @@
|
||||
datum
|
||||
computer
|
||||
var/name
|
||||
folder
|
||||
var/list/datum/computer/contents = list()
|
||||
|
||||
file
|
||||
@@ -255,7 +255,7 @@ var/record_id_num = 1001
|
||||
if(PDA_Manifest.len)
|
||||
PDA_Manifest.Cut()
|
||||
|
||||
if(H.mind && (H.mind.assigned_role != "MODE"))
|
||||
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
|
||||
var/assignment
|
||||
if(H.mind.role_alt_title)
|
||||
assignment = H.mind.role_alt_title
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum
|
||||
var/gc_destroyed //Time when this object was destroyed.
|
||||
var/list/active_timers //for SStimer
|
||||
var/list/datum_components //for /datum/components
|
||||
var/var_edited = FALSE //Warranty void if seal is broken
|
||||
|
||||
@@ -16,6 +17,14 @@
|
||||
/datum/proc/Destroy(force = FALSE, ...)
|
||||
tag = null
|
||||
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
for(var/thing in timers)
|
||||
var/datum/timedevent/timer = thing
|
||||
if(timer.spent)
|
||||
continue
|
||||
qdel(timer)
|
||||
|
||||
var/list/dc = datum_components
|
||||
if(dc)
|
||||
var/all_components = dc[/datum/component]
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
output_atoms (list of atoms) The destination(s) for the sounds
|
||||
|
||||
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
|
||||
mid_length (num) The length to wait between playing mid_sounds
|
||||
|
||||
start_sound (soundfile) Played before starting the mid_sounds loop
|
||||
start_length (num) How long to wait before starting the main loop after playing start_sound
|
||||
|
||||
end_sound (soundfile) The sound played after the main loop has concluded
|
||||
|
||||
chance (num) Chance per loop to play a mid_sound
|
||||
volume (num) Sound output volume
|
||||
muted (bool) Private. Used to stop the sound loop.
|
||||
max_loops (num) The max amount of loops to run for.
|
||||
direct (bool) If true plays directly to provided atoms instead of from them
|
||||
*/
|
||||
/datum/looping_sound
|
||||
var/list/atom/output_atoms
|
||||
var/mid_sounds
|
||||
var/mid_length
|
||||
var/start_sound
|
||||
var/start_length
|
||||
var/end_sound
|
||||
var/chance
|
||||
var/volume = 100
|
||||
var/muted = TRUE
|
||||
var/max_loops
|
||||
var/direct
|
||||
|
||||
/datum/looping_sound/New(list/_output_atoms = list(), start_immediately = FALSE, _direct = FALSE)
|
||||
if(!mid_sounds)
|
||||
WARNING("A looping sound datum was created without sounds to play.")
|
||||
return
|
||||
|
||||
output_atoms = _output_atoms
|
||||
direct = _direct
|
||||
|
||||
if(start_immediately)
|
||||
start()
|
||||
|
||||
/datum/looping_sound/Destroy()
|
||||
stop()
|
||||
output_atoms = null
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/proc/start(atom/add_thing)
|
||||
if(add_thing)
|
||||
output_atoms |= add_thing
|
||||
if(!muted)
|
||||
return
|
||||
muted = FALSE
|
||||
on_start()
|
||||
|
||||
/datum/looping_sound/proc/stop(atom/remove_thing)
|
||||
if(remove_thing)
|
||||
output_atoms -= remove_thing
|
||||
if(muted)
|
||||
return
|
||||
muted = TRUE
|
||||
|
||||
/datum/looping_sound/proc/sound_loop(looped = 0)
|
||||
if(muted || (max_loops && looped > max_loops))
|
||||
on_stop(looped)
|
||||
return
|
||||
if(!chance || prob(chance))
|
||||
play(get_sound(looped))
|
||||
addtimer(CALLBACK(src, .proc/sound_loop, ++looped), mid_length)
|
||||
|
||||
/datum/looping_sound/proc/play(soundfile)
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = open_sound_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
if(direct)
|
||||
SEND_SOUND(thing, S)
|
||||
else
|
||||
playsound(thing, S, volume)
|
||||
|
||||
/datum/looping_sound/proc/get_sound(looped, _mid_sounds)
|
||||
if(!_mid_sounds)
|
||||
. = mid_sounds
|
||||
else
|
||||
. = _mid_sounds
|
||||
while(!isfile(.) && !isnull(.))
|
||||
. = pickweight(.)
|
||||
|
||||
/datum/looping_sound/proc/on_start()
|
||||
var/start_wait = 0
|
||||
if(start_sound)
|
||||
play(start_sound)
|
||||
start_wait = start_length
|
||||
addtimer(CALLBACK(src, .proc/sound_loop), start_wait)
|
||||
|
||||
/datum/looping_sound/proc/on_stop(looped)
|
||||
if(end_sound)
|
||||
play(end_sound)
|
||||
@@ -0,0 +1,7 @@
|
||||
/datum/looping_sound/showering
|
||||
start_sound = 'sound/machines/shower/shower_start.ogg'
|
||||
start_length = 2
|
||||
mid_sounds = list('sound/machines/shower/shower_mid1.ogg' = 1,'sound/machines/shower/shower_mid2.ogg' = 1,'sound/machines/shower/shower_mid3.ogg' = 1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/shower/shower_end.ogg'
|
||||
volume = 20
|
||||
+78
-40
@@ -38,8 +38,8 @@
|
||||
|
||||
var/memory
|
||||
|
||||
var/assigned_role
|
||||
var/special_role
|
||||
var/assigned_role //assigned role is what job you're assigned to when you join the station.
|
||||
var/special_role //special roles are typically reserved for antags or roles like ERT. If you want to avoid a character being automatically announced by the AI, on arrival (becuase they're an off station character or something); ensure that special_role and assigned_role are equal.
|
||||
var/list/restricted_roles = list()
|
||||
|
||||
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
|
||||
@@ -54,6 +54,7 @@
|
||||
var/has_been_rev = 0//Tracks if this mind has been a rev or not
|
||||
|
||||
var/miming = 0 // Mime's vow of silence
|
||||
var/list/antag_datums
|
||||
var/speech_span // What span any body this mind has talks in.
|
||||
var/datum/faction/faction //associated faction
|
||||
var/datum/changeling/changeling //changeling holder
|
||||
@@ -72,17 +73,29 @@
|
||||
var/brigged_since = -1
|
||||
var/suicided = FALSE
|
||||
|
||||
New(var/key)
|
||||
src.key = key
|
||||
|
||||
//put this here for easier tracking ingame
|
||||
var/datum/money_account/initial_account
|
||||
|
||||
//zealot_master is a reference to the mob that converted them into a zealot (for ease of investigation and such)
|
||||
var/mob/living/carbon/human/zealot_master = null
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
src.key = key
|
||||
|
||||
|
||||
/datum/mind/Destroy()
|
||||
ticker.minds -= src
|
||||
if(islist(antag_datums))
|
||||
for(var/i in antag_datums)
|
||||
var/datum/antagonist/antag_datum = i
|
||||
if(antag_datum.delete_on_mind_deletion)
|
||||
qdel(i)
|
||||
antag_datums = null
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/transfer_to(mob/living/new_character)
|
||||
var/datum/atom_hud/antag/hud_to_transfer = antag_hud //we need this because leave_hud() will clear this list
|
||||
var/mob/living/old_current = current
|
||||
if(!istype(new_character))
|
||||
log_runtime(EXCEPTION("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob."), src)
|
||||
if(current) //remove ourself from our old body's mind variable
|
||||
@@ -95,6 +108,9 @@
|
||||
new_character.mind.current = null
|
||||
current = new_character //link ourself to our new body
|
||||
new_character.mind = src //and link our new body to ourself
|
||||
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
|
||||
var/datum/antagonist/A = a
|
||||
A.on_body_transfer(old_current, current)
|
||||
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
|
||||
transfer_actions(new_character)
|
||||
|
||||
@@ -525,8 +541,8 @@
|
||||
new_objective = new objective_path
|
||||
new_objective.owner = src
|
||||
new_objective:target = new_target:mind
|
||||
//Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
|
||||
new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role=="MODE" ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
|
||||
//Will display as special role if assigned mode is equal to special role.. Ninjas/commandos/nuke ops.
|
||||
new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role == new_target:mind:special_role ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
|
||||
|
||||
if("destroy")
|
||||
var/list/possible_targets = active_ais(1)
|
||||
@@ -726,7 +742,7 @@
|
||||
if(src in ticker.mode.revolutionaries)
|
||||
ticker.mode.revolutionaries -= src
|
||||
ticker.mode.update_rev_icons_removed(src)
|
||||
to_chat(current, "<span class='warning'>\red <FONT size = 3><B>You have proven your devotion to revolution! You are a head revolutionary now!</B></FONT></span>")
|
||||
to_chat(current, "<span class='userdanger'>You have proven your devotion to revolution! You are a head revolutionary now!</span>")
|
||||
else if(!(src in ticker.mode.head_revolutionaries))
|
||||
to_chat(current, "<span class='notice'>You are a member of the revolutionaries' leadership now!</span>")
|
||||
else
|
||||
@@ -1211,37 +1227,60 @@
|
||||
message_admins("[key_name_admin(usr)] has announced [key_name_admin(current)]'s objectives")
|
||||
|
||||
edit_memory()
|
||||
/*
|
||||
/datum/mind/proc/clear_memory(var/silent = 1)
|
||||
var/datum/game_mode/current_mode = ticker.mode
|
||||
|
||||
// remove traitor uplinks
|
||||
var/list/L = current.get_contents()
|
||||
for(var/t in L)
|
||||
if(istype(t, /obj/item/pda))
|
||||
if(t:uplink) qdel(t:uplink)
|
||||
t:uplink = null
|
||||
else if(istype(t, /obj/item/radio))
|
||||
if(t:traitorradio) qdel(t:traitorradio)
|
||||
t:traitorradio = null
|
||||
t:traitor_frequency = 0.0
|
||||
else if(istype(t, /obj/item/SWF_uplink) || istype(t, /obj/item/syndicate_uplink))
|
||||
if(t:origradio)
|
||||
var/obj/item/radio/R = t:origradio
|
||||
R.loc = current.loc
|
||||
R.traitorradio = null
|
||||
R.traitor_frequency = 0.0
|
||||
qdel(t)
|
||||
|
||||
// remove wizards spells
|
||||
//If there are more special powers that need removal, they can be procced into here./N
|
||||
current.spellremove(current)
|
||||
// Datum antag mind procs
|
||||
/datum/mind/proc/add_antag_datum(datum_type_or_instance, team)
|
||||
if(!datum_type_or_instance)
|
||||
return
|
||||
var/datum/antagonist/A
|
||||
if(!ispath(datum_type_or_instance))
|
||||
A = datum_type_or_instance
|
||||
if(!istype(A))
|
||||
return
|
||||
else
|
||||
A = new datum_type_or_instance()
|
||||
//Choose snowflake variation if antagonist handles it
|
||||
var/datum/antagonist/S = A.specialization(src)
|
||||
if(S && S != A)
|
||||
qdel(A)
|
||||
A = S
|
||||
if(!A.can_be_owned(src))
|
||||
qdel(A)
|
||||
return
|
||||
A.owner = src
|
||||
LAZYADD(antag_datums, A)
|
||||
A.create_team(team)
|
||||
var/datum/team/antag_team = A.get_team()
|
||||
if(antag_team)
|
||||
antag_team.add_member(src)
|
||||
A.on_gain()
|
||||
return A
|
||||
|
||||
// clear memory
|
||||
memory = ""
|
||||
special_role = null
|
||||
/datum/mind/proc/remove_antag_datum(datum_type)
|
||||
if(!datum_type)
|
||||
return
|
||||
var/datum/antagonist/A = has_antag_datum(datum_type)
|
||||
if(A)
|
||||
A.on_removal()
|
||||
return TRUE
|
||||
|
||||
*/
|
||||
|
||||
/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
|
||||
for(var/a in antag_datums)
|
||||
var/datum/antagonist/A = a
|
||||
A.on_removal()
|
||||
|
||||
/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
|
||||
if(!datum_type)
|
||||
return
|
||||
. = FALSE
|
||||
for(var/a in antag_datums)
|
||||
var/datum/antagonist/A = a
|
||||
if(check_subtypes && istype(A, datum_type))
|
||||
return A
|
||||
else if(A.type == datum_type)
|
||||
return A
|
||||
|
||||
/datum/mind/proc/find_syndicate_uplink()
|
||||
var/list/L = current.get_contents()
|
||||
@@ -1273,7 +1312,7 @@
|
||||
else
|
||||
current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"
|
||||
special_role = SPECIAL_ROLE_NUKEOPS
|
||||
assigned_role = "MODE"
|
||||
assigned_role = SPECIAL_ROLE_NUKEOPS
|
||||
to_chat(current, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
|
||||
ticker.mode.forge_syndicate_objectives(src)
|
||||
ticker.mode.greet_syndicate(src)
|
||||
@@ -1308,7 +1347,7 @@
|
||||
if(!(src in ticker.mode.wizards))
|
||||
ticker.mode.wizards += src
|
||||
special_role = SPECIAL_ROLE_WIZARD
|
||||
assigned_role = "MODE"
|
||||
assigned_role = SPECIAL_ROLE_WIZARD
|
||||
//ticker.mode.learn_basic_spells(current)
|
||||
if(!wizardstart.len)
|
||||
current.loc = pick(latejoin)
|
||||
@@ -1514,7 +1553,7 @@
|
||||
var/datum/objective/protect/mindslave/MS = new
|
||||
MS.owner = src
|
||||
MS.target = missionary.mind
|
||||
MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role=="MODE" ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
|
||||
MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
|
||||
objectives += MS
|
||||
for(var/datum/objective/objective in objectives)
|
||||
to_chat(current, "<B>Objective #1</B>: [objective.explanation_text]")
|
||||
@@ -1538,8 +1577,7 @@
|
||||
H.update_inv_w_uniform(0,0)
|
||||
|
||||
add_attack_logs(missionary, current, "Converted to a zealot for [convert_duration/600] minutes")
|
||||
addtimer(src, "remove_zealot", convert_duration, FALSE, jumpsuit) //deconverts after the timer expires
|
||||
|
||||
addtimer(CALLBACK(src, .proc/remove_zealot, jumpsuit), convert_duration) //deconverts after the timer expires
|
||||
return 1
|
||||
|
||||
/datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// module datum.
|
||||
// this is per-object instance, and shows the condition of the modules in the object
|
||||
// actual modules needed is referenced through modulestypes and the object type
|
||||
|
||||
/datum/module
|
||||
var/status // bits set if working, 0 if broken
|
||||
var/installed // bits set if installed, 0 if missing
|
||||
|
||||
// moduletypes datum
|
||||
// this is per-object type, and shows the modules needed for a type of object
|
||||
|
||||
/datum/moduletypes
|
||||
var/list/modcount = list() // assoc list of the count of modules for a type
|
||||
|
||||
|
||||
var/list/modules = list( // global associative list
|
||||
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
|
||||
|
||||
|
||||
/datum/module/New(var/obj/O)
|
||||
|
||||
var/type = O.type // the type of the creating object
|
||||
|
||||
var/mneed = mods.inmodlist(type) // find if this type has modules defined
|
||||
|
||||
if(!mneed) // not found in module list?
|
||||
qdel(src) // delete self, thus ending proc
|
||||
return
|
||||
|
||||
var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
|
||||
status = needed
|
||||
installed = needed
|
||||
|
||||
/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
|
||||
modules += type // index by type text
|
||||
modules[type] = modtextlist
|
||||
|
||||
/datum/moduletypes/proc/inmodlist(var/type)
|
||||
return ("[type]" in modules)
|
||||
|
||||
/datum/moduletypes/proc/getbitmask(var/type)
|
||||
var/count = modcount["[type]"]
|
||||
if(count)
|
||||
return 2**count-1
|
||||
|
||||
var/modtext = modules["[type]"]
|
||||
var/num = 1
|
||||
var/pos = 1
|
||||
|
||||
while(1)
|
||||
pos = findtext(modtext, ",", pos, 0)
|
||||
if(!pos)
|
||||
break
|
||||
else
|
||||
pos++
|
||||
num++
|
||||
|
||||
modcount += "[type]"
|
||||
modcount["[type]"] = num
|
||||
|
||||
return 2**num-1
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
belt = /obj/item/gun/projectile/automatic/pistol/deagle/camo
|
||||
l_ear = /obj/item/radio/headset/syndicate/alt
|
||||
l_pocket = /obj/item/pinpointer/advpinpointer
|
||||
r_pocket = null // stop them getting a radio uplink, they get an implant instead
|
||||
|
||||
backpack_contents = list(
|
||||
/obj/item/storage/box/engineer = 1,
|
||||
@@ -158,7 +159,6 @@
|
||||
|
||||
id_icon = "commander"
|
||||
id_access = "Syndicate Operative Leader"
|
||||
uplink_uses = 500
|
||||
|
||||
/datum/outfit/admin/syndicate/officer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
. = ..()
|
||||
@@ -613,15 +613,16 @@
|
||||
|
||||
uniform = /obj/item/clothing/under/solgov/rep
|
||||
back = /obj/item/storage/backpack/satchel
|
||||
glasses = /obj/item/clothing/glasses/hud/security/night
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
shoes = /obj/item/clothing/shoes/centcom
|
||||
l_ear = /obj/item/radio/headset
|
||||
l_ear = /obj/item/radio/headset/ert
|
||||
id = /obj/item/card/id/silver
|
||||
r_pocket = /obj/item/lighter/zippo/blue
|
||||
l_pocket = /obj/item/storage/fancy/cigarettes/cigpack_robustgold
|
||||
pda = /obj/item/pda
|
||||
backpack_contents = list(
|
||||
/obj/item/storage/box/survival = 1,
|
||||
/obj/item/storage/box/responseteam = 1,
|
||||
/obj/item/implanter/dust = 1,
|
||||
/obj/item/implanter/death_alarm = 1,
|
||||
)
|
||||
@@ -633,25 +634,33 @@
|
||||
|
||||
var/obj/item/card/id/I = H.wear_id
|
||||
if(istype(I))
|
||||
apply_to_card(I, H, get_centcom_access("VIP Guest"), "Solar Federation Representative")
|
||||
apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
|
||||
|
||||
|
||||
/datum/outfit/admin/solgov
|
||||
name = "Solar Federation Marine"
|
||||
|
||||
uniform = /obj/item/clothing/under/solgov
|
||||
suit = /obj/item/clothing/suit/armor/bulletproof
|
||||
back = /obj/item/storage/backpack/security
|
||||
belt = /obj/item/storage/belt/military/assault
|
||||
head = /obj/item/clothing/head/soft/solgov
|
||||
glasses = /obj/item/clothing/glasses/hud/security/night
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
shoes = /obj/item/clothing/shoes/combat
|
||||
l_ear = /obj/item/radio/headset/ert
|
||||
id = /obj/item/card/id
|
||||
l_hand = /obj/item/gun/projectile/automatic/ar
|
||||
r_pocket = /obj/item/flashlight/seclite
|
||||
pda = /obj/item/pda
|
||||
backpack_contents = list(
|
||||
/obj/item/storage/box/survival = 1,
|
||||
/obj/item/kitchen/knife/combat = 1,
|
||||
/obj/item/storage/box/responseteam = 1,
|
||||
/obj/item/ammo_box/magazine/m556 = 3,
|
||||
/obj/item/clothing/shoes/magboots = 1
|
||||
/obj/item/clothing/shoes/magboots = 1,
|
||||
/obj/item/gun/projectile/automatic/pistol/m1911 = 1,
|
||||
/obj/item/ammo_box/magazine/m45 = 2
|
||||
)
|
||||
var/is_tsf_lieutenant = FALSE
|
||||
|
||||
|
||||
/datum/outfit/admin/solgov/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
@@ -659,9 +668,14 @@
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
if(is_tsf_lieutenant)
|
||||
H.real_name = "Lieutenant [pick(last_names)]"
|
||||
else
|
||||
H.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]"
|
||||
H.name = H.real_name
|
||||
var/obj/item/card/id/I = H.wear_id
|
||||
if(istype(I))
|
||||
apply_to_card(I, H, get_centcom_access("VIP Guest"), name)
|
||||
apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
|
||||
|
||||
/datum/outfit/admin/solgov/lieutenant
|
||||
name = "Solar Federation Lieutenant"
|
||||
@@ -670,14 +684,16 @@
|
||||
head = /obj/item/clothing/head/soft/solgov/command
|
||||
back = /obj/item/storage/backpack/satchel
|
||||
l_hand = null
|
||||
belt = /obj/item/gun/projectile/automatic/pistol/deagle
|
||||
l_pocket = /obj/item/pinpointer/advpinpointer
|
||||
backpack_contents = list(
|
||||
/obj/item/storage/box/survival = 1,
|
||||
/obj/item/kitchen/knife/combat = 1,
|
||||
/obj/item/storage/box/responseteam = 1,
|
||||
/obj/item/melee/classic_baton/telescopic = 1,
|
||||
/obj/item/ammo_box/magazine/m50 = 2,
|
||||
/obj/item/clothing/shoes/magboots/advance = 1
|
||||
/obj/item/clothing/shoes/magboots/advance = 1,
|
||||
/obj/item/gun/projectile/automatic/pistol/deagle = 1,
|
||||
/obj/item/ammo_box/magazine/m50 = 2
|
||||
)
|
||||
is_tsf_lieutenant = TRUE
|
||||
|
||||
|
||||
/datum/outfit/admin/chrono
|
||||
name = "Chrono Legionnaire"
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets, mob/user = usr)
|
||||
|
||||
for(var/mob/living/target in targets)
|
||||
empulse(target.loc, emp_heavy, emp_light)
|
||||
empulse(target.loc, emp_heavy, emp_light, 1)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains
|
||||
to_chat(target, "<span class='warning'>You are somehow too bound to your current location to abandon it.</span>")
|
||||
continue
|
||||
addtimer(src, "do_jaunt", 0, FALSE, target)
|
||||
INVOKE_ASYNC(src, .proc/do_jaunt, target)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
|
||||
target.notransform = 1
|
||||
|
||||
@@ -1336,6 +1336,13 @@ var/list/uplink_items = list()
|
||||
item = /obj/item/storage/fancy/cigarettes/cigpack_syndicate
|
||||
cost = 2
|
||||
|
||||
/datum/uplink_item/badass/rapid
|
||||
name = "Gloves of the North Star"
|
||||
desc = "These gloves let the user punch people very fast. Does not improve weapon attack speed."
|
||||
reference = "RPGD"
|
||||
item = /obj/item/clothing/gloves/fingerless/rapid
|
||||
cost = 8
|
||||
|
||||
/datum/uplink_item/badass/bundle
|
||||
name = "Syndicate Bundle"
|
||||
desc = "Syndicate Bundles are specialised groups of items that arrive in a plain box. These items are collectively worth more than 20 telecrystals, but you do not know which specialisation you will receive."
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
|
||||
var/target_z = MAIN_STATION //The z-level to affect
|
||||
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
|
||||
|
||||
|
||||
var/overlay_layer = 10 //Since it's above everything else, this is the layer used by default. 2 is below mobs and walls if you need to use that.
|
||||
var/aesthetic = FALSE //If the weather has no purpose other than looks
|
||||
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
|
||||
@@ -70,7 +70,7 @@
|
||||
to_chat(M, telegraph_message)
|
||||
if(telegraph_sound)
|
||||
M << sound(telegraph_sound)
|
||||
addtimer(src, "start", telegraph_duration)
|
||||
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
|
||||
|
||||
/datum/weather/proc/start()
|
||||
if(stage >= MAIN_STAGE)
|
||||
@@ -85,7 +85,7 @@
|
||||
if(weather_sound)
|
||||
M << sound(weather_sound)
|
||||
weather_master.processing_weather |= src
|
||||
addtimer(src, "wind_down", weather_duration)
|
||||
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
|
||||
|
||||
/datum/weather/proc/wind_down()
|
||||
if(stage >= WIND_DOWN_STAGE)
|
||||
@@ -100,7 +100,7 @@
|
||||
if(end_sound)
|
||||
M << sound(end_sound)
|
||||
weather_master.processing_weather -= src
|
||||
addtimer(src, "end", end_duration)
|
||||
addtimer(CALLBACK(src, .proc/end), end_duration)
|
||||
|
||||
/datum/weather/proc/end()
|
||||
if(stage == END_STAGE)
|
||||
|
||||
Reference in New Issue
Block a user