This commit is contained in:
Ghommie
2020-03-08 02:33:27 +01:00
190 changed files with 2895 additions and 2115 deletions
+1 -2
View File
@@ -23,8 +23,7 @@ GLOBAL_PROTECT(protected_ranks)
name = init_name
if(!name)
qdel(src)
throw EXCEPTION("Admin rank created without name.")
return
CRASH("Admin rank created without name.")
if(init_rights)
rights = init_rights
include_rights = rights
+2 -4
View File
@@ -39,12 +39,10 @@ GLOBAL_PROTECT(href_token)
return
if(!ckey)
QDEL_IN(src, 0)
throw EXCEPTION("Admin datum created without a ckey")
return
CRASH("Admin datum created without a ckey")
if(!istype(R))
QDEL_IN(src, 0)
throw EXCEPTION("Admin datum created without a rank")
return
CRASH("Admin datum created without a rank")
target = ckey
name = "[ckey]'s admin datum ([R])"
rank = R
@@ -4,6 +4,7 @@
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.
var/show_roundend_report = TRUE
/datum/team/New(starting_members)
. = ..()
@@ -25,6 +26,8 @@
//Display members/victory/failure/objectives for the team
/datum/team/proc/roundend_report()
if(!show_roundend_report)
return
var/list/report = list()
report += "<span class='header'>[name]:</span>"
@@ -218,11 +218,16 @@
/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize()
. = ..()
if(!independent) //no pulling people deep into the blob
verbs -= /mob/living/verb/pulled
else
if(independent)
pass_flags &= ~PASSBLOB
/mob/living/simple_animal/hostile/blob/blobbernaut/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
if(!independent && ismob(AM))
if(!supress_message)
to_chat(src, "<span class='warning'>You are unable to grasp people in this form.</span>")
return FALSE
return ..()
/mob/living/simple_animal/hostile/blob/blobbernaut/Life()
if(..())
var/list/blobs_in_area = range(2, src)
@@ -303,8 +303,7 @@
/obj/structure/blob/proc/change_to(type, controller)
if(!ispath(type))
throw EXCEPTION("change_to(): invalid type for blob")
return
CRASH("change_to(): invalid type for blob")
var/obj/structure/blob/B = new type(src.loc, controller)
B.creation_action()
B.update_icon()
@@ -42,25 +42,18 @@
/obj/structure/closet/crate
var/mob/living/resident // This lets bloodsuckers claim any "closet" as a Coffin, so long as they could get into it and close it. This locks it in place, too.
/obj/structure/closet/crate/coffin
var/pryLidTimer = 250
can_weld_shut = FALSE
breakout_time = 200
/obj/structure/closet/crate/coffin/blackcoffin
name = "black coffin"
desc = "For those departed who are not so dear."
icon_state = "coffin"
icon = 'icons/obj/vamp_obj.dmi'
can_weld_shut = FALSE
resistance_flags = 0 // Start off with no bonuses.
open_sound = 'sound/bloodsucker/coffin_open.ogg'
close_sound = 'sound/bloodsucker/coffin_close.ogg'
breakout_time = 600
pryLidTimer = 400
resistance_flags = NONE
integrity_failure = 70
max_integrity = 100
integrity_failure = 0.5
armor = list("melee" = 50, "bullet" = 20, "laser" = 30, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
/obj/structure/closet/crate/coffin/meatcoffin
@@ -68,8 +61,6 @@
desc = "When you're ready to meat your maker, the steaks can never be too high."
icon_state = "meatcoffin"
icon = 'icons/obj/vamp_obj.dmi'
can_weld_shut = FALSE
resistance_flags = 0 // Start off with no bonuses.
open_sound = 'sound/effects/footstep/slime1.ogg'
close_sound = 'sound/effects/footstep/slime1.ogg'
breakout_time = 200
@@ -77,24 +68,23 @@
resistance_flags = NONE
material_drop = /obj/item/reagent_containers/food/snacks/meat/slab
material_drop_amount = 3
integrity_failure = 40
integrity_failure = 0.57
armor = list("melee" = 70, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 100)
/obj/structure/closet/crate/coffin/metalcoffin
name = "metal coffin"
desc = "A big metal sardine can inside of another big metal sardine can, in space."
icon_state = "metalcoffin"
icon = 'icons/obj/vamp_obj.dmi'
can_weld_shut = FALSE
resistance_flags = FIRE_PROOF | LAVA_PROOF
open_sound = 'sound/effects/pressureplate.ogg'
close_sound = 'sound/effects/pressureplate.ogg'
breakout_time = 300
pryLidTimer = 200
resistance_flags = NONE
material_drop = /obj/item/stack/sheet/metal
material_drop_amount = 5
integrity_failure = 60
max_integrity = 200
integrity_failure = 0.25
armor = list("melee" = 40, "bullet" = 15, "laser" = 50, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
//////////////////////////////////////////////
@@ -81,7 +81,7 @@
if(istype(our_target, /datum/cellular_emporium))
cellular_emporium = our_target
else
throw EXCEPTION("cellular_emporium action created with non emporium")
CRASH("cellular_emporium action created with non emporium")
/datum/action/innate/cellular_emporium/Activate()
cellular_emporium.ui_interact(owner)
+1 -1
View File
@@ -477,7 +477,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
A.convert_to_archdevil()
else
throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection")
CRASH("Unable to find a blobstart landmark for hellish resurrection")
/datum/antagonist/devil/proc/update_hud()
+1 -1
View File
@@ -191,7 +191,7 @@
return 0
/obj/item/IntegrateAmount() //returns the amount of resources gained when eating this item
if(custom_materials[getmaterialref(/datum/material/iron)] || custom_materials[getmaterialref(/datum/material/glass)])
if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] || custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)])
return 1
return ..()
@@ -13,6 +13,7 @@
var/should_give_codewords = TRUE
var/should_equip = TRUE
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
var/datum/contractor_hub/contractor_hub
hijack_speed = 0.5 //10 seconds per hijack stage by default
/datum/antagonist/traitor/on_gain()
@@ -413,6 +414,9 @@
var/special_role_text = lowertext(name)
if(contractor_hub)
result += contractor_round_end()
if(traitorwin)
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
else
@@ -421,12 +425,44 @@
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/completed_contracts = 0
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
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.
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 += contractor_item_icons
result += "<br>"
if(completed_contracts > 0)
var/pluralCheck = "contract"
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>"
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>"
<b>The code responses were:</b> <span class='redtext'>[responses]</span><br>"
return message
@@ -0,0 +1,227 @@
// Support unit gets it's own very basic antag datum for admin logging.
/datum/antagonist/traitor/contractor_support
name = "Contractor Support Unit"
antag_moodlet = /datum/mood_event/focused
show_in_roundend = FALSE /// We're already adding them in to the contractor's roundend.
give_objectives = TRUE /// We give them their own custom objective.
show_in_antagpanel = FALSE /// Not a proper/full antag.
should_equip = FALSE /// Don't give them an uplink.
var/datum/team/contractor_team/contractor_team
/datum/team/contractor_team // Team for storing both the contractor and their support unit - only really for the HUD and admin logging.
show_roundend_report = FALSE
/datum/antagonist/traitor/contractor_support/forge_traitor_objectives()
var/datum/objective/generic_objective = new
generic_objective.name = "Follow Contractor's Orders"
generic_objective.explanation_text = "Follow your orders. Assist agents in this mission area."
generic_objective.completed = TRUE
add_objective(generic_objective)
/datum/contractor_hub
var/contract_rep = 0
var/list/hub_items = list()
var/list/purchased_items = list()
var/static/list/contractor_items = typecacheof(/datum/contractor_item/, TRUE)
var/datum/syndicate_contract/current_contract
var/list/datum/syndicate_contract/assigned_contracts = list()
var/list/assigned_targets = list() // used as a blacklist to make sure we're not assigning targets already assigned
var/contract_TC_payed_out = 0 // Keeping track for roundend reporting
var/contract_TC_to_redeem = 0 // Used internally and roundend reporting - what TC we have available to cashout.
/datum/contractor_hub/proc/create_hub_items()
for(var/path in contractor_items)
var/datum/contractor_item/contractor_item = new path
hub_items.Add(contractor_item)
/datum/contractor_hub/proc/create_contracts(datum/mind/owner) // 6 initial contracts
var/list/to_generate = list(
CONTRACT_PAYOUT_LARGE,
CONTRACT_PAYOUT_MEDIUM,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL,
CONTRACT_PAYOUT_SMALL
)
var/lowest_TC_threshold = 30 // We don't want the sum of all the payouts to be under this amount
var/total = 0
var/lowest_paying_sum = 0
var/datum/syndicate_contract/lowest_paying_contract
to_generate = shuffle(to_generate) // Randomise order, so we don't have contracts always in payout order.
var/start_index = 1 // Support contract generation happening multiple times
if(assigned_contracts.len != 0)
start_index = assigned_contracts.len + 1
for(var/i = 1; i <= to_generate.len; i++) // Generate contracts, and find the lowest paying.
var/datum/syndicate_contract/contract_to_add = new(owner, assigned_targets, to_generate[i])
var/contract_payout_total = contract_to_add.contract.payout + contract_to_add.contract.payout_bonus
assigned_targets.Add(contract_to_add.contract.target)
if(!lowest_paying_contract || (contract_payout_total < lowest_paying_sum))
lowest_paying_sum = contract_payout_total
lowest_paying_contract = contract_to_add
total += contract_payout_total
contract_to_add.id = start_index
assigned_contracts.Add(contract_to_add)
start_index++
if(total < lowest_TC_threshold) // If the threshold for TC payouts isn't reached, boost the lowest paying contract
lowest_paying_contract.contract.payout_bonus += (lowest_TC_threshold - total)
/datum/contractor_item
var/name // Name of item
var/desc // description of item
var/item // item path, no item path means the purchase needs it's own handle_purchase()
var/item_icon = "fa-broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/
var/limited = -1 // Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited.
var/cost // Cost of the item in contract rep.
/datum/contractor_item/contract_reroll
name = "Contract Reroll"
desc = "Request a reroll of your current contract list. Will generate a new target, payment, and dropoff for the contracts you currently have available."
item_icon = "fa-dice"
limited = 2
cost = 0
/datum/contractor_item/contract_reroll/handle_purchase(var/datum/contractor_hub/hub)
. = ..()
if (.)
var/list/new_target_list = list() // We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets.
for(var/datum/syndicate_contract/contract_check in hub.assigned_contracts)
if (contract_check.status != CONTRACT_STATUS_ACTIVE && contract_check.status != CONTRACT_STATUS_INACTIVE)
if (contract_check.contract.target)
new_target_list.Add(contract_check.contract.target)
continue
for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts) // Reroll contracts without duplicates
if (rerolling_contract.status != CONTRACT_STATUS_ACTIVE && rerolling_contract.status != CONTRACT_STATUS_INACTIVE)
continue
rerolling_contract.generate(new_target_list)
new_target_list.Add(rerolling_contract.contract.target)
hub.assigned_targets = new_target_list // Set our target list with the new set we've generated.
/datum/contractor_item/contractor_pinpointer
name = "Contractor Pinpointer"
desc = "A pinpointer that finds targets even without active suit sensors. Due to taking advantage of an exploit within the system, it can't pinpoint to the same accuracy as the traditional models. Becomes permanently locked to the user that first activates it."
item = /obj/item/pinpointer/crew/contractor
item_icon = "fa-search-location"
limited = 2
cost = 1
/datum/contractor_item/fulton_extraction_kit
name = "Fulton Extraction Kit"
desc = "For getting your target across the station to those difficult dropoffs. Place the beacon somewhere secure, and link the pack. Activating the pack on your target in space will send them over to the beacon - make sure they're not just going to run away though!"
item = /obj/item/storage/box/contractor/fulton_extraction
item_icon = "fa-parachute-box"
limited = 1
cost = 1
/datum/contractor_item/contractor_partner
name = "Reinforcements"
desc = "Upon purchase we'll contact available units in the area. Should there be an agent free, we'll send them down to assist you immediately. If no units are free, we give a full refund."
item_icon = "fa-user-friends"
limited = 1
cost = 2
var/datum/mind/partner_mind = null
/datum/contractor_item/contractor_partner/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
. = ..()
if (.)
to_chat(user, "<span class='notice'>The uplink vibrates quietly, connecting to nearby agents...</span>")
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
spawn_contractor_partner(user, C.key)
else
to_chat(user, "<span class='notice'>No available agents at this time, please try again later.</span>")
limited += 1 // refund and add the limit back.
hub.contract_rep += cost
hub.purchased_items -= src
/datum/outfit/contractor_partner
name = "Contractor Support Unit"
uniform = /obj/item/clothing/under/chameleon
suit = /obj/item/clothing/suit/chameleon
back = /obj/item/storage/backpack
belt = /obj/item/pda/chameleon
mask = /obj/item/clothing/mask/cigarette/syndicate
shoes = /obj/item/clothing/shoes/chameleon/noslip
ears = /obj/item/radio/headset/chameleon
id = /obj/item/card/id/syndicate
r_hand = /obj/item/storage/toolbox/syndicate
backpack_contents = list(/obj/item/storage/box/survival, /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter)
/datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(SLOT_WEAR_MASK)
cig.light() // pre-light their cig for extra badass
/datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key)
var/mob/living/carbon/human/partner = new()
var/datum/outfit/contractor_partner/partner_outfit = new()
partner_outfit.equip(partner)
var/obj/structure/closet/supplypod/arrival_pod = new()
arrival_pod.style = STYLE_SYNDICATE
arrival_pod.explosionSize = list(0,0,0,1)
arrival_pod.bluespace = TRUE
var/turf/free_location = find_obstruction_free_location(2, user)
if (!free_location) // We really want to send them - if we can't find a nice location just land it on top of them.
free_location = get_turf(user)
partner.forceMove(arrival_pod)
partner.ckey = key
partner_mind = partner.mind // We give a reference to the mind that'll be the support unit
partner_mind.make_Contractor_Support()
to_chat(partner_mind.current, "\n<span class='alertwarning'>[user.real_name] is your superior. Follow any, and all orders given by them. You're here to support their mission only.</span>")
to_chat(partner_mind.current, "<span class='alertwarning'>Should they perish, or be otherwise unavailable, you're to assist other active agents in this mission area to the best of your ability.</span>\n\n")
new /obj/effect/abstract/DPtarget(free_location, arrival_pod)
/datum/contractor_item/blackout
name = "Blackout"
desc = "Request Syndicate Command to distrupt the station's powernet. Disables power across the station for a short duration."
item_icon = "fa-bolt"
limited = 2
cost = 3
/datum/contractor_item/blackout/handle_purchase(var/datum/contractor_hub/hub)
. = ..()
if (.)
power_fail(35, 50)
priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff")
// Subtract cost, and spawn if it's an item.
/datum/contractor_item/proc/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
if (hub.contract_rep >= cost)
hub.contract_rep -= cost
else
return FALSE
if (limited >= 1)
limited -= 1
else if (limited == 0)
return FALSE
hub.purchased_items.Add(src)
if (item && ispath(item))
var/atom/item_to_create = new item(get_turf(user))
if(user.put_in_hands(item_to_create))
to_chat(user, "<span class='notice'>Your purchase materializes into your hands!</span>")
else
to_chat(user, "<span class='notice'>Your purchase materializes onto the floor.</span>")
return item_to_create
return TRUE
/obj/item/pinpointer/crew/contractor
name = "contractor pinpointer"
desc = "A handheld tracking device that locks onto certain signals. Ignores suit sensors, but is much less accurate."
icon_state = "pinpointer_syndicate"
minimum_range = 25
has_owner = TRUE
ignore_suit_sensor_level = TRUE
/obj/item/storage/box/contractor/fulton_extraction
name = "Fulton Extraction Kit"
icon_state = "syndiebox"
illustration = "writing_syndie"
/obj/item/storage/box/contractor/fulton_extraction/PopulateContents()
new /obj/item/extraction_pack(src)
new /obj/item/fulton_core(src)
@@ -0,0 +1,144 @@
/datum/syndicate_contract
var/id = 0
var/status = CONTRACT_STATUS_INACTIVE
var/datum/objective/contract/contract = new()
var/ransom = 0
var/payout_type = null
var/list/victim_belongings = list()
/datum/syndicate_contract/New(contract_owner, blacklist, type=CONTRACT_PAYOUT_SMALL)
contract.owner = contract_owner
payout_type = type
generate(blacklist)
/datum/syndicate_contract/proc/generate(blacklist)
contract.find_target(null, blacklist)
if (payout_type == CONTRACT_PAYOUT_LARGE)
contract.payout_bonus = rand(9,13)
else if(payout_type == CONTRACT_PAYOUT_MEDIUM)
contract.payout_bonus = rand(6,8)
else
contract.payout_bonus = rand(2,4)
contract.payout = rand(0, 2)
contract.generate_dropoff()
ransom = 100 * rand(18, 45)
/datum/syndicate_contract/proc/handle_extraction(var/mob/living/user)
if (contract.target && contract.dropoff_check(user, contract.target.current))
var/turf/free_location = find_obstruction_free_location(3, user, contract.dropoff)
if(free_location) // We've got a valid location, launch.
launch_extraction_pod(free_location)
return TRUE
return FALSE
// Launch the pod to collect our victim.
/datum/syndicate_contract/proc/launch_extraction_pod(turf/empty_pod_turf)
var/obj/structure/closet/supplypod/extractionpod/empty_pod = new()
RegisterSignal(empty_pod, COMSIG_ATOM_ENTERED, .proc/enter_check)
empty_pod.stay_after_drop = TRUE
empty_pod.reversing = TRUE
empty_pod.explosionSize = list(0,0,0,1)
empty_pod.leavingSound = 'sound/effects/podwoosh.ogg'
new /obj/effect/abstract/DPtarget(empty_pod_turf, empty_pod)
/datum/syndicate_contract/proc/enter_check(datum/source, sent_mob)
if(istype(source, /obj/structure/closet/supplypod/extractionpod))
if(isliving(sent_mob))
var/mob/living/M = sent_mob
var/datum/antagonist/traitor/traitor_data = contract.owner.has_antag_datum(/datum/antagonist/traitor)
if(M == contract.target.current)
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout
if(M.stat != DEAD)
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout_bonus
status = CONTRACT_STATUS_COMPLETE
if(traitor_data.contractor_hub.current_contract == src)
traitor_data.contractor_hub.current_contract = null
traitor_data.contractor_hub.contract_rep += 2
else
status = CONTRACT_STATUS_ABORTED // Sending a target that wasn't even yours is as good as just aborting it
if(traitor_data.contractor_hub.current_contract == src)
traitor_data.contractor_hub.current_contract = null
if(iscarbon(M))
for(var/obj/item/W in M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(W == H.w_uniform || W == H.shoes)
continue //So all they're left with are shoes and uniform.
M.transferItemToLoc(W)
victim_belongings.Add(W)
var/obj/structure/closet/supplypod/extractionpod/pod = source
pod.send_up(pod) // Handle the pod returning
if(ishuman(M))
var/mob/living/carbon/human/target = M // After we remove items, at least give them what they need to live.
target.dna.species.give_important_for_life(target)
handleVictimExperience(M) // After pod is sent we start the victim narrative/heal.
var/points_to_check = SSshuttle.points // This is slightly delayed because of the sleep calls above to handle the narrative. We don't want to tell the station instantly.
if(points_to_check >= ransom)
SSshuttle.points -= ransom
else
SSshuttle.points -= points_to_check
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \
As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection")
/datum/syndicate_contract/proc/handleVictimExperience(var/mob/living/M) // They're off to holding - handle the return timer and give some text about what's going on.
addtimer(CALLBACK(src, .proc/returnVictim, M), (60 * 10) * 4) // Ship 'em back - dead or alive... 4 minutes wait.
if(M.stat != DEAD) //Even if they weren't the target, we're still treating them the same.
M.reagents.add_reagent(/datum/reagent/medicine/omnizine, 20) // Heal them up - gets them out of crit/soft crit.
M.flash_act()
M.confused += 10
M.blur_eyes(5)
to_chat(M, "<span class='warning'>You feel strange...</span>")
sleep(60)
to_chat(M, "<span class='warning'>That pod did something to you...</span>")
M.Dizzy(35)
sleep(65)
to_chat(M, "<span class='warning'>Your head pounds... It feels like it's going to burst out your skull!</span>")
M.flash_act()
M.confused += 20
M.blur_eyes(3)
sleep(30)
to_chat(M, "<span class='warning'>Your head pounds...</span>")
sleep(100)
M.flash_act()
M.Unconscious(200)
to_chat(M, "<span class='reallybig hypnophrase'>A million voices echo in your head... <i>\"Your mind held many valuable secrets - \
we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
so it's only a matter of time before we ship you back...\"</i></span>")
M.blur_eyes(10)
M.Dizzy(15)
M.confused += 20
/datum/syndicate_contract/proc/returnVictim(var/mob/living/M) // We're returning the victim
var/list/possible_drop_loc = list()
for(var/turf/possible_drop in contract.dropoff.contents)
if(!is_blocked_turf(possible_drop))
possible_drop_loc.Add(possible_drop)
if(possible_drop_loc.len > 0)
var/pod_rand_loc = rand(1, possible_drop_loc.len)
var/obj/structure/closet/supplypod/return_pod = new()
return_pod.bluespace = TRUE
return_pod.explosionSize = list(0,0,0,0)
return_pod.style = STYLE_SYNDICATE
do_sparks(8, FALSE, M)
M.visible_message("<span class='notice'>[M] vanishes...</span>")
for(var/obj/item/W in M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(W == H.w_uniform || W == H.shoes)
continue //So all they're left with are shoes and uniform.
M.dropItemToGround(W)
for(var/obj/item/W in victim_belongings)
W.forceMove(return_pod)
M.forceMove(return_pod)
M.flash_act()
M.blur_eyes(30)
M.Dizzy(35)
M.confused += 20
new /obj/effect/abstract/DPtarget(possible_drop_loc[pod_rand_loc], return_pod)
else
to_chat(M, "<span class='reallybig hypnophrase'>A million voices echo in your head... <i>\"Seems where you got sent here from won't \
be able to handle our pod... You will die here instead.\"</i></span>")
if(iscarbon(M))
var/mob/living/carbon/C = M
if(C.can_heartattack())
C.set_heartattack(TRUE)
@@ -144,7 +144,7 @@
for(var/i in 1 to device_type)
var/datum/pipeline/parent = parents[i]
if(!parent)
throw EXCEPTION("Component is missing a pipenet! Rebuilding...")
stack_trace("Component is missing a pipenet! Rebuilding...")
build_network()
parent.update = 1
+2 -2
View File
@@ -15,10 +15,10 @@
if(!isitem(O))
return 0
var/obj/item/I = O
if(!(getmaterialref(material_id) in I.custom_materials))
if(!(SSmaterials.GetMaterialRef(material_id) in I.custom_materials))
return 0
var/amount = I.custom_materials[getmaterialref(material_id)]
var/amount = I.custom_materials[SSmaterials.GetMaterialRef(material_id)]
if(istype(I, /obj/item/stack/ore))
amount *= 0.8 // Station's ore redemption equipment is really goddamn good.
+57 -16
View File
@@ -42,6 +42,8 @@
var/soundVolume = 80 //Volume to play sounds at. Ignores the cap
var/bay //Used specifically for the centcom_podlauncher datum. Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
var/list/explosionSize = list(0,0,2,3)
var/stay_after_drop = FALSE
var/specialised = TRUE // It's not a general use pod for cargo/admin use
/obj/structure/closet/supplypod/bluespacepod
style = STYLE_BLUESPACE
@@ -49,6 +51,15 @@
explosionSize = list(0,0,1,2)
landingDelay = 15 //Slightly quicker than the supplypod
/obj/structure/closet/supplypod/extractionpod
name = "Syndicate Extraction Pod"
desc = "A specalised, blood-red styled pod for extracting high-value targets out of active mission areas."
specialised = TRUE
style = STYLE_SYNDICATE
bluespace = TRUE
explosionSize = list(0,0,1,2)
landingDelay = 25 //Slightly longer than others
/obj/structure/closet/supplypod/centcompod
style = STYLE_CENTCOM
bluespace = TRUE
@@ -56,6 +67,13 @@
landingDelay = 20 //Very speedy!
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/structure/closet/supplypod/proc/specialisedPod()
return 1
/obj/structure/closet/supplypod/extractionpod/specialisedPod(atom/movable/holder)
holder.forceMove(pick(GLOB.holdingfacility)) // land in ninja jail
open(holder, forced = TRUE)
/obj/structure/closet/supplypod/Initialize()
. = ..()
setStyle(style, TRUE) //Upon initialization, give the supplypod an iconstate, name, and description based on the "style" variable. This system is important for the centcom_podlauncher to function correctly
@@ -76,7 +94,7 @@
return
style = chosenStyle
icon_state = POD_STYLES[chosenStyle][POD_ICON_STATE] //POD_STYLES is a 2D array we treat as a dictionary. The style represents the verticle index, with the icon state, name, and desc being stored in the horizontal indexes of the 2D array.
if (!adminNamed) //We dont want to name it ourselves if it has been specifically named by an admin using the centcom_podlauncher datum
if (!adminNamed && !specialised) //We dont want to name it ourselves if it has been specifically named by an admin using the centcom_podlauncher datum
name = POD_STYLES[chosenStyle][POD_NAME]
desc = POD_STYLES[chosenStyle][POD_DESC]
update_icon()
@@ -96,6 +114,30 @@
/obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums
return
/obj/structure/closet/supplypod/proc/handleReturningClose(atom/movable/holder, returntobay)
opened = FALSE
INVOKE_ASYNC(holder, .proc/setClosed) //Use the INVOKE_ASYNC proc to call setClosed() on whatever the holder may be, without giving the atom/movable base class a setClosed() proc definition
for(var/atom/movable/O in get_turf(holder))
if ((ismob(O) && !isliving(O)) || (is_type_in_typecache(O, GLOB.blacklisted_cargo_types) && !isliving(O))) //We dont want to take ghosts with us, and we don't want blacklisted items going, but we allow mobs.
continue
O.forceMove(holder) //Put objects inside before we close
var/obj/effect/temp_visual/risingPod = new /obj/effect/abstract/DPfall(get_turf(holder), src) //Make a nice animation of flying back up
risingPod.pixel_z = 0 //The initial value of risingPod's pixel_z is 200 because it normally comes down from a high spot
animate(risingPod, pixel_z = 200, time = 10, easing = LINEAR_EASING) //Animate our rising pod
if(returntobay)
holder.forceMove(bay) //Move the pod back to centcom, where it belongs
QDEL_IN(risingPod, 10)
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
open(holder, forced = TRUE)
else
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
QDEL_IN(risingPod, 10)
audible_message("<span class='notice'>The pod hisses, closing quickly and launching itself away from the station.</span>", "<span class='notice'>The ground vibrates, the nearby pod launching away from the station.</span>")
stay_after_drop = FALSE
specialisedPod(holder) // Do special actions for specialised pods - this is likely if we were already doing manual launches
/obj/structure/closet/supplypod/proc/preOpen() //Called before the open() proc. Handles anything that occurs right as the pod lands.
var/turf/T = get_turf(src)
var/list/B = explosionSize //Mostly because B is more readable than explosionSize :p
@@ -172,7 +214,8 @@
if (style == STYLE_SEETHROUGH)
depart(src)
else
addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time
if(!stay_after_drop) // Departing should be handled manually
addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time
/obj/structure/closet/supplypod/proc/depart(atom/movable/holder)
if (leavingSound)
@@ -187,20 +230,18 @@
qdel(holder)
/obj/structure/closet/supplypod/centcompod/close(atom/movable/holder) //Closes the supplypod and sends it back to centcom. Should only ever be called if the "reversing" variable is true
opened = FALSE
INVOKE_ASYNC(holder, .proc/setClosed) //Use the INVOKE_ASYNC proc to call setClosed() on whatever the holder may be, without giving the atom/movable base class a setClosed() proc definition
for (var/atom/movable/O in get_turf(holder))
if (ismob(O) && !isliving(O)) //We dont want to take ghosts with us
continue
O.forceMove(holder) //Put objects inside before we close
var/obj/effect/temp_visual/risingPod = new /obj/effect/abstract/DPfall(get_turf(holder), src) //Make a nice animation of flying back up
risingPod.pixel_z = 0 //The initial value of risingPod's pixel_z is 200 because it normally comes down from a high spot
holder.forceMove(bay) //Move the pod back to centcom, where it belongs
animate(risingPod, pixel_z = 200, time = 10, easing = LINEAR_EASING) //Animate our rising pod
QDEL_IN(risingPod, 10)
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
open(holder, forced = TRUE)
handleReturningClose(holder, TRUE)
/obj/structure/closet/supplypod/extractionpod/close(atom/movable/holder) //handles closing, and returns pod - deletes itself when returned
. = ..()
return
/obj/structure/closet/supplypod/extractionpod/proc/send_up(atom/movable/holder)
if(!holder)
holder = src
if(leavingSound)
playsound(get_turf(holder), leavingSound, soundVolume, 0, 0)
handleReturningClose(holder, FALSE)
/obj/structure/closet/supplypod/proc/setOpened() //Proc exists here, as well as in any atom that can assume the role of a "holder" of a supplypod. Check the open() proc for more details
update_icon()
+1 -1
View File
@@ -243,7 +243,7 @@
icon_state = "knight_greyscale"
item_state = "knight_greyscale"
armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40)
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR //Can change color and add prefix
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix
/obj/item/clothing/head/helmet/skull
name = "skull helmet"
@@ -455,6 +455,18 @@
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS
/obj/item/clothing/head/helmet/space/hardsuit/medical/equipped(mob/living/carbon/human/user, slot)
..()
if (slot == SLOT_HEAD)
var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
DHUD.add_hud_to(user)
/obj/item/clothing/head/helmet/space/hardsuit/medical/dropped(mob/living/carbon/human/user)
..()
if (user.head == src)
var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
DHUD.remove_hud_from(user)
/obj/item/clothing/suit/space/hardsuit/medical
icon_state = "hardsuit-medical"
name = "medical hardsuit"
+16
View File
@@ -75,6 +75,22 @@
icon_state = "syndicate-black"
item_state = "syndicate-black"
//Black-red syndicate contract varient
/obj/item/clothing/head/helmet/space/syndicate/contract
name = "contractor helmet"
desc = "A specialised black and gold helmet that's more compact than its standard Syndicate counterpart. Can be ultra-compressed into even the tightest of spaces."
slowdown = 0.55
w_class = WEIGHT_CLASS_SMALL
icon_state = "syndicate-contract-helm"
item_state = "syndicate-contract-helm"
/obj/item/clothing/suit/space/syndicate/contract
name = "contractor space suit"
desc = "A specialised black and gold space suit that's quicker, and more compact than its standard Syndicate counterpart. Can be ultra-compressed into even the tightest of spaces."
slowdown = 0.55
w_class = WEIGHT_CLASS_SMALL
icon_state = "syndicate-contract"
item_state = "syndicate-contract"
//Black-green syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/black/green
+1 -1
View File
@@ -267,7 +267,7 @@
icon_state = "knight_greyscale"
item_state = "knight_greyscale"
armor = list("melee" = 35, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 10, "bio" = 10, "rad" = 10, "fire" = 40, "acid" = 40)
material_flags = MATERIAL_ADD_PREFIX //Can change color and add prefix
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix
/obj/item/clothing/suit/armor/vest/durathread
name = "makeshift vest"
+1 -4
View File
@@ -13,7 +13,4 @@
/datum/round_event/grid_check/start()
for(var/P in GLOB.apcs_list)
var/obj/machinery/power/apc/C = P
if(C.cell && is_station_level(C.z))
C.energy_fail(rand(30,120))
power_fail(30, 120)
@@ -140,7 +140,7 @@
/obj/item/reagent_containers/food/snacks/snowcones/blue
name = "bluecherry snowcone"
desc = "Bluecherry syrup drizzled over a snowball in a paper cup, how rare!"
icon_state = "blue_sc"
icon_state = "red_sc"
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/bluecherryjelly = 5)
tastes = list("ice" = 1, "water" = 1, "blue" = 5, "cherries" = 5)
foodtype = FRUIT
@@ -148,7 +148,7 @@
/obj/item/reagent_containers/food/snacks/snowcones/red
name = "cherry snowcone"
desc = "Cherry syrup drizzled over a snowball in a paper cup."
icon_state = "red_sc"
icon_state = "blue_sc"
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cherryjelly = 5)
tastes = list("ice" = 1, "water" = 1, "red" = 5, "cherries" = 5)
foodtype = FRUIT
@@ -223,7 +223,7 @@
tastes = list("ice" = 1, "water" = 1, "cola" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/spacemountainwind
name = "Space Mountain Wind snowcone"
name = "\improper Space Mountain Wind snowcone"
desc = "Space Mountain Wind drizzled over a snowball in a paper cup."
icon_state = "kiwi_sc"
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/spacemountainwind = 5)
@@ -201,10 +201,10 @@
/obj/item/reagent_containers/food/snacks/donut/jelly/choco
name = "chocolate jelly donut"
desc = "Goes great with a glass of warm milk."
icon_state = "jelly_choc"
icon_state = "jelly_choco"
bonus_reagents = list(/datum/reagent/consumable/hot_coco = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1) //the coco reagent is just bitter.
tastes = list("jelly" = 1, "donut" = 4, "bitterness" = 1)
decorated_icon = "jelly_choc_sprinkles"
decorated_icon = "jelly_choco_sprinkles"
filling_color = "#4F230D"
/obj/item/reagent_containers/food/snacks/donut/jelly/blumpkin
@@ -310,7 +310,7 @@
for(var/obj/item/O in ingredients)
O.microwave_act(src)
if(O.custom_materials?.len)
metal += O.custom_materials[getmaterialref(/datum/material/iron)]
metal += O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
if(metal)
spark()
@@ -620,7 +620,7 @@
results = list(/datum/reagent/consumable/ethanol/quintuple_sec = 15)
required_reagents = list(/datum/reagent/consumable/ethanol/quadruple_sec = 5, /datum/reagent/consumable/clownstears = 5, /datum/reagent/consumable/ethanol/syndicatebomb = 5)
mix_message = "Judgement is upon you."
mix_message = 'sound/items/airhorn2.ogg'
mix_sound = 'sound/items/airhorn2.ogg'
/datum/chemical_reaction/bastion_bourbon
name = "Bastion Bourbon"
+5 -1
View File
@@ -4,6 +4,10 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
"power_supply", "contents", "reagents", "stat", "x", "y", "z", "group", "atmos_adjacent_turfs", "comp_lookup"
))
GLOBAL_LIST_INIT(duplicate_forbidden_vars_by_type, typecacheof_assoc_list(list(
/obj/item/gun/energy = "ammo_type"
)))
/proc/DuplicateObject(atom/original, perfectcopy = TRUE, sameloc = FALSE, atom/newloc = null, nerf = FALSE, holoitem=FALSE)
RETURN_TYPE(original.type)
if(!original)
@@ -16,7 +20,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
O = new original.type(newloc)
if(perfectcopy && O && original)
for(var/V in original.vars - GLOB.duplicate_forbidden_vars)
for(var/V in original.vars - GLOB.duplicate_forbidden_vars - GLOB.duplicate_forbidden_vars_by_type[O.type])
if(islist(original.vars[V]))
var/list/L = original.vars[V]
O.vars[V] = L.Copy()
+4 -4
View File
@@ -196,7 +196,7 @@
dat += "<A href='?src=[REF(src)];create=[D.id];amount=5'>x5</A>"
if(ispath(D.build_path, /obj/item/stack))
dat += "<A href='?src=[REF(src)];create=[D.id];amount=10'>x10</A>"
dat += "([D.materials[getmaterialref(/datum/material/biomass)]/efficiency])<br>"
dat += "([D.materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]/efficiency])<br>"
dat += "</div>"
else
dat += "<div class='statusDisplay'>No container inside, please insert container.</div>"
@@ -233,14 +233,14 @@
menustat = "void"
/obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = TRUE)
if(materials.len != 1 || materials[1] != getmaterialref(/datum/material/biomass))
if(materials.len != 1 || materials[1] != SSmaterials.GetMaterialRef(/datum/material/biomass))
return FALSE
if (materials[getmaterialref(/datum/material/biomass)]*multiplier/efficiency > points)
if (materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency > points)
menustat = "nopoints"
return FALSE
else
if(remove_points)
points -= materials[getmaterialref(/datum/material/biomass)]*multiplier/efficiency
points -= materials[SSmaterials.GetMaterialRef(/datum/material/biomass)]*multiplier/efficiency
update_icon()
updateUsrDialog()
return TRUE
+3 -3
View File
@@ -27,9 +27,6 @@
mutatelist = list()
rarity = 20
/obj/item/grown/log
seed = /obj/item/seeds/tower
name = "tower-cap log"
@@ -275,6 +272,9 @@
else if(istype(A, /obj/item) && prob(20))
var/obj/item/O = A
O.microwave_act()
else if(istype(A, /obj/item/grown/log))
qdel(A)
new /obj/item/stack/sheet/mineral/coal(loc, 1)
/obj/structure/bonfire/process()
if(!CheckOxygen())
@@ -190,10 +190,10 @@
var/cost = 400
if(ispath(build_type, /obj/item/electronic_assembly))
var/obj/item/electronic_assembly/E = SScircuit.cached_assemblies[build_type]
cost = E.custom_materials[getmaterialref(/datum/material/iron)]
cost = E.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
else if(ispath(build_type, /obj/item/integrated_circuit))
var/obj/item/integrated_circuit/IC = SScircuit.cached_components[build_type]
cost = IC.custom_materials[getmaterialref(/datum/material/iron)]
cost = IC.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
else if(!(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"]))
return
@@ -260,7 +260,7 @@
blocks["max_space"] = assembly.max_components
// Start keeping track of total metal cost
blocks["metal_cost"] = assembly.custom_materials[getmaterialref(/datum/material/iron)]
blocks["metal_cost"] = assembly.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
// Block 2. Components.
@@ -291,7 +291,7 @@
// Update estimated assembly complexity, taken space and material cost
blocks["complexity"] += component.complexity
blocks["used_space"] += component.size
blocks["metal_cost"] += component.custom_materials[getmaterialref(/datum/material/iron)]
blocks["metal_cost"] += component.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
// Check if the assembly requires printer upgrades
if(!(component.spawn_flags & IC_SPAWN_DEFAULT))
@@ -414,7 +414,7 @@
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
set_pin_data(IC_OUTPUT, 2, materials.total_amount)
for(var/I in 1 to mtypes.len)
var/datum/material/M = materials.materials[getmaterialref(I)]
var/datum/material/M = materials.materials[SSmaterials.GetMaterialRef(I)]
var/amount = materials[M]
if(M)
set_pin_data(IC_OUTPUT, I+2, amount)
@@ -452,7 +452,7 @@
continue
if(!mt) //Invalid input
if(U>0)
if(materials.retrieve_sheets(U, getmaterialref(mtypes[I]), T))
if(materials.retrieve_sheets(U, SSmaterials.GetMaterialRef(mtypes[I]), T))
suc = TRUE
else
if(mt.transer_amt_to(materials, U, mtypes[I]))
@@ -23,7 +23,7 @@
return
template = SSmapping.shelter_templates[template_id]
if(!template)
throw EXCEPTION("Shelter template ([template_id]) not found!")
stack_trace("Shelter template ([template_id]) not found!")
qdel(src)
/obj/item/survivalcapsule/Destroy()
+1 -1
View File
@@ -86,7 +86,7 @@
proximity_monitor = new(src, 1)
AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace), INFINITY, TRUE, /obj/item/stack)
stored_research = new /datum/techweb/specialized/autounlocking/smelter
selected_material = getmaterialref(/datum/material/iron)
selected_material = SSmaterials.GetMaterialRef(/datum/material/iron)
/obj/machinery/mineral/processing_unit/Destroy()
CONSOLE = null
+1 -1
View File
@@ -29,7 +29,7 @@
/datum/material/plastic,
/datum/material/runite
), MINERAL_MATERIAL_AMOUNT * 50, FALSE, /obj/item/stack)
chosen = getmaterialref(chosen)
chosen = SSmaterials.GetMaterialRef(chosen)
/obj/machinery/mineral/mint/process()
var/turf/T = get_step(src, input_dir)
+1 -1
View File
@@ -320,7 +320,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
throwforce = 2
w_class = WEIGHT_CLASS_TINY
custom_materials = list(/datum/material/iron = 400)
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR
material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
var/string_attached
var/list/sideslist = list("heads","tails")
var/cooldown = 0
+1
View File
@@ -16,6 +16,7 @@
QDEL_LIST(stomach_contents)
QDEL_LIST(bodyparts)
QDEL_LIST(implants)
hand_bodyparts = null //Just references out bodyparts, don't need to delete twice.
remove_from_all_data_huds()
QDEL_NULL(dna)
GLOB.carbon_list -= src
@@ -1,15 +1,3 @@
/mob/living/carbon/movement_delay()
. = ..()
. += grab_state * 3 //can't go fast while grabbing something.
if(!get_leg_ignore()) //ignore the fact we lack legs
var/leg_amount = get_num_legs()
. += 6 - 3*leg_amount //the fewer the legs, the slower the mob
if(!leg_amount)
. += 6 - 3*get_num_arms() //crawling is harder with fewer arms
if(legcuffed)
. += legcuffed.slowdown
/mob/living/carbon/slip(knockdown_amount, obj/O, lube)
if(movement_type & FLYING && !(lube & FLYING_DOESNT_HELP))
return FALSE
@@ -948,6 +948,22 @@
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
visible_message("<span class='warning'>[src.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/human/updatehealth()
. = ..()
if(HAS_TRAIT(src, TRAIT_IGNORESLOWDOWN))
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
return
var/stambufferinfluence = (bufferedstam*(100/stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay
var/health_deficiency = ((100 + stambufferinfluence) - health + (getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss and makes stamina buffer influence it
if(health_deficiency >= 40)
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 75), blacklisted_movetypes = FLOATING|FLYING)
add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING, override = TRUE, multiplicative_slowdown = ((health_deficiency-39) / 25), movetypes = FLOATING)
else
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN)
remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING)
/mob/living/carbon/human/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
@@ -9,8 +9,8 @@
/mob/living/carbon/human/movement_delay()
. = ..()
if(dna && dna.species)
. += dna.species.movement_delay(src)
if (m_intent == MOVE_INTENT_WALK && HAS_TRAIT(src, TRAIT_SPEEDY_STEP))
. -= 1.5
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
if(HAS_TRAIT(src, TRAIT_NOSLIPALL))
@@ -145,6 +145,12 @@
return not_handled //For future deeper overrides
/mob/living/carbon/human/equipped_speed_mods()
. = ..()
for(var/sloties in get_all_slots())
var/obj/item/thing = sloties
. += thing?.slowdown
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
var/index = get_held_index_of_item(I)
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
+26 -53
View File
@@ -71,6 +71,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
var/list/special_step_sounds //Sounds to override barefeet walkng
var/grab_sound //Special sound for grabbing
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
// species-only traits. Can be found in DNA.dm
var/list/species_traits = list()
@@ -1019,6 +1020,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_overlay(BODY_TAUR_LAYER) // CITADEL EDIT
/*
* Equip the outfit required for life. Replaces items currently worn.
*/
/datum/species/proc/give_important_for_life(mob/living/carbon/human/human_to_equip)
if(!outfit_important_for_life)
return
outfit_important_for_life= new()
outfit_important_for_life.equip(human_to_equip)
//This exists so sprite accessories can still be per-layer without having to include that layer's
//number in their sprite name, which causes issues when those numbers change.
/datum/species/proc/mutant_bodyparts_layertext(layer)
@@ -1286,12 +1296,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(H.overeatduration < 100)
to_chat(H, "<span class='notice'>You feel fit again!</span>")
REMOVE_TRAIT(H, TRAIT_FAT, OBESITY)
H.remove_movespeed_modifier(MOVESPEED_ID_FAT)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
else
if(H.overeatduration >= 100)
to_chat(H, "<span class='danger'>You suddenly feel blubbery!</span>")
ADD_TRAIT(H, TRAIT_FAT, OBESITY)
H.add_movespeed_modifier(MOVESPEED_ID_FAT, multiplicative_slowdown = 1.5)
H.update_inv_w_uniform()
H.update_inv_wear_suit()
@@ -1342,6 +1354,15 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
to_chat(H, "<span class='notice'>You no longer feel vigorous.</span>")
H.metabolism_efficiency = 1
//Hunger slowdown for if mood isn't enabled
if(CONFIG_GET(flag/disable_human_mood))
if(!HAS_TRAIT(H, TRAIT_NOHUNGER))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if(hungry >= 70)
H.add_movespeed_modifier(MOVESPEED_ID_HUNGRY, override = TRUE, multiplicative_slowdown = (hungry / 50))
else
H.remove_movespeed_modifier(MOVESPEED_ID_HUNGRY)
switch(H.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
H.throw_alert("nutrition", /obj/screen/alert/fat)
@@ -1391,59 +1412,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.hair_style = "Bald"
H.update_hair()
////////////////
// MOVE SPEED //
////////////////
/datum/species/proc/movement_delay(mob/living/carbon/human/H)
. = 0 //We start at 0.
var/flight = 0 //Check for flight and flying items
var/gravity = 0
if(H.movement_type & FLYING)
flight = 1
gravity = H.has_gravity()
if (H.m_intent == MOVE_INTENT_WALK && HAS_TRAIT(H, TRAIT_SPEEDY_STEP))
. -= 1.5
if(!HAS_TRAIT(H, TRAIT_IGNORESLOWDOWN) && gravity)
if(H.wear_suit)
. += H.wear_suit.slowdown
if(H.shoes)
. += H.shoes.slowdown
if(H.back)
. += H.back.slowdown
for(var/obj/item/I in H.held_items)
if(I.item_flags & SLOWS_WHILE_IN_HAND)
. += I.slowdown
var/stambufferinfluence = (H.bufferedstam*(100/H.stambuffer))*0.2 //CIT CHANGE - makes stamina buffer influence movedelay
var/health_deficiency = ((100 + stambufferinfluence) - H.health + (H.getStaminaLoss()*0.75))//CIT CHANGE - reduces the impact of staminaloss on movement speed and makes stamina buffer influence movedelay
if(health_deficiency >= 40)
if(flight)
. += ((health_deficiency-39) / 75) // CIT CHANGE - adds -39 to health deficiency penalty to make the transition to low health movement a little less jarring
else
. += ((health_deficiency-39) / 25) // CIT CHANGE - ditto
if(CONFIG_GET(flag/disable_human_mood))
var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80
if((hungry >= 70) && !flight) //Being hungry will still allow you to use a flightsuit/wings.
. += hungry / 50
//Moving in high gravity is very slow (Flying too)
if(gravity > STANDARD_GRAVITY)
var/grav_force = min(gravity - STANDARD_GRAVITY,3)
. += 1 + grav_force
if(HAS_TRAIT(H, TRAIT_FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
return .
//////////////////
// ATTACK PROCS //
//////////////////
//////////////////
// ATTACK PROCS //
//////////////////
@@ -2060,6 +2028,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "hot", /datum/mood_event/hot)
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
var/burn_damage
var/firemodifier = H.fire_stacks / 50
if (H.on_fire)
@@ -2075,6 +2045,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(H, TRAIT_RESISTCOLD))
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "cold", /datum/mood_event/cold)
//Sorry for the nasty oneline but I don't want to assign a variable on something run pretty frequently
H.add_movespeed_modifier(MOVESPEED_ID_COLD, override = TRUE, multiplicative_slowdown = ((BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR))
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod*H.physiology.cold_mod, BURN)
@@ -2084,6 +2056,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod*H.physiology.cold_mod, BURN)
else
H.remove_movespeed_modifier(MOVESPEED_ID_COLD)
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "cold")
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "hot")
@@ -20,6 +20,7 @@
var/internal_fire = FALSE //If the bones themselves are burning clothes won't help you much
disliked_food = FRUIT
liked_food = VEGETABLES
outfit_important_for_life = /datum/outfit/plasmaman
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
+2 -1
View File
@@ -295,7 +295,7 @@
if(!iscarbon(src))
M.LAssailant = null
else
M.LAssailant = usr
M.LAssailant = WEAKREF(usr)
if(isliving(M))
var/mob/living/L = M
//Share diseases that are spread by touch
@@ -727,6 +727,7 @@
return name
/mob/living/update_gravity(has_gravity,override = 0)
. = ..()
if(!SSticker.HasRoundStarted())
return
if(has_gravity)
+1 -1
View File
@@ -250,7 +250,7 @@
return 0
if(user.voremode && user.grab_state == GRAB_AGGRESSIVE)
return 0
user.grab_state++
user.setGrabState(user.grab_state + 1)
switch(user.grab_state)
if(GRAB_AGGRESSIVE)
var/add_log = ""
@@ -152,4 +152,17 @@
if(CHECK_MOBILITY(src, MOBILITY_MOVE) && !intentionalresting && canstand_involuntary && iscarbon(src) && client?.prefs?.autostand)//CIT CHANGE - adds autostanding as a preference
addtimer(CALLBACK(src, .proc/resist_a_rest, TRUE), 0) //CIT CHANGE - ditto
// Movespeed mods based on arms/legs quantity
if(!get_leg_ignore())
var/limbless_slowdown = 0
// These checks for <2 should be swapped out for something else if we ever end up with a species with more than 2
if(has_legs < 2)
limbless_slowdown += 6 - (has_legs * 3)
if(!has_legs && has_arms < 2)
limbless_slowdown += 6 - (has_arms * 3)
if(limbless_slowdown)
add_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=limbless_slowdown, movetypes=GROUND)
else
remove_movespeed_modifier(MOVESPEED_ID_LIVING_LIMBLESS, update=TRUE)
return mobility_flags
@@ -97,8 +97,8 @@
var/obj/item/stack/S = I
if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
if(S.custom_materials?.len && S.custom_materials[getmaterialref(/datum/material/iron)])
S.cost = S.custom_materials[getmaterialref(/datum/material/iron)] * 0.25
if(S.custom_materials?.len && S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)])
S.cost = S.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] * 0.25
S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
else if(istype(S, /obj/item/stack/sheet/glass))
@@ -325,6 +325,7 @@ obj/structure/elite_tumor/proc/onEliteWon()
return
E.faction = list("neutral")
E.revive(full_heal = TRUE, admin_revive = TRUE)
E.grab_ghost()
user.visible_message("<span class='notice'>[user] stabs [E] with [src], reviving it.</span>")
E.playsound_local(get_turf(E), 'sound/effects/magic.ogg', 40, 0)
to_chat(E, "<span class='userdanger'>You have been revived by [user]. While you can't speak to them, you owe [user] a great debt. Assist [user.p_them()] in achieving [user.p_their()] goals, regardless of risk.</span")
@@ -275,7 +275,7 @@
H.dna.add_mutation(DWARFISM)
/obj/effect/mob_spawn/human/corpse/damaged/legioninfested/Initialize()
var/type = pickweight(list("Miner" = 66, "Ashwalker" = 10, "Golem" = 10,"Clown" = 10, pick(list("Shadow", "YeOlde","Operative", "Cultist", "Lavaknight")) = 4)) //CIT CHANGE: Lavaknights
var/type = pickweight(list("Miner" = 45, "Ashwalker" = 10, "Golem" = 10,"Clown" = 10, pick(list("Shadow", "YeOlde","Operative", "Cultist", "Lavaknight")) = 4, "Assistant" = 20, "Beelegion" = 1))
switch(type)
if("Miner")
mob_species = pickweight(list(/datum/species/human = 70, /datum/species/lizard = 26, /datum/species/fly = 2, /datum/species/plasmaman = 2))
@@ -374,13 +374,47 @@
l_pocket = /obj/item/melee/cultblade/dagger
glasses = /obj/item/clothing/glasses/hud/health/night/cultblind
backpack_contents = list(/obj/item/reagent_containers/glass/beaker/unholywater = 1, /obj/item/cult_shift = 1, /obj/item/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15)
if("Lavaknight") //START OF CIT CHANGE
if("Lavaknight")
uniform = /obj/item/clothing/under/assistantformal
mask = /obj/item/clothing/mask/breath
shoes = /obj/item/clothing/shoes/sneakers/black
r_pocket = /obj/item/melee/transforming/energy/sword/cx/broken
suit = /obj/item/clothing/suit/space/hardsuit/lavaknight
suit_store = /obj/item/tank/internals/oxygen
id = /obj/item/card/id/knight //END OF CIT CHANGE
id = /obj/item/card/id/knight
id_job = "Knight"
if("Assistant")
uniform = /obj/item/clothing/under/color/grey
belt = /obj/item/tank/internals/emergency_oxygen
mask = /obj/item/clothing/mask/gas
ears = /obj/item/radio/headset
gloves = /obj/item/clothing/gloves/color/fyellow
id = /obj/item/card/id/silver/reaper //looks cool and has a fancy name but only a 1% chance
back = /obj/item/storage/backpack
backpack_contents = list(/obj/item/stack/cable_coil = 12, /obj/item/assembly/flash = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1)
if(prob(99))
id = /obj/item/card/id
id_job = "Assisant"
if(prob(95))
head = /obj/item/clothing/head/hardhat/red
if(prob(5))
gloves = /obj/item/clothing/gloves/color/yellow
if(prob(10))
back = /obj/item/twohanded/spear
backpack_contents = null
if(prob(90))
r_pocket = /obj/item/kitchen/knife
if(prob(60))
l_pocket = /obj/item/soap/homemade
if("Beelegion")
uniform = /obj/item/clothing/under/color/yellow
suit = /obj/item/clothing/suit/hooded/bee_costume
shoes = /obj/item/clothing/shoes/sneakers/yellow
gloves = /obj/item/clothing/gloves/color/yellow
ears = /obj/item/radio/headset
belt = /obj/item/storage/belt/fannypack/yellow
id_job = "Assisant"
id = /obj/item/card/id
l_pocket = /obj/item/reagent_containers/food/drinks/soda_cans/buzz_fuzz
mask = /obj/item/clothing/mask/rat/bee
. = ..()
@@ -186,12 +186,13 @@
if(M.stat == DEAD) // our victim died
if(!client)
if(!rabid && !attacked)
if(M.LAssailant && M.LAssailant != M)
var/mob/living/carbon/their_attacker = M.getLAssailant()
if(their_attacker != M)
if(prob(50))
if(!(M.LAssailant in Friends))
Friends[M.LAssailant] = 1
if(!(their_attacker in Friends))
Friends[their_attacker] = 1
else
++Friends[M.LAssailant]
++Friends[their_attacker]
else
to_chat(src, "<i>This subject does not have a strong enough life energy anymore...</i>")
@@ -70,7 +70,8 @@
var/colour = "grey"
var/coretype = /obj/item/slime_extract/grey
var/list/slime_mutation[4]
var/list/slime_mutation
var/static/list/color_mutation_cache = list()
var/static/list/slime_colours = list("rainbow", "grey", "purple", "metal", "orange",
"blue", "dark blue", "dark purple", "yellow", "silver", "pink", "red",
@@ -84,6 +85,7 @@
/mob/living/simple_animal/slime/Initialize(mapload, new_colour="grey", new_is_adult=FALSE)
initialize_mutations()
var/datum/action/innate/slime/feed/F = new
F.Grant(src)
@@ -108,10 +110,16 @@
AC.Remove(src)
return ..()
/mob/living/simple_animal/slime/proc/initialize_mutations()
var/list/cached = color_mutation_cache[colour]
if(!cached)
cached = color_mutation_cache[colour] = mutation_table(colour)
slime_mutation = cached
/mob/living/simple_animal/slime/proc/set_colour(new_colour)
colour = new_colour
update_name()
slime_mutation = mutation_table(colour)
initialize_mutations()
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
regenerate_icons()
+27
View File
@@ -5,6 +5,8 @@
GLOB.all_clockwork_mobs -= src
GLOB.mob_directory -= tag
focus = null
LAssailant = null
movespeed_modification = null
for (var/alert in alerts)
clear_alert(alert, TRUE)
if(observers && observers.len)
@@ -952,3 +954,28 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/mob/setMovetype(newval)
. = ..()
update_movespeed(FALSE)
/mob/proc/getLAssailant()
return LAssailant?.resolve()
/// Updates the grab state of the mob and updates movespeed
/mob/setGrabState(newstate)
. = ..()
if(grab_state == GRAB_PASSIVE)
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=grab_state*3, blacklisted_movetypes=FLOATING)
/mob/proc/update_equipment_speed_mods()
var/speedies = equipped_speed_mods()
if(!speedies)
remove_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_EQUIPMENT, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speedies, blacklisted_movetypes=FLOATING)
/// Gets the combined speed modification of all worn items
/// Except base mob type doesnt really wear items
/mob/proc/equipped_speed_mods()
for(var/obj/item/I in held_items)
if(I.item_flags & SLOWS_WHILE_IN_HAND)
. += I.slowdown
+2 -2
View File
@@ -80,8 +80,8 @@
var/list/faction = list("neutral") //A list of factions that this mob is currently in, for hostile mob targetting, amongst other things
var/move_on_shuttle = 1 // Can move on the shuttle.
//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition)
var/mob/living/carbon/LAssailant = null
/// The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition)
var/datum/weakref/LAssailant
var/list/obj/user_movement_hooks //Passes movement in client/Move() to these!
+6 -2
View File
@@ -249,8 +249,12 @@
/mob/proc/slip(s_amount, w_amount, obj/O, lube)
return
/mob/proc/update_gravity()
return
/mob/proc/update_gravity(has_gravity, override=FALSE)
var/speed_change = max(0, has_gravity - STANDARD_GRAVITY)
if(!speed_change)
remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE)
else
add_movespeed_modifier(MOVESPEED_ID_MOB_GRAVITY, update=TRUE, priority=100, override=TRUE, multiplicative_slowdown=speed_change, blacklisted_movetypes=FLOATING)
//bodypart selection - Cyberboss
//8 toggles through head - eyes - mouth
@@ -12,12 +12,26 @@
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
has_light = TRUE //LED flashlight!
comp_light_luminosity = 2.3 //Same as the PDA
var/has_variants = TRUE
var/finish_color = null
/obj/item/modular_computer/tablet/update_icon()
..()
if(!finish_color)
finish_color = pick("red","blue","brown","green","black")
icon_state = "tablet-[finish_color]"
icon_state_unpowered = "tablet-[finish_color]"
icon_state_powered = "tablet-[finish_color]"
if(has_variants)
if(!finish_color)
finish_color = pick("red","blue","brown","green","black")
icon_state = "tablet-[finish_color]"
icon_state_unpowered = "tablet-[finish_color]"
icon_state_powered = "tablet-[finish_color]"
/obj/item/modular_computer/tablet/syndicate_contract_uplink
name = "contractor tablet"
icon = 'icons/obj/contractor_tablet.dmi'
icon_state = "tablet-red"
icon_state_unpowered = "tablet"
icon_state_powered = "tablet"
icon_state_menu = "assign"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
comp_light_luminosity = 6.3
has_variants = FALSE
@@ -27,3 +27,18 @@
install_component(new /obj/item/computer_hardware/hard_drive/small)
install_component(new /obj/item/computer_hardware/network_card)
install_component(new /obj/item/computer_hardware/printer/mini)
/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize() // Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
. = ..()
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = new
var/datum/computer_file/program/contract_uplink/uplink = new
active_program = uplink
uplink.program_state = PROGRAM_STATE_ACTIVE
uplink.computer = src
hard_drive.store_file(uplink)
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/network_card)
install_component(new /obj/item/computer_hardware/card_slot)
install_component(new /obj/item/computer_hardware/printer/mini)
@@ -0,0 +1,175 @@
/datum/computer_file/program/contract_uplink
filename = "contractor uplink"
filedesc = "Syndicate Contract Uplink"
program_icon_state = "assign"
extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field."
size = 10
requires_ntnet = 0
available_on_ntnet = 0
unsendable = 1
undeletable = 1
tgui_id = "synd_contract"
ui_style = "syndicate"
ui_x = 600
ui_y = 600
var/error = ""
var/page = CONTRACT_UPLINK_PAGE_CONTRACTS
var/assigned = FALSE
/datum/computer_file/program/contract_uplink/run_program(var/mob/living/user)
. = ..(user)
/datum/computer_file/program/contract_uplink/ui_act(action, params)
if(..())
return 1
var/mob/living/user = usr
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
switch(action)
if("PRG_contract-accept")
var/contract_id = text2num(params["contract_id"])
// Set as the active contract
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ACTIVE
hard_drive.traitor_data.contractor_hub.current_contract = hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id]
program_icon_state = "single_contract"
return 1
if("PRG_login")
var/datum/antagonist/traitor/traitor_data = user.mind.has_antag_datum(/datum/antagonist/traitor)
if(traitor_data) // Bake their data right into the hard drive, or we don't allow non-antags gaining access to unused contract system. We also create their contracts at this point.
if(!traitor_data.contractor_hub) // Only play greet sound, and handle contractor hub when assigning for the first time.
traitor_data.contractor_hub = new
traitor_data.contractor_hub.create_hub_items()
user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, 0)
// Stops any topic exploits such as logging in multiple times on a single system.
if(!assigned)
traitor_data.contractor_hub.create_contracts(traitor_data.owner)
hard_drive.traitor_data = traitor_data
program_icon_state = "contracts"
assigned = TRUE
else
error = "Incorrect login details."
return 1
if("PRG_call_extraction")
if(hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING)
if(hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user))
user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, 1)
hard_drive.traitor_data.contractor_hub.current_contract.status = CONTRACT_STATUS_EXTRACTING
program_icon_state = "extracted"
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
error = "Either both you or your target aren't at the dropoff location, or the pod hasn't got a valid place to land. Clear space, or make sure you're both inside."
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
error = "Already extracting... Place the target into the pod. If the pod was destroyed, you will need to cancel this contract."
return 1
if("PRG_contract_abort")
var/contract_id = hard_drive.traitor_data.contractor_hub.current_contract.id
hard_drive.traitor_data.contractor_hub.current_contract = null
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED
program_icon_state = "contracts"
return 1
if("PRG_redeem_TC")
if(hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user), hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
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>")
else
to_chat(user, "<span class='notice'>Your payment materializes onto the floor.</span>")
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
return 1
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
return 1
if("PRG_clear_error")
error = ""
if("PRG_contractor_hub")
page = CONTRACT_UPLINK_PAGE_HUB
program_icon_state = "store"
if("PRG_hub_back")
page = CONTRACT_UPLINK_PAGE_CONTRACTS
program_icon_state = "contracts"
if("buy_hub")
if(hard_drive.traitor_data.owner.current == user)
var/item = params["item"]
for (var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items)
if (hub_item.name == item)
hub_item.handle_purchase(hard_drive.traitor_data.contractor_hub, user)
else
error = "Invalid user... You weren't recognised as the user of this system."
/datum/computer_file/program/contract_uplink/ui_data(mob/user)
var/list/data = list()
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
var/screen_to_be = null
if(hard_drive && hard_drive.traitor_data != null)
var/datum/antagonist/traitor/traitor_data = hard_drive.traitor_data
error = ""
data = get_header_data()
if(traitor_data.contractor_hub.current_contract)
data["ongoing_contract"] = TRUE
screen_to_be = "single_contract"
if(traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING)
data["extraction_enroute"] = TRUE
screen_to_be = "extracted"
data["logged_in"] = TRUE
data["station_name"] = GLOB.station_name
data["redeemable_tc"] = traitor_data.contractor_hub.contract_TC_to_redeem
data["contract_rep"] = traitor_data.contractor_hub.contract_rep
data["page"] = page
data["error"] = error
for(var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items)
data["contractor_hub_items"] += list(list(
"name" = hub_item.name,
"desc" = hub_item.desc,
"cost" = hub_item.cost,
"limited" = hub_item.limited,
"item_icon" = hub_item.item_icon
))
for(var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts)
var/target_rank = ""
if(contract.contract.target)
var/datum/data/record/record = find_record("name", contract.contract.target.current.real_name, GLOB.data_core.general)
if(record)
target_rank = record.fields["rank"]
else
target_rank = "Unknown"
data["contracts"] += list(list(
"target" = contract.contract.target,
"target_rank" = target_rank,
"payout" = contract.contract.payout,
"payout_bonus" = contract.contract.payout_bonus,
"dropoff" = contract.contract.dropoff,
"id" = contract.id,
"status" = contract.status
))
var/direction
if(traitor_data.contractor_hub.current_contract)
var/turf/curr = get_turf(user)
var/turf/dropoff_turf
data["current_location"] = "[get_area_name(curr, TRUE)]"
for(var/turf/content in traitor_data.contractor_hub.current_contract.contract.dropoff.contents)
if(isturf(content))
dropoff_turf = content
break
if(curr.z == dropoff_turf.z) //Direction calculations for same z-level only
direction = uppertext(dir2text(get_dir(curr, dropoff_turf))) //Direction text (East, etc). Not as precise, but still helpful.
if(get_area(user) == traitor_data.contractor_hub.current_contract.contract.dropoff)
direction = "LOCATION CONFIRMED"
else
direction = "???"
data["dropoff_direction"] = direction
if (page == CONTRACT_UPLINK_PAGE_HUB)
screen_to_be = "store"
if (!screen_to_be)
screen_to_be = "contracts"
else
data["logged_in"] = FALSE
if (!screen_to_be)
screen_to_be = "assign"
program_icon_state = screen_to_be
update_computer_icon()
return data
@@ -158,6 +158,12 @@
icon_state = "ssd_mini"
w_class = WEIGHT_CLASS_TINY
/obj/item/computer_hardware/hard_drive/small/syndicate // Syndicate variant - very slight better
desc = "An efficient SSD for portable devices developed by a rival organisation."
power_usage = 8
max_capacity = 70
var/datum/antagonist/traitor/traitor_data // Syndicate hard drive has the user's data baked directly into it on creation
/obj/item/computer_hardware/hard_drive/micro
name = "micro solid state drive"
desc = "A highly efficient SSD chip for portable devices."
@@ -657,8 +657,7 @@ GLOBAL_LIST_EMPTY(allCasters)
var/mob/living/silicon/ai_user = user
scanned_user = "[ai_user.name] ([ai_user.job])"
else
throw EXCEPTION("Invalid user for this proc")
return
CRASH("Invalid user for this proc")
/obj/machinery/newscaster/proc/print_paper()
SSblackbox.record_feedback("amount", "newspapers_printed", 1)
+1 -1
View File
@@ -69,7 +69,7 @@ Contents:
Mind.add_antag_datum(ninjadatum)
if(Ninja.mind != Mind) //something has gone wrong!
throw EXCEPTION("Ninja created with incorrect mind")
stack_trace("Ninja created with incorrect mind")
spawned_mobs += Ninja
message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by an event.")
+1 -2
View File
@@ -37,8 +37,7 @@
var/mindrain = 200
var/maxdrain = 400
var/stunforce = 140 //Same as stunbaton, adjustable.
var/stunforce = 100
/obj/item/clothing/gloves/space_ninja/Touch(atom/A,proximity)
if(!candrain || draining)
+2 -2
View File
@@ -22,7 +22,7 @@ Contents:
/obj/item/clothing/mask/gas/space_ninja/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
var/list/temp_message = text2list(message, " ")
var/list/temp_message = splittext(message, " ")
var/list/pick_list = list()
for(var/i in 1 to temp_message.len)
pick_list += i
@@ -32,7 +32,7 @@ Contents:
continue
temp_message[H] = ninjaspeak(temp_message[H])
pick_list -= H
message = list2text(temp_message, " ")
message = temp_message.Join(" ")
//The Alternate speech mod is now the main one.
message = replacetext(message, "l", "r")
@@ -53,12 +53,10 @@ It is possible to destroy the net by the occupant or someone else.
if(ishuman(affecting))
var/mob/living/carbon/human/H = affecting
for(var/obj/item/W in H)
if(W == H.w_uniform)
if(W == H.w_uniform || W == H.shoes)
continue//So all they're left with are shoes and uniform.
if(W == H.shoes)
continue
H.dropItemToGround(W)
H.dna.species.give_important_for_life(H) // After we remove items, at least give them what they need to live.
var/datum/antagonist/antag_datum
for(var/datum/antagonist/ninja/AD in GLOB.antagonists) //Because only ninjas get capture objectives; They're not doable without the suit.
if(AD.owner == master)
-1
View File
@@ -264,7 +264,6 @@ They *could* go in their appropriate files, but this is supposed to be modular
electrocute_act(15, H)
DefaultCombatKnockdown(G.stunforce)
adjustStaminaLoss(G.stunforce*0.1, affected_zone = (istype(H) ? H.zone_selected : BODY_ZONE_CHEST))
apply_effect(EFFECT_STUTTER, G.stunforce)
SEND_SIGNAL(src, COMSIG_LIVING_MINOR_SHOCK)
+3 -2
View File
@@ -79,6 +79,7 @@
linked_filter = null
linked_turfs.Cut()
mobs_in_pool.Cut()
mist_off()
return ..()
/obj/machinery/pool/controller/proc/scan_things()
@@ -411,6 +412,7 @@
/obj/machinery/pool/controller/proc/mist_on() //Spawn /obj/effect/mist (from the shower) on all linked pool tiles
if(mist_state)
return
mist_off() //make sure it cycles and deletes everything
mist_state = TRUE
for(var/X in linked_turfs)
var/turf/open/pool/W = X
@@ -419,6 +421,5 @@
linked_mist += M
/obj/machinery/pool/controller/proc/mist_off() //Delete all /obj/effect/mist from all linked pool tiles.
for(var/M in linked_mist)
qdel(M)
QDEL_LIST(linked_mist)
mist_state = FALSE
+1 -2
View File
@@ -570,8 +570,7 @@
else if (istype(W, /obj/item/stack/cable_coil) && opened)
var/turf/host_turf = get_turf(src)
if(!host_turf)
throw EXCEPTION("attackby on APC when it's not on a turf")
return
CRASH("attackby on APC when it's not on a turf")
if (host_turf.intact)
to_chat(user, "<span class='warning'>You must remove the floor plating in front of the APC first!</span>")
return
+1 -2
View File
@@ -67,8 +67,7 @@
/obj/item/gun/energy/Destroy()
if(flags_1 & INITIALIZED_1)
QDEL_NULL(cell)
if(!(flags_1 & HOLOGRAM_1)) //holodeck stuff.
QDEL_LIST(ammo_type)
QDEL_LIST(ammo_type)
STOP_PROCESSING(SSobj, src)
return ..()
+2 -3
View File
@@ -136,7 +136,7 @@
reagents.reaction(target, TOUCH)
else if(bartender_check(target) && thrown)
visible_message("<span class='notice'>[src] lands onto the [target.name] without spilling a single drop.</span>")
visible_message("<span class='notice'>[src] lands without spilling a single drop.</span>")
transform = initial(transform)
addtimer(CALLBACK(src, .proc/ForceResetRotation), 1)
@@ -153,11 +153,10 @@
log_reagent("SPLASH - [src] object SplashReagents() onto [target] at [T] ([AREACOORD(T)])[throwerstring] - [reagents.log_list()]")
visible_message("<span class='notice'>[src] spills its contents all over [target].</span>")
reagents.reaction(target, TOUCH)
reagents.clear_reagents()
if(QDELETED(src))
return
reagents.clear_reagents()
//melts plastic beakers
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
reagents.expose_temperature(1000)
@@ -354,6 +354,14 @@
return
return ..()
/obj/item/reagent_containers/glass/bucket/wood
name = "wooden bucket"
desc = "It's a bucket made of wood."
icon_state = "bucket_wooden"
custom_materials = null
slot_flags = NONE
item_flags = NO_MAT_REDEMPTION
/obj/item/reagent_containers/glass/beaker/waterbottle
name = "bottle of water"
desc = "A bottle of water filled at an old Earth bottling facility."
+1 -1
View File
@@ -137,7 +137,7 @@
else
target.visible_message("<span class='danger'>[user] has placed [target] in [src].</span>", "<span class='userdanger'>[user] has placed [target] in [src].</span>")
log_combat(user, target, "stuffed", addition="into [src]")
target.LAssailant = user
target.LAssailant = WEAKREF(user)
update_icon()
/obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE)
+1 -1
View File
@@ -53,7 +53,7 @@ other types of metals and chemistry for reagents).
for(var/i in materials) //Go through all of our materials, get the subsystem instance, and then replace the list.
var/amount = materials[i]
if(!istext(i)) //Not a category, so get the ref the normal way
var/datum/material/M = getmaterialref(i)
var/datum/material/M = SSmaterials.GetMaterialRef(i)
temp_list[M] = amount
else
temp_list[i] = amount
@@ -27,7 +27,7 @@
rogue_types = list(/datum/nanite_program/toxic, /datum/nanite_program/nerve_decay)
/datum/nanite_program/adrenaline/on_trigger()
host_mob.do_adrenaline(-10, TRUE, TRUE, FALSE, TRUE, list(/datum/reagent/medicine/stimulants = 1.5), "<span class='notice'>You feel a sudden surge of energy!</span>", FALSE, FALSE, FALSE)
host_mob.do_adrenaline(50, TRUE, TRUE, FALSE, TRUE, list(), "<span class='notice'>You feel a sudden surge of energy!</span>", 25)
/datum/nanite_program/hardening
name = "Dermal Hardening"
@@ -236,7 +236,7 @@
if(X.monkeys >= 1)
var/mob/living/carbon/monkey/food = new /mob/living/carbon/monkey(remote_eye.loc, TRUE, owner)
if (!QDELETED(food))
food.LAssailant = C
food.LAssailant = WEAKREF(C)
X.monkeys --
to_chat(owner, "<span class='notice'>[X] now has [X.monkeys] monkey(s) left.</span>")
else
@@ -474,7 +474,7 @@
if(X.monkeys >= 1)
var/mob/living/carbon/monkey/food = new /mob/living/carbon/monkey(T, TRUE, C)
if (!QDELETED(food))
food.LAssailant = C
food.LAssailant = WEAKREF(C)
X.monkeys--
X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
to_chat(C, "<span class='notice'>[X] now has [X.monkeys] monkey(s) stored.</span>")
@@ -30,6 +30,17 @@
cost = 14 // normally 16
include_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/bundles_TC/contract_kit
name = "Contract Kit"
desc = "The Syndicate have offered you the chance to become a contractor, take on kidnapping contracts for TC and cash payouts. Upon purchase, \
you'll be granted your own contract uplink embedded within the supplied tablet computer. Additionally, you'll be granted \
standard contractor gear to help with your mission - comes supplied with the tablet, specialised space suit, chameleon jumpsuit and mask, \
specialised contractor baton, and three randomly selected low cost items. Can include otherwise unobtainable items."
item = /obj/item/storage/box/syndie_kit/contract_kit
cost = 20
player_minimum = 20
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/bundles_TC/cybernetics_bundle
name = "Cybernetic Implants Bundle"
desc = "A random selection of cybernetic implants. Guaranteed 5 high quality implants. Comes with an autosurgeon."
+4 -2
View File
@@ -161,6 +161,8 @@
SSbellies.belly_list -= src
if(owner?.vore_organs)
owner.vore_organs -= src
if(owner.vore_selected == src)
owner.vore_selected = null
owner = null
. = ..()
@@ -413,7 +415,7 @@
if("em")
raw_messages = examine_messages
var/messages = list2text(raw_messages,delim)
var/messages = raw_messages.Join(delim)
return messages
// The next function sets the messages on the belly, from human-readable var
@@ -422,7 +424,7 @@
/obj/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_list = text2list(html_encode(raw_text),delim)
var/list/raw_list = splittext(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
testing("[owner] tried to set [lowertext(name)] with 11+ messages")
+1 -1
View File
@@ -574,7 +574,7 @@
if(new_bulge == 0) //Disable.
selected.bulge_size = 0
to_chat(user,"<span class='notice'>Your stomach will not be seen on examine.</span>")
else if (!IsInRange(new_bulge,25,200))
else if (!ISINRANGE(new_bulge,25,200))
selected.bulge_size = 0.25 //Set it to the default.
to_chat(user,"<span class='notice'>Invalid size.</span>")
else if(new_bulge)
+3 -3
View File
@@ -78,12 +78,12 @@ in their list
/proc/list_to_object(var/list/data, var/loc)
if(!islist(data))
throw EXCEPTION("You didn't give me a list, bucko")
stack_trace("You didn't give me a list, bucko")
if(!("type" in data))
throw EXCEPTION("No 'type' field in the data")
stack_trace("No 'type' field in the data")
var/path = text2path(data["type"])
if(!path)
throw EXCEPTION("Path not found: [path]")
stack_trace("Path not found: [path]")
var/atom/movable/thing = new path(loc)
thing.deserialize(data)