Merge branch 'master' into gc_debugging

This commit is contained in:
kevinz000
2020-03-06 10:14:19 -07:00
committed by GitHub
62 changed files with 1390 additions and 120 deletions
+39 -11
View File
@@ -655,7 +655,7 @@
/turf/open/floor/plating,
/area/mine/laborcamp)
"ia" = (
/obj/item/reagent_containers/glass/bucket,
/obj/item/reagent_containers/glass/bucket/wood,
/obj/structure/stone_tile/block/cracked{
dir = 4
},
@@ -750,8 +750,23 @@
/obj/item/stack/sheet/mineral/wood,
/obj/item/stack/sheet/mineral/wood,
/obj/item/stack/sheet/mineral/wood,
/obj/item/seeds/tower,
/obj/item/seeds/tower,
/obj/item/seeds/ambrosia/deus{
yield = 5
potency = 50
},
/obj/item/seeds/ambrosia/deus{
yield = 5
potency = 50
},
/obj/item/seeds/tower{
yield = 5
potency = 50
},
/obj/item/seeds/tower{
yield = 5
potency = 50
},
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen,
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"iJ" = (
@@ -2179,8 +2194,15 @@
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"wm" = (
/obj/item/seeds/glowshroom,
/obj/item/seeds/glowshroom,
/obj/item/seeds/glowshroom{
yield = 5
potency = 50
},
/obj/item/seeds/glowshroom{
yield = 5
potency = 50
},
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
/obj/structure/stone_tile/block{
dir = 4
},
@@ -3327,8 +3349,15 @@
dir = 4
},
/obj/item/storage/bag/plants/portaseeder,
/obj/item/seeds/cotton,
/obj/item/seeds/cotton,
/obj/item/storage/bag/plants,
/obj/item/seeds/cotton{
yield = 5
potency = 50
},
/obj/item/seeds/cotton{
yield = 5
potency = 50
},
/turf/open/indestructible/boss,
/area/ruin/unpowered/ash_walkers)
"Vj" = (
@@ -3355,10 +3384,9 @@
/turf/open/floor/plasteel,
/area/mine/laborcamp)
"VI" = (
/obj/structure/stone_tile{
dir = 8
},
/obj/structure/reagent_dispensers/watertank,
/obj/structure/well_foundation,
/obj/item/reagent_containers/glass/bucket/wood,
/obj/item/reagent_containers/glass/bucket/wood,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/ash_walkers)
"VP" = (
+15
View File
@@ -34,6 +34,21 @@
#define HIJACK_HIJACKER 1 //Needs to be present for shuttle to be hijacked
#define HIJACK_PREVENT 2 //Prevents hijacking same way as non-antags
//Syndicate Contracts
#define CONTRACT_STATUS_INACTIVE 1
#define CONTRACT_STATUS_ACTIVE 2
#define CONTRACT_STATUS_BOUNTY_CONSOLE_ACTIVE 3
#define CONTRACT_STATUS_EXTRACTING 4
#define CONTRACT_STATUS_COMPLETE 5
#define CONTRACT_STATUS_ABORTED 6
#define CONTRACT_PAYOUT_LARGE 1
#define CONTRACT_PAYOUT_MEDIUM 2
#define CONTRACT_PAYOUT_SMALL 3
#define CONTRACT_UPLINK_PAGE_CONTRACTS "CONTRACTS"
#define CONTRACT_UPLINK_PAGE_HUB "HUB"
//Overthrow time to update heads obj
#define OBJECTIVE_UPDATING_TIME 300
+5
View File
@@ -1,5 +1,10 @@
#define BP_MAX_ROOM_SIZE 300
GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/engineering, \
/area/engine/supermatter, \
/area/engine/atmospherics_engine, \
/area/ai_monitored/turret_protected/ai))
//Repopulates sortedAreas list
/proc/repopulate_sorted_areas()
GLOB.sortedAreas = list()
+33
View File
@@ -549,3 +549,36 @@
var/pressure = environment.return_pressure()
if(pressure <= LAVALAND_EQUIPMENT_EFFECT_PRESSURE)
. = TRUE
/proc/ispipewire(item)
var/static/list/pipe_wire = list(
/obj/machinery/atmospherics,
/obj/structure/disposalpipe,
/obj/structure/cable
)
return (is_type_in_list(item, pipe_wire))
// Find a obstruction free turf that's within the range of the center. Can also condition on if it is of a certain area type.
/proc/find_obstruction_free_location(var/range, var/atom/center, var/area/specific_area)
var/list/turfs = RANGE_TURFS(range, center)
var/list/possible_loc = list()
for(var/turf/found_turf in turfs)
var/area/turf_area = get_area(found_turf)
if (specific_area) // We check if both the turf is a floor, and that it's actually in the area. // We also want a location that's clear of any obstructions.
if(!istype(turf_area, specific_area))
continue
if(!isspaceturf(found_turf))
if(!is_blocked_turf(found_turf))
possible_loc.Add(found_turf)
if (possible_loc.len < 1) // Need at least one free location.
return FALSE
return pick(possible_loc)
/proc/power_fail(duration_min, duration_max)
for(var/P in GLOB.apcs_list)
var/obj/machinery/power/apc/C = P
if(C.cell && SSmapping.level_trait(C.z, ZTRAIT_STATION))
var/area/A = C.area
if(GLOB.typecache_powerfailure_safe_areas[A.type])
continue
C.energy_fail(rand(duration_min,duration_max))
+1
View File
@@ -354,6 +354,7 @@
roundend_report.set_content(content)
roundend_report.stylesheets = list()
roundend_report.add_stylesheet("roundend", 'html/browser/roundend.css')
roundend_report.add_stylesheet("font-awesome", 'html/font-awesome/css/all.min.css')
roundend_report.open(0)
/datum/controller/subsystem/ticker/proc/personal_report(client/C, popcount)
+15 -1
View File
@@ -49,7 +49,7 @@
alert("Invalid name.")
return ""
return sanitize(t)
/proc/sanitize_filename(t)
return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"=""))
@@ -798,3 +798,17 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
out += prob(replaceprob)? pick(replacementchars) : char
return out.Join("")
/proc/readable_corrupted_text(text)
var/list/corruption_options = list("..", "£%", "~~\"", "!!", "*", "^", "$!", "-", "}", "?")
var/corrupted_text = ""
for(var/letter_index = 1; letter_index <= length(text); letter_index++) // Have every letter have a chance of creating corruption on either side
var/letter = text[letter_index] // Small chance of letters being removed in place of corruption - still overall readable
if(prob(15))
corrupted_text += pick(corruption_options)
if(prob(95))
corrupted_text += letter
else
corrupted_text += pick(corruption_options)
if(prob(15))
corrupted_text += pick(corruption_options)
return corrupted_text
+3 -1
View File
@@ -18,6 +18,7 @@
#define POLL_IGNORE_DEMON "demon"
#define POLL_IGNORE_WIZARD "wizard"
#define POLL_IGNORE_CLONE "clone"
#define POLL_IGNORE_CONTRACTOR_SUPPORT "contractor_support"
GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_SENTIENCE_POTION = "Sentience potion",
@@ -37,7 +38,8 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_SPLITPERSONALITY = "Split Personality",
POLL_IGNORE_DEMON = "Demons",
POLL_IGNORE_WIZARD = "Wizards",
POLL_IGNORE_CLONE = "Defective/SDGF clones"
POLL_IGNORE_CLONE = "Defective/SDGF clones",
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit"
))
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
+9 -3
View File
@@ -39,12 +39,18 @@
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
if(istype(name, /datum/asset/spritesheet))
if (istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else
stylesheets["[ckey(name)].css"] = file
register_asset("[ckey(name)].css", file)
var/asset_name = "[name].css"
stylesheets[asset_name] = file
if(!SSassets.cache[asset_name])
register_asset(asset_name, file)
/datum/browser/proc/add_script(name, file)
scripts["[ckey(name)].js"] = file
register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
+4
View File
@@ -617,6 +617,10 @@
if(!(has_antag_datum(/datum/antagonist/traitor)))
add_antag_datum(/datum/antagonist/traitor)
/datum/mind/proc/make_Contractor_Support()
if(!(has_antag_datum(/datum/antagonist/traitor/contractor_support)))
add_antag_datum(/datum/antagonist/traitor/contractor_support)
/datum/mind/proc/make_Changeling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
if(!C)
+2
View File
@@ -3,6 +3,8 @@
/area/ruin/space
has_gravity = FALSE
blob_allowed = FALSE //Nope, no winning in space as a blob. Gotta eat the station.
outdoors = TRUE
ambientsounds = SPACE
/area/ruin/space/has_grav
has_gravity = STANDARD_GRAVITY
+25 -4
View File
@@ -86,8 +86,10 @@ GLOBAL_LIST_EMPTY(objectives)
if(M)
. += M
/datum/objective/proc/find_target()
/datum/objective/proc/find_target(dupe_search_range, blacklist)
var/list/datum/mind/owners = get_owners()
if(!dupe_search_range)
dupe_search_range = get_owners()
var/list/possible_targets = list()
var/try_target_late_joiners = FALSE
for(var/I in owners)
@@ -96,7 +98,8 @@ GLOBAL_LIST_EMPTY(objectives)
try_target_late_joiners = TRUE
for(var/datum/mind/possible_target in get_crewmember_minds())
if(!(possible_target in owners) && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && is_unique_objective(possible_target))
possible_targets += possible_target
if(!(possible_target in blacklist))
possible_targets += possible_target
if(try_target_late_joiners)
var/list/all_possible_targets = possible_targets.Copy()
for(var/I in all_possible_targets)
@@ -1075,7 +1078,7 @@ GLOBAL_LIST_EMPTY(cult_contraband)
var/mob/living/carbon/human/H = owner
H.equip_in_one_of_slots(I, list("backpack" = SLOT_IN_BACKPACK))
hoarded_item = I
GLOBAL_LIST_EMPTY(possible_sabotages)
@@ -1092,7 +1095,7 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
if(!GLOB.possible_sabotages.len)//Only need to fill the list when it's needed.
for(var/I in subtypesof(/datum/sabotage_objective))
new I
/datum/objective/sabotage/find_target()
var/list/datum/mind/owners = get_owners()
var/approved_targets = list()
@@ -1155,3 +1158,21 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
/datum/objective/flavor/wizard
flavor_file = "strings/flavor_objectives/wizard.txt"
/datum/objective/contract
var/payout = 0
var/payout_bonus = 0
var/area/dropoff = null
/datum/objective/contract/proc/generate_dropoff() // Generate a random valid area on the station that the dropoff will happen.
var/found = FALSE
while(!found)
var/area/dropoff_area = pick(GLOB.sortedAreas)
if(dropoff_area && is_station_level(dropoff_area.z) && !dropoff_area.outdoors)
dropoff = dropoff_area
found = TRUE
/datum/objective/contract/proc/dropoff_check(mob/user, mob/target) // Check if both the contractor and contract target are at the dropoff point.
var/area/user_area = get_area(user)
var/area/target_area = get_area(target)
return (istype(user_area, dropoff) && istype(target_area, dropoff))
+4 -4
View File
@@ -23,18 +23,18 @@
START_PROCESSING(SSprocessing, src)
/datum/sabotage_objective/processing/proc/check_condition_processing()
return 100
return 1
/datum/sabotage_objective/processing/process()
check_condition_processing()
if(won >= 100)
if(won >= 1)
STOP_PROCESSING(SSprocessing,src)
/datum/sabotage_objective/processing/check_conditions()
return won
/datum/sabotage_objective/processing/power_sink
name = "Drain at least 1 gigajoule of power using a power sink."
name = "Drain at least 100 megajoules of power using a power sink."
sabotage_type = "powersink"
special_equipment = list(/obj/item/sbeacondrop/powersink)
var/sink_found = FALSE
@@ -47,7 +47,7 @@
for(var/datum/powernet/PN in GLOB.powernets)
for(var/obj/item/powersink/sink in PN.nodes)
sink_found_this_time = TRUE
won = max(won,sink.power_drained/1e9)
won = max(won,sink.power_drained/1e8)
sink_found = sink_found_this_time
count = 0
return FALSE
+129 -23
View File
@@ -181,13 +181,60 @@
slot_flags = ITEM_SLOT_BELT
force = 12 //9 hit crit
w_class = WEIGHT_CLASS_NORMAL
var/cooldown = 13
var/on = TRUE
var/last_hit = 0
var/stun_stam_cost_coeff = 1.25
var/hardstun_ds = 1
var/hardstun_ds = TRUE
var/softstun_ds = 0
var/stam_dmg = 30
var/cooldown_check = 0 // Used internally, you don't want to modify
var/cooldown = 13 // Default wait time until can stun again.
var/stun_time_silicon = 60 // How long it stuns silicons for - 6 seconds.
var/affect_silicon = FALSE // Does it stun silicons.
var/on_sound // "On" sound, played when switching between able to stun or not.
var/on_stun_sound = "sound/effects/woodhit.ogg" // Default path to sound for when we stun.
var/stun_animation = TRUE // Do we animate the "hit" when stunning.
var/on = TRUE // Are we on or off
var/on_icon_state // What is our sprite when turned on
var/off_icon_state // What is our sprite when turned off
var/on_item_state // What is our in-hand sprite when turned on
var/force_on // Damage when on - not stunning
var/force_off // Damage when off - not stunning
var/weight_class_on // What is the new size class when turned on
/obj/item/melee/classic_baton/Initialize()
. = ..()
// Description for trying to stun when still on cooldown.
/obj/item/melee/classic_baton/proc/get_wait_description()
return
// Description for when turning their baton "on"
/obj/item/melee/classic_baton/proc/get_on_description()
. = list()
.["local_on"] = "<span class ='warning'>You extend the baton.</span>"
.["local_off"] = "<span class ='notice'>You collapse the baton.</span>"
return .
// Default message for stunning mob.
/obj/item/melee/classic_baton/proc/get_stun_description(mob/living/target, mob/living/user)
. = list()
.["visible"] = "<span class ='danger'>[user] has knocked down [target] with [src]!</span>"
.["local"] = "<span class ='danger'>[user] has knocked down [target] with [src]!</span>"
return .
// Default message for stunning a silicon.
/obj/item/melee/classic_baton/proc/get_silicon_stun_description(mob/living/target, mob/living/user)
. = list()
.["visible"] = "<span class='danger'>[user] pulses [target]'s sensors with the baton!</span>"
.["local"] = "<span class='danger'>You pulse [target]'s sensors with the baton!</span>"
return .
// Are we applying any special effects when we stun to carbon
/obj/item/melee/classic_baton/proc/additional_effects_carbon(mob/living/target, mob/living/user)
return
// Are we applying any special effects when we stun to silicon
/obj/item/melee/classic_baton/proc/additional_effects_silicon(mob/living/target, mob/living/user)
return
/obj/item/melee/classic_baton/attack(mob/living/target, mob/living/user)
if(!on)
@@ -208,15 +255,28 @@
user.take_bodypart_damage(2*force)
return
if(iscyborg(target))
..()
if(user.a_intent != INTENT_HARM) // We don't stun if we're on harm.
if(affect_silicon)
var/list/desc = get_silicon_stun_description(target, user)
target.flash_act(affect_silicon = TRUE)
target.Stun(stun_time_silicon)
additional_effects_silicon(target, user)
user.visible_message(desc["visible"], desc["local"])
playsound(get_turf(src), on_stun_sound, 100, TRUE, -1)
if(stun_animation)
user.do_attack_animation(target)
else
..()
else
..()
return
if(!isliving(target))
return
if (user.a_intent == INTENT_HARM)
if(user.a_intent == INTENT_HARM)
if(!..() || !iscyborg(target))
return
else
if(last_hit < world.time)
if(cooldown_check < world.time)
if(target.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
return
@@ -224,18 +284,25 @@
var/mob/living/carbon/human/H = target
if(check_martial_counter(H, user))
return
playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1)
var/list/desc = get_stun_description(target, user)
if(stun_animation)
user.do_attack_animation(target)
playsound(get_turf(src), on_stun_sound, 75, 1, -1)
target.DefaultCombatKnockdown(softstun_ds, TRUE, FALSE, hardstun_ds, stam_dmg)
additional_effects_carbon(target, user)
log_combat(user, target, "stunned", src)
src.add_fingerprint(user)
target.visible_message("<span class ='danger'>[user] has knocked down [target] with [src]!</span>", \
"<span class ='userdanger'>[user] has knocked down [target] with [src]!</span>")
add_fingerprint(user)
target.visible_message(desc["visible"], desc["local"])
if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = WEAKREF(user)
last_hit = world.time + cooldown
cooldown_check = world.time + cooldown
user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes swinging batons cost stamina
else
var/wait_desc = get_wait_description()
if(wait_desc)
to_chat(user, wait_desc)
/obj/item/melee/classic_baton/telescopic
name = "telescopic baton"
@@ -250,6 +317,13 @@
item_flags = NONE
force = 0
on = FALSE
on_sound = 'sound/weapons/batonextend.ogg'
on_icon_state = "telebaton_1"
off_icon_state = "telebaton_0"
on_item_state = "nullrod"
force_on = 10
force_off = 0
weight_class_on = WEIGHT_CLASS_BULKY
total_mass = TOTAL_MASS_NORMAL_ITEM
/obj/item/melee/classic_baton/telescopic/suicide_act(mob/user)
@@ -260,7 +334,7 @@
if(!on)
src.attack_self(user)
else
playsound(loc, 'sound/weapons/batonextend.ogg', 50, 1)
playsound(loc, on_sound, 50, 1)
add_fingerprint(user)
sleep(3)
if (H && !QDELETED(H))
@@ -272,25 +346,57 @@
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user)
on = !on
var/list/desc = get_on_description()
if(on)
to_chat(user, "<span class ='warning'>You extend the baton.</span>")
icon_state = "telebaton_1"
item_state = "nullrod"
w_class = WEIGHT_CLASS_BULKY //doesnt fit in backpack when its on for balance
force = 10 //stunbaton damage
to_chat(user, desc["local_on"])
icon_state = on_icon_state
item_state = on_item_state
w_class = weight_class_on
force = force_on
attack_verb = list("smacked", "struck", "cracked", "beaten")
else
to_chat(user, "<span class ='notice'>You collapse the baton.</span>")
icon_state = "telebaton_0"
to_chat(user, desc["local_off"])
icon_state = off_icon_state
item_state = null //no sprite for concealment even when in hand
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
force = 0 //not so robust now
force = force_off
attack_verb = list("hit", "poked")
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
playsound(src.loc, on_sound, 50, 1)
add_fingerprint(user)
/obj/item/melee/classic_baton/telescopic/contractor_baton
name = "contractor baton"
desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "contractor_baton_0"
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
item_state = null
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
item_flags = NONE
force = 5
cooldown = 20
stam_dmg = 45 //3 hit stamcrit
affect_silicon = TRUE
on_sound = 'sound/weapons/contractorbatonextend.ogg'
on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
on_icon_state = "contractor_baton_1"
off_icon_state = "contractor_baton_0"
on_item_state = "contractor_baton"
force_on = 16
force_off = 5
weight_class_on = WEIGHT_CLASS_NORMAL
/obj/item/melee/classic_baton/telescopic/contractor_baton/get_wait_description()
return "<span class='danger'>The baton is still charging!</span>"
/obj/item/melee/classic_baton/telescopic/contractor_baton/additional_effects_carbon(mob/living/target, mob/living/user)
target.Jitter(20)
target.apply_effect(EFFECT_STUTTER, 20)
target.apply_status_effect(/datum/status_effect/electrostaff, 30) //knockdown, disarm, and slowdown, the unholy triumvirate of stam combat
/obj/item/melee/supermatter_sword
name = "supermatter sword"
desc = "In a station full of bad ideas, this might just be the worst."
+9 -2
View File
@@ -17,6 +17,7 @@
var/active = FALSE
var/atom/movable/target //The thing we're searching for
var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
var/ignore_suit_sensor_level = FALSE // Do we find people even if their suit sensors are turned off
var/alert = FALSE // TRUE to display things more seriously
/obj/item/pinpointer/Initialize()
@@ -77,6 +78,8 @@
name = "crew pinpointer"
desc = "A handheld tracking device that points to crew suit sensors."
icon_state = "pinpointer_crew"
var/has_owner = FALSE
var/pinpointer_owner = null
/obj/item/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
var/turf/here = get_turf(src)
@@ -84,7 +87,7 @@
var/obj/item/clothing/under/U = H.w_uniform
// Suit sensors must be on maximum.
if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS)
if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS && !ignore_suit_sensor_level)
return FALSE
var/turf/there = get_turf(H)
@@ -101,7 +104,11 @@
STOP_PROCESSING(SSfastprocess, src)
update_icon()
return
if (has_owner && !pinpointer_owner)
pinpointer_owner = user
if (pinpointer_owner && pinpointer_owner != user)
to_chat(user, "<span class='notice'>The pinpointer doesn't respond. It seems to only recognise its owner.</span>")
return
var/list/name_counts = list()
var/list/names = list()
@@ -229,6 +229,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
null, \
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \
new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 30), \
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 15),\
null, \
@@ -397,3 +397,97 @@
/obj/item/storage/box/syndie_kit/revolver/PopulateContents()
new /obj/item/gun/ballistic/revolver(src)
new /obj/item/ammo_box/a357(src)
/obj/item/storage/box/syndie_kit/contract_kit
name = "contractor kit"
desc = "Supplied to Syndicate contractors in active mission areas."
/obj/item/storage/box/syndicate/contractor_loadout
name = "standard loadout"
desc = "Supplied to Syndicate contractors, providing their specialised space suit and chameleon uniform."
icon_state = "syndiebox"
illustration = "writing_syndie"
/obj/item/paper/contractor_guide
name = "Contractor Guide"
/obj/item/paper/contractor_guide/Initialize()
info = {"<p>Welcome agent, congratulations on your new position as contractor. On top of your already assigned objectives,
this kit will provide you contracts to take on for TC payments.</p>
<p>Provided within, we give your specialist contractor space suit. It's even more compact, being able to fit into a pocket, and faster than the
Syndicate space suit available to you on the uplink. We also provide your chameleon jumpsuit and mask, both of which can be changed
to any form you need for the moment. The cigarettes are a special blend - it'll heal your injuries slowly overtime.</p>
<p>The three additional items, apart from the tablet and loadout box, have been randomly selected from what we had available. We hope
they're useful to you for you mission.</p>
<p>The contractor hub, available at the top right of the uplink, will provide you unique items and abilities. These are bought using Contractor Rep,
with two Rep being provided each time you complete a contract.</p>
<h3>Using the tablet</h3>
<ol>
<li>Open the Syndicate Contract Uplink program.</li>
<li>Assign yourself.</li>
<li>Here, you can accept a contract, and redeem your TC payments from completed contracts.</li>
<li>The payment number shown in brackets is the bonus you'll recieve when bringing your target <b>alive</b>. You recieve the
other number regardless of if they were alive or dead.</li>
<li>Contracts are completed by bringing the target to designated dropoff, calling for extraction, and putting them
inside the pod.</li>
</ol>
<p>Be careful when accepting a contract. While you'll be able to see the location of the dropoff point, cancelling will make it
unavailable to take on again.</p>
<p>The tablet can also be recharged at any cell charger.</p>
<h3>Extracting</h3>
<ol>
<li>Make sure both yourself and your target are at the dropoff.</li>
<li>Call the extraction, and stand back from the drop point</li>
<li>If it fails, make sure your target is inside, and there's a free space for the pod to land.</li>
<li>Grab your target, and drag them into the pod.</li>
</ol>
<h3>Ransoms</h3>
<p>We need your target for our own reasons, but we ransom them back to your mission area once their use is served. They will return back
from where you sent them off from in several minutes time. You will be paid in TC for your services.</p>
<p>Good luck agent. You can burn this document with the supplied lighter.</p>"}
return ..()
/obj/item/storage/box/syndicate/contractor_loadout/PopulateContents()
new /obj/item/clothing/head/helmet/space/syndicate/contract(src)
new /obj/item/clothing/suit/space/syndicate/contract(src)
new /obj/item/clothing/under/chameleon(src)
new /obj/item/clothing/mask/chameleon(src)
new /obj/item/card/id/syndicate(src)
new /obj/item/storage/fancy/cigarettes/cigpack_syndicate(src)
new /obj/item/lighter(src)
/obj/item/storage/box/syndie_kit/contract_kit/PopulateContents()
new /obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink(src)
new /obj/item/storage/box/syndicate/contractor_loadout(src)
new /obj/item/melee/classic_baton/telescopic/contractor_baton(src)
var/list/item_list = list( // All 4 TC or less - some nukeops only items, but fit nicely to the theme.
/obj/item/storage/backpack/duffelbag/syndie/x4,
/obj/item/storage/box/syndie_kit/throwing_weapons,
/obj/item/gun/syringe/syndicate,
/obj/item/pen/edagger,
/obj/item/pen/sleepy,
/obj/item/flashlight/emp,
/obj/item/reagent_containers/syringe/mulligan,
/obj/item/clothing/shoes/chameleon/noslip,
/obj/item/storage/firstaid/tactical,
/obj/item/storage/backpack/duffelbag/syndie/surgery,
/obj/item/encryptionkey/syndicate,
/obj/item/clothing/glasses/thermal/syndi,
/obj/item/slimepotion/slime/sentience/nuclear,
/obj/item/storage/box/syndie_kit/imp_radio,
/obj/item/storage/box/syndie_kit/imp_uplink,
/obj/item/clothing/gloves/krav_maga/combatglovesplus,
/obj/item/gun/ballistic/automatic/c20r/toy/unrestricted/riot,
/obj/item/reagent_containers/syringe/stimulants,
/obj/item/storage/box/syndie_kit/imp_freedom,
/obj/item/toy/eightball/haunted
)
var/obj/item1 = pick_n_take(item_list)
var/obj/item2 = pick_n_take(item_list)
var/obj/item3 = pick_n_take(item_list)
new item1(src) // Create three, non repeat items from the list.
new item2(src)
new item3(src)
new /obj/item/paper/contractor_guide(src) //Paper guide
+72 -8
View File
@@ -444,9 +444,6 @@
C.adjustFireLoss(5)
to_chat(C, "<span class='danger'>The water is searing!</span>")
/obj/item/bikehorn/rubberducky
name = "rubber ducky"
desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl
@@ -454,8 +451,6 @@
icon_state = "rubberducky"
item_state = "rubberducky"
/obj/structure/sink
name = "sink"
icon = 'icons/obj/watercloset.dmi'
@@ -465,7 +460,6 @@
var/busy = FALSE //Something's being washed at the moment
var/dispensedreagent = /datum/reagent/water // for whenever plumbing happens
/obj/structure/sink/attack_hand(mob/living/user)
. = ..()
if(.)
@@ -578,12 +572,82 @@
new /obj/item/stack/sheet/metal (loc, 3)
qdel(src)
/obj/structure/sink/kitchen
name = "kitchen sink"
icon_state = "sink_alt"
/obj/structure/sink/well
name = "well"
desc = "A well, used to get water from an underground reservoir."
icon_state = "well"
//The making of the well
/obj/structure/well_foundation
name = "well foundation"
desc = "A small patch of dirt, ready for a well to be made over it. Just use a shovel!"
icon = 'icons/obj/watercloset.dmi'
icon_state = "well_1"
density = FALSE
anchored = TRUE
max_integrity = 1000
var/steps = 0
/obj/structure/well_foundation/attackby(obj/item/S, mob/user, params)
if(steps == 0 && S.tool_behaviour == TOOL_SHOVEL)
S.use_tool(src, user, 80, volume=100)
steps = 1
desc = "A deep patch of dirt, ready for a well to be made over it. Just add some sandstone!"
icon_state = "well_1"
return TRUE
if(steps == 1 && istype(S, /obj/item/stack/sheet/mineral/sandstone))
if(S.use(15))
steps = 2
desc = "A patch of dirt and bricks. Just add some more sandstone!"
icon_state = "well_2"
return TRUE
else
to_chat(user, "<span class='warning'>You need at least fifteen pieces of sandstone!</span>")
return
if(steps == 2 && istype(S, /obj/item/stack/sheet/mineral/sandstone))
if(S.use(25))
steps = 3
desc = "A large well foundation ready to be dug out. Just use a shovel!"
icon_state = "well_3"
return TRUE
else
to_chat(user, "<span class='warning'>You need at least tweenty-five pieces of sandstone!</span>")
return
if(steps == 3 && S.tool_behaviour == TOOL_SHOVEL)
S.use_tool(src, user, 80, volume=100)
steps = 4
desc = "A deep patch of dirt, needs something to hold a bucket and rope. Just add some wood planks!"
icon_state = "well_3"
return TRUE
if(steps == 4 && istype(S, /obj/item/stack/sheet/mineral/wood))
if(S.use(3))
steps = 5
desc = "A dug out well, A dug out well with out rope. Just add some cloth!"
icon_state = "well_4"
return TRUE
else
to_chat(user, "<span class='warning'>You need at least three planks!</span>")
return
if(steps == 5 && istype(S, /obj/item/stack/sheet/cloth))
if(S.use(2))
steps = 6
desc = "A dug out well with a rope. Just add a wooden bucket!"
icon_state = "well_5"
return TRUE
else
to_chat(user, "<span class='warning'>You need at least two pieces of cloth!</span>")
return
if(steps == 6 && istype(S, /obj/item/reagent_containers/glass/bucket/wood))
new /obj/structure/sink/well(loc)
qdel(S)
qdel(src)
return
else
return ..()
/obj/structure/sink/puddle //splishy splashy ^_^
name = "puddle"
@@ -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>"
@@ -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)
+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()
+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 -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)
@@ -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"
+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())
@@ -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)
@@ -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()
@@ -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."
@@ -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)
+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
@@ -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."
@@ -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."
@@ -0,0 +1,7 @@
author: "Trilbyspaceclone"
delete-after: True
changes:
- rscadd: "Well contruction, grubs to ash walker home, more seeds for ash walkers."
- rscadd: "Wooden buckets can be made from 2 planks of wood, Tower caps also can be used on a fire to make coal"
- tweak: "Makes all ashwalker round start seeds 5 yield and 50 harvest so that they can get good crops in rather then failing after 1 harvest"
- bugfix: "arrow crafting has been fixed"
@@ -1,5 +0,0 @@
author: "ancientpower"
delete-after: True
changes:
- imageadd: "Snazzier sprites for paramedic gear."
- rscadd: "Unused paramedic gear added for future use."
@@ -0,0 +1,26 @@
author: "Kraseo"
delete-after: True
changes:
- rscadd: "Syndicate Contracts. Use the new contract uplink to select a contract, and bring the assigned target dead or alive to the designated drop off. Call for the extraction pod and send them off for your TC payment, with much higher rewards for keeping them alive. A high risk, high reward choice for a traitor who wants a real challenge."
- rscadd: "New 20 TC contract kit - supplies you with your contractor loadout and uplink."
- rscadd: "Targets successfully extracted will be held for ransom by the Syndicate after their use to them is fulfilled. Central command covers the cost, but they'll be taking a cut out of station funds to offset their loss..."
- rscadd: "Adds a third random item, as well as a small guide on using the contract kit. Also added new possible items that can appear."
- tweak: "Supplied space suit in the contract kit is now an improved variant on the normal Syndicate version."
- balance: "TC payouts adjusted to be a bit more fair to the contractor. Total payout can never be below a certain threshold."
- bugfix: "Broken dropoff locations work again, and general bugfixes."
- rscadd: "Contract kit comes with a contractor baton - a unique, lightly electrified weapon to help complete your contracts."
- tweak: "Finalized payment system for contracts; much more balanced for contractors. No more extremely low paying contract sets."
- tweak: "Generated contracts will all have unique targets, no more duplicates."
- tweak: "Extraction droppod explosion has been removed, it'll only damage the tile it lands on."
- bugfix: "Extraction pods get sent to the jail immediately again."
- refactor: "Refactored classic_baton code."
- rscadd: "Contractor Hub. A unique store for contractors to buy items with Contractor Rep, with two Rep being given when completing a contract."
- rscadd: "Contractor pinpointer, available through the Hub. A very inaccurate pinpointer that ignores suit sensors."
- rscadd: "Call reinforcements, available through the Hub. Limited to a one-time buy for a contractor, you can purchase an agent to be sent down to help in your mission. Role is polled to ghosts."
- rscadd: "Blackout, available through the Hub. Disable station power for a small duration - an expensive, but powerful option of getting into secure areas."
- rscadd: "Fulton extraction, available through the Hub. Purchase a fulton extraction kit to help move your targets across the station for those difficult dropoffs."
- tweak: "Assigning yourself to another tablet will give you another contract set."
- rscadd: "Contractors can now reroll their contracts a small number of times."
- rscadd: "Brand new sprites! A redesign of the specialist space suit, and the kit's own unique tablet. Done by Mey Ha Zah."
- tweak: "Displays contract target jobs under their name."
- tweak: "New locations, such as maintenance, are now possible dropoff locations."
@@ -0,0 +1,5 @@
author: "Putnam3145"
delete-after: True
changes:
- balance: "Power sink objective is 10x as easy to get"
- bugfix: "Processing objectives now properly stop once won"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 KiB

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -1472,6 +1472,8 @@
#include "code\modules\antagonists\swarmer\swarmer.dm"
#include "code\modules\antagonists\swarmer\swarmer_event.dm"
#include "code\modules\antagonists\traitor\datum_traitor.dm"
#include "code\modules\antagonists\traitor\syndicate_contract.dm"
#include "code\modules\antagonists\traitor\equipment\contractor.dm"
#include "code\modules\antagonists\traitor\equipment\Malf_Modules.dm"
#include "code\modules\antagonists\traitor\IAA\internal_affairs.dm"
#include "code\modules\antagonists\valentines\heartbreaker.dm"
@@ -2483,6 +2485,7 @@
#include "code\modules\modular_computers\file_system\programs\nttransfer.dm"
#include "code\modules\modular_computers\file_system\programs\powermonitor.dm"
#include "code\modules\modular_computers\file_system\programs\sm_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\contract_uplink.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm"
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
#include "code\modules\modular_computers\hardware\_hardware.dm"
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -21
View File
File diff suppressed because one or more lines are too long
+148
View File
@@ -0,0 +1,148 @@
<link rel='ractive' href='./ntosheader.ract'>
<ntosheader/>
<ui-display>
<div style="position:relative;">
{{#if data.error}}
<div style="position:absolute; width=75%; margin:auto; padding:5px; top:2px; background-color: black; border: 1px solid #750000; text-align:center; z-index: 5000;">
<div style="color:white; font-weight: bold; font-style: italic; margin-bottom: 10px">
{{data.error}}
</div>
<div style="text-align:center; margin-bottom:3px">
<ui-button action='PRG_clear_error'>Confirm</ui-button>
</div>
</div>
{{/if}}
{{#if data.logged_in}}
{{#if data.page == "CONTRACTS"}}
<div style="position:absolute; top:2px; right:2px">
<ui-button action='PRG_contractor_hub'><div style="padding-top:6px; padding-bottom:3px"><i class="fas fa-satellite-dish fa-3x"></i></div></ui-button>
</div>
<div style="text-align:center">
<h1>Welcome Agent...</h1>
<br>
<h3>Current status: Onboard {{data.station_name}}.</h3>
</div>
<p>
We've identified potentional high-value targets that are currently
assigned to your mission area. They are believed to hold valuable information
which could be of immediate importance to our organisation.
</p>
<p>
Listed below are all of the contracts available to you. You are to bring the
specified target to the designated drop-off, and contact us via this uplink. We will send
a specialised extraction unit to put the body into.
</p>
<p>
We want targets alive - but we will sometimes pay slight amounts if they're not, you just won't
recieve the shown bonus. You can redeem your payment through this uplink in the form of raw telecrystals,
which can be put into your regular Syndicate uplink to purchase whatever you may need. We provide you with
these crystals the moment you send the target up to us, which can be collected at anytime through this system.
</p>
<p>
Targets extracted will be ransomed back to the station once their use to us is fulfilled.
You may want to be mindful of them identifying you when they come back.
We provide you with the standard contractor loadout, which will help cover your identity.
</p>
<p>
You have {{data.redeemable_tc}} TC to redeem. <ui-button action='PRG_redeem_TC'>Collect</ui-button>
</p>
{{#if data.ongoing_contract}}
<div style="text-align:center; margin-bottom:3px">
<ui-button action='PRG_call_extraction' {{#if extraction_enroute}}state="disabled"{{/if}}>Call Extraction</ui-button>
</div>
{{/if}}
<table style="text-align:center;" border="2" cellspacing="0" width="100%">
<tr>
<th>Target</th>
<th>Payment</th>
<th>Drop-Off</th>
<th></th>
</tr>
{{#each data.contracts}}
{{#if data.ongoing_contract}}
{{#if status == 2 || status == 3 || status == 4}}
<tr>
<td>
<div>{{target}}</div>
<div>({{target_rank}})</div>
</td>
<td>{{payout}} (+{{payout_bonus}}) TC</td>
<td>{{dropoff}}</td>
<td><ui-button action='PRG_contract_abort' {{#if extraction_enroute}}state="disabled"{{/if}} params='{"contract_id": "{{id}}"}'>Cancel</ui-button></td>
</tr>
{{/if}}
{{else}}
{{#if status != 5 && status != 6}}
<tr>
<td>
<div>{{target}}</div>
<div>({{target_rank}})</div>
</td>
<td>{{payout}} (+{{payout_bonus}}) TC</td>
<td>{{dropoff}}</td>
<td><ui-button action='PRG_contract-accept' params='{"contract_id": "{{id}}"}'>Accept</ui-button></td>
</tr>
{{/if}}
{{/if}}
{{/each}}
</table>
{{#if data.ongoing_contract}}
<div style="text-align:center;">
<ui-display title='Dropoff Locator'>
Current Location: {{data.current_location}}
<br>
Dropoff Location: {{data.dropoff_direction}}
</ui-display>
</div>
{{/if}}
{{else}}
<div style="position:absolute; top:2px; left:2px"><ui-button action='PRG_hub_back'><i class="fas fa-arrow-left"></i> Back</ui-button></div>
<div style="position:absolute; top:2px; right:2px">Contractor Rep: {{data.contract_rep}}</div>
<br>
<br>
<p style="text-align: center">
The items available on the Hub are available only to contractors. They are bought using Contractor Rep, with two Rep being given on the completion of a contract.
</p>
<div class="margin-top: 10px">
{{#each data.contractor_hub_items}}
{{#if limited != 0}}
<div style="margin-top:10px; border: 1px solid white">
<div style="text-align:center; margin-top:5px; margin-bottom:3px">
{{name}}{{#if cost != 0}} - {{cost}} Rep{{/if}}
</div>
<div style="text-align:center; margin-top: 10px">
<i class="fas {{item_icon}} fa-3x"></i>
</div>
<div style="text-align:center; padding:15px">
<p>{{desc}}</p>
</div>
<div style="text-align:center; margin-bottom:5px">
<ui-button action='buy_hub' params='{"item": "{{name}}", "cost": "{{cost}}"}'>{{#if limited != -1}}Purchase - {{limited}} remaining{{else}}Purchase{{/if}}</ui-button>
</div>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
{{else}}
<div style="text-align:center">
<ui-button action='PRG_login'>Assign</ui-button><br>
{{#if data.error}}
{{data.error}}
{{/if}}
</div>
{{/if}}
</div>
</ui-display>