Merge branch 'master' into digileg-runtime

This commit is contained in:
Poojawa
2018-03-17 20:16:21 -05:00
committed by GitHub
112 changed files with 1640 additions and 581 deletions

View File

@@ -8,4 +8,5 @@
#define CINEMATIC_CULT 8
#define CINEMATIC_NUKE_FAKE 9
#define CINEMATIC_NUKE_NO_CORE 10
#define CINEMATIC_NUKE_FAR 11
#define CINEMATIC_NUKE_FAR 11
#define CINEMATIC_NUKE_CLOWNOP 12

View File

@@ -110,6 +110,11 @@
#define CITADEL_MENTOR_OOC_COLOUR "#224724"
//xenobio console upgrade stuff
#define XENOBIO_UPGRADE_MONKEYS 1
#define XENOBIO_UPGRADE_SLIMEBASIC 2
#define XENOBIO_UPGRADE_SLIMEADV 4
//stamina stuff
#define STAMINA_SOFTCRIT 100 //softcrit for stamina damage. prevents standing up, prevents performing actions that cost stamina, etc, but doesn't force a rest or stop movement
#define STAMINA_CRIT 140 //crit for stamina damage. forces a rest, and stops movement until stamina goes back to stamina softcrit

View File

@@ -142,3 +142,7 @@
#define EMP_HEAVY 1
#define EMP_LIGHT 2
#define GRENADE_CLUMSY_FUMBLE 1
#define GRENADE_NONCLUMSY_FUMBLE 2
#define GRENADE_NO_FUMBLE 3

View File

@@ -86,3 +86,8 @@
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
//Component Specific Signals
//Wet floors
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.

View File

@@ -85,3 +85,16 @@
#define SUPERMATTER_DANGER 4 // Integrity < 50%
#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
//Nuclear bomb stuff
#define NUKESTATE_INTACT 5
#define NUKESTATE_UNSCREWED 4
#define NUKESTATE_PANEL_REMOVED 3
#define NUKESTATE_WELDED 2
#define NUKESTATE_CORE_EXPOSED 1
#define NUKESTATE_CORE_REMOVED 0
#define NUKE_OFF_LOCKED 0
#define NUKE_OFF_UNLOCKED 1
#define NUKE_ON_TIMING 2
#define NUKE_ON_EXPLODING 3

View File

@@ -185,15 +185,17 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
#define HAS_SENSORS 1
#define LOCKED_SENSORS 2
//Turf wet states
//Wet floor type flags. Stronger ones should be higher in number.
#define TURF_DRY 0
#define TURF_WET_WATER 1
#define TURF_WET_LUBE 2
#define TURF_WET_ICE 3
#define TURF_WET_PERMAFROST 4
#define TURF_WET_ICE 4
#define TURF_WET_PERMAFROST 8
//Maximum amount of time, (in approx. seconds.) a tile can be wet for.
#define MAXIMUM_WET_TIME 300
#define IS_WET_OPEN_TURF(O) O.GetComponent(/datum/component/wet_floor)
//Maximum amount of time, (in deciseconds) a tile can be wet for.
#define MAXIMUM_WET_TIME 3000
//unmagic-strings for types of polls
#define POLLTYPE_OPTION "OPTION"

View File

@@ -86,6 +86,7 @@
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_RESEARCH 10
#define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_WET_FLOORS 20
#define FIRE_PRIORITY_AIR 20
#define FIRE_PRIORITY_NPC 20
#define FIRE_PRIORITY_PROCESS 25

View File

@@ -1,5 +1,3 @@
#define ION_FILE "ion_laws.json"
/proc/lizard_name(gender)
if(gender == MALE)
return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"

View File

@@ -10,9 +10,8 @@
Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
*/
/mob/living/silicon/ai/DblClickOn(var/atom/A, params)
if(client.click_intercept)
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
return
if(check_click_intercept(params,A))
return
if(control_disabled || incapacitated())
return
@@ -27,9 +26,8 @@
return
next_click = world.time + 1
if(client.click_intercept)
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
return
if(check_click_intercept(params,A))
return
if(control_disabled || incapacitated())
return

View File

@@ -61,9 +61,8 @@
return
next_click = world.time + 1
if(client && client.click_intercept)
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
return
if(check_click_intercept(params,A))
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])
@@ -476,7 +475,7 @@
var/mob/living/carbon/C = usr
C.swap_hand()
else
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr.client ? usr.client.eye : usr))
params += "&catcher=1"
if(T)
T.Click(location, control, params)
@@ -496,3 +495,16 @@
else
view = 1
add_view_range(view)
/mob/proc/check_click_intercept(params,A)
//Client level intercept
if(client && client.click_intercept)
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
return TRUE
//Mob level intercept
if(click_intercept)
if(call(click_intercept, "InterceptClickOn")(src, params, A))
return TRUE
return FALSE

View File

@@ -11,9 +11,8 @@
return
next_click = world.time + 1
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
if(check_click_intercept(params,A))
return
if(stat || lockcharge || IsKnockdown() || IsStun() || IsUnconscious())
return

View File

@@ -21,6 +21,7 @@
C.parallax_layers_cached = list()
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view)
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view)
C.parallax_layers_cached += new /obj/screen/parallax_layer/planet(null, C.view)
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_3(null, C.view)
C.parallax_layers = C.parallax_layers_cached.Copy()
@@ -86,6 +87,7 @@
/datum/hud/proc/update_parallax_pref(mob/viewmob)
remove_parallax(viewmob)
create_parallax(viewmob)
update_parallax()
// This sets which way the current shuttle is moving (returns true if the shuttle has stopped moving so the caller can append their animation)
/datum/hud/proc/set_parallax_movedir(new_parallax_movedir, skip_windups)
@@ -194,18 +196,27 @@
var/obj/screen/parallax_layer/L = thing
if (L.view_sized != C.view)
L.update_o(C.view)
var/change_x = offset_x * L.speed
L.offset_x -= change_x
var/change_y = offset_y * L.speed
L.offset_y -= change_y
if(L.offset_x > 240)
L.offset_x -= 480
if(L.offset_x < -240)
L.offset_x += 480
if(L.offset_y > 240)
L.offset_y -= 480
if(L.offset_y < -240)
L.offset_y += 480
var/change_x
var/change_y
if(L.absolute)
L.offset_x = -(posobj.x - SSparallax.planet_x_offset) * L.speed
L.offset_y = -(posobj.y - SSparallax.planet_y_offset) * L.speed
else
change_x = offset_x * L.speed
L.offset_x -= change_x
change_y = offset_y * L.speed
L.offset_y -= change_y
if(L.offset_x > 240)
L.offset_x -= 480
if(L.offset_x < -240)
L.offset_x += 480
if(L.offset_y > 240)
L.offset_y -= 480
if(L.offset_y < -240)
L.offset_y += 480
if(!areaobj.parallax_movedir && C.dont_animate_parallax <= world.time && (offset_x || offset_y) && abs(offset_x) <= max(C.parallax_throttle/world.tick_lag+1,1) && abs(offset_y) <= max(C.parallax_throttle/world.tick_lag+1,1) && (round(abs(change_x)) > 1 || round(abs(change_y)) > 1))
@@ -232,6 +243,7 @@
var/offset_x = 0
var/offset_y = 0
var/view_sized
var/absolute = FALSE
blend_mode = BLEND_ADD
plane = PLANE_SPACE_PARALLAX
screen_loc = "CENTER-7,CENTER-7"
@@ -247,7 +259,7 @@
/obj/screen/parallax_layer/proc/update_o(view)
if (!view)
view = world.view
var/list/viewscales = getviewsize(view)
var/countx = CEILING((viewscales[1]/2)/(480/world.icon_size), 1)+1
var/county = CEILING((viewscales[2]/2)/(480/world.icon_size), 1)+1
@@ -278,6 +290,16 @@
speed = 1.4
layer = 3
/obj/screen/parallax_layer/planet
icon_state = "planet"
blend_mode = BLEND_OVERLAY
absolute = TRUE //Status of seperation
speed = 3
layer = 30
/obj/screen/parallax_layer/planet/update_o()
return //Shit wont move
#undef LOOP_NONE
#undef LOOP_NORMAL
#undef LOOP_REVERSE

View File

@@ -1,7 +1,6 @@
/mob/dead/observer/DblClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
if(check_click_intercept(params,A))
return
if(can_reenter_corpse && mind && mind.current)
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
@@ -18,9 +17,8 @@
update_parallax_contents()
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(client.click_intercept)
if(call(client.click_intercept,"InterceptClickOn")(src,params,A))
return
if(check_click_intercept(params,A))
return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["middle"])

View File

@@ -1,10 +1,17 @@
SUBSYSTEM_DEF(parallax)
name = "Parallax"
wait = 2
flags = SS_POST_FIRE_TIMING | SS_BACKGROUND | SS_NO_INIT
flags = SS_POST_FIRE_TIMING | SS_BACKGROUND
priority = FIRE_PRIORITY_PARALLAX
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/list/currentrun
var/planet_x_offset = 128
var/planet_y_offset = 128
/datum/controller/subsystem/parallax/Initialize(timeofday)
. = ..()
planet_y_offset = rand(100, 160)
planet_x_offset = rand(100, 160)
/datum/controller/subsystem/parallax/fire(resumed = 0)
if (!resumed)

View File

@@ -0,0 +1,5 @@
PROCESSING_SUBSYSTEM_DEF(wet_floors)
name = "Wet floors"
priority = FIRE_PRIORITY_WET_FLOORS
wait = 15
stat_tag = "WFP" //Used for logging

View File

@@ -51,7 +51,7 @@ GLOBAL_LIST_EMPTY(cinematics)
for(var/A in GLOB.cinematics)
var/datum/cinematic/C = A
if(C == src)
continue
continue
if(C.is_global || !is_global)
return //Can't play two global or local cinematics at the same time
@@ -73,7 +73,7 @@ GLOBAL_LIST_EMPTY(cinematics)
if(is_global)
M.notransform = TRUE
locked += M
//Actually play it
content()
//Cleanup
@@ -209,6 +209,17 @@ GLOBAL_LIST_EMPTY(cinematics)
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
special()
/datum/cinematic/clownop
id = CINEMATIC_NUKE_CLOWNOP
cleanup_time = 100
/datum/cinematic/clownop/content()
flick("intro_nuke",screen)
sleep(35)
cinematic_sound(sound('sound/items/airhorn.ogg'))
flick("summary_selfdes",screen) //???
special()
/* Intended usage.
Nuke.Explosion()
-> Cinematic(NUKE_BOOM,world)

View File

@@ -0,0 +1,171 @@
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor")
var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor")
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static")
var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static")
var/current_overlay
var/permanent = FALSE
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
add_wet(arglist(argslist))
else //We are being passed in a full blown component
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, permanent = FALSE)
if(!isopenturf(parent))
. = COMPONENT_INCOMPATIBLE
CRASH("Wet floor component attempted to be applied to a non open turf!")
add_wet(strength, duration_minimum, duration_add, duration_maximum)
RegisterSignal(COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(COMSIG_TURF_MAKE_DRY, .proc/dry)
if(!permanent)
START_PROCESSING(SSwet_floors, src)
if(gc())
stack_trace("Warning: Wet floor component added and immediately deleted! What a waste of time!")
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
qdel(T.GetComponent(/datum/component/slippery))
if(istype(T)) //If this is false there is so many things wrong with it.
T.cut_overlay(current_overlay)
else
stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!")
return ..()
/datum/component/wet_floor/proc/update_overlay()
var/intended
if(!istype(parent, /turf/open/floor))
intended = generic_turf_overlay
else
switch(highest_strength)
if(TURF_WET_PERMAFROST)
intended = permafrost_overlay
if(TURF_WET_ICE)
intended = ice_overlay
else
intended = water_overlay
if(current_overlay != intended)
var/turf/T = parent
T.cut_overlay(current_overlay)
T.add_overlay(intended)
current_overlay = intended
/datum/component/wet_floor/proc/AfterSlip(mob/living/L)
if(highest_strength == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/datum/component/wet_floor/proc/update_flags()
var/intensity
lube_flags = NONE
switch(highest_strength)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
else
qdel(parent.GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/datum/component/wet_floor/proc/dry(strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY)
for(var/i in time_left_list)
if(text2num(i) <= strength)
time_left_list[i] = max(0, time_left_list[i] - duration_decrease)
if(immediate)
check()
/datum/component/wet_floor/proc/max_time_left()
. = 0
for(var/i in time_left_list)
. = max(., time_left_list[i])
/datum/component/wet_floor/process()
var/turf/open/T = parent
var/decrease = 0
var/t = T.GetTemperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = (T.air.temperature - T0C) //one ds per degree.
if(T0C + 100 to INFINITY)
decrease = INFINITY
if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water!
for(var/obj/O in T.contents)
if(O.flags_2 & FROZEN_2)
O.make_unfrozen()
add_wet(TURF_WET_WATER, max_time_left())
dry(TURF_WET_ICE)
dry(ALL, FALSE, decrease)
check()
/datum/component/wet_floor/proc/update_strength()
highest_strength = 0 //Not bitflag.
for(var/i in time_left_list)
highest_strength = max(highest_strength, text2num(i))
/datum/component/wet_floor/proc/is_wet()
. = 0
for(var/i in time_left_list)
. |= text2num(i)
/datum/component/wet_floor/OnTransfer(datum/to_datum)
if(!isopenturf(to_datum))
. = COMPONENT_INCOMPATIBLE
CRASH("Wet floor component attempted to be transferred to a non open turf!")
var/turf/O = parent
O.cut_overlay(current_overlay)
var/turf/T = to_datum
T.add_overlay(current_overlay)
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST)
if(!duration_minimum || duration_minimum < 0 || !type || !(type in allowed_types))
return FALSE
var/time = 0
if(LAZYACCESS(time_left_list, "[type]"))
time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum)
else
time = min(duration_minimum, duration_maximum)
LAZYSET(time_left_list, "[type]", time)
check(TRUE)
return TRUE
/datum/component/wet_floor/proc/gc()
if(!LAZYLEN(time_left_list))
qdel(src)
return TRUE
/datum/component/wet_floor/proc/check(force_update = FALSE)
var/changed = FALSE
for(var/i in time_left_list)
if(time_left_list[i] <= 0)
time_left_list -= i
changed = TRUE
if(changed || force_update)
update_strength()
update_overlay()
update_flags()
gc()

View File

@@ -813,11 +813,6 @@
if(!mind.assigned_role)
mind.assigned_role = "Unassigned" //default
//XENO
/mob/living/carbon/alien/mind_initialize()
..()
mind.special_role = ROLE_ALIEN
//AI
/mob/living/silicon/ai/mind_initialize()
..()

View File

@@ -84,7 +84,7 @@
mood_change = -3
/datum/mood_event/brain_damage/add_effects()
var/damage_message = pick_list_replacements("BRAIN_DAMAGE_FILE", "brain_damage")
var/damage_message = pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage")
description = "<span class='warning'>Hurr durr... [damage_message]</span>\n"
/datum/mood_event/hulk //Entire duration of having the hulk mutation

View File

@@ -501,19 +501,15 @@
if(((hand % 2) == 0))
var/obj/item/bodypart/L = itemUser.newBodyPart("r_arm", FALSE, FALSE)
L.attach_limb(itemUser)
itemUser.put_in_r_hand(newRod)
itemUser.put_in_hand(newRod, hand, forced = TRUE)
else
var/obj/item/bodypart/L = itemUser.newBodyPart("l_arm", FALSE, FALSE)
L.attach_limb(itemUser)
itemUser.put_in_l_hand(newRod)
itemUser.put_in_hand(newRod, hand, forced = TRUE)
to_chat(itemUser, "<span class='notice'>Your arm suddenly grows back with the Rod of Asclepius still attached!</span>")
else
//Otherwise get rid of whatever else is in their hand and return the rod to said hand
itemUser.dropItemToGround(itemUser.get_item_for_held_index(hand))
if(((hand % 2) == 0))
itemUser.put_in_r_hand(newRod)
else
itemUser.put_in_l_hand(newRod)
itemUser.put_in_hand(newRod, hand, forced = TRUE)
to_chat(itemUser, "<span class='notice'>The Rod of Asclepius suddenly grows back out of your arm!</span>")
//Because a servant of medicines stops at nothing to help others, lets keep them on their toes and give them an additional boost.
if(itemUser.health < itemUser.maxHealth)

View File

@@ -304,6 +304,9 @@
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube)
return
//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
/mob/living/proc/get_blood_dna_list()
if(get_blood_id() != "blood")
@@ -354,9 +357,6 @@
/atom/proc/handle_fall()
return
/atom/proc/handle_slip()
return
/atom/proc/singularity_act()
return

View File

@@ -0,0 +1,59 @@
/obj/machinery/nuclearbomb/syndicate/bananium
name = "bananium fission explosive"
desc = "You probably shouldn't stick around to see if this is armed."
icon = 'icons/obj/machines/nuke.dmi'
icon_state = "bananiumbomb_base"
/obj/machinery/nuclearbomb/syndicate/bananium/update_icon()
if(deconstruction_state == NUKESTATE_INTACT)
switch(get_nuke_state())
if(NUKE_OFF_LOCKED, NUKE_OFF_UNLOCKED)
icon_state = "bananiumbomb_base"
update_icon_interior()
update_icon_lights()
if(NUKE_ON_TIMING)
cut_overlays()
icon_state = "bananiumbomb_timing"
if(NUKE_ON_EXPLODING)
cut_overlays()
icon_state = "bananiumbomb_exploding"
else
icon_state = "bananiumbomb_base"
update_icon_interior()
update_icon_lights()
/obj/machinery/nuclearbomb/syndicate/bananium/get_cinematic_type(off_station)
switch(off_station)
if(0)
return CINEMATIC_NUKE_CLOWNOP
if(1)
return CINEMATIC_NUKE_MISS
if(2)
return CINEMATIC_NUKE_FAKE //it is farther away, so just a bikehorn instead of an airhorn
return CINEMATIC_NUKE_FAKE
/obj/machinery/nuclearbomb/syndicate/bananium/really_actually_explode(off_station)
Cinematic(get_cinematic_type(off_station), world)
for(var/mob/living/carbon/human/H in GLOB.carbon_list)
var/turf/T = get_turf(H)
if(!T || T.z != z)
continue
H.Stun(10)
var/obj/item/clothing/C
if(!H.w_uniform || H.dropItemToGround(H.w_uniform))
C = new /obj/item/clothing/under/rank/clown(H)
C.flags_1 |= NODROP_1 //mwahaha
H.equip_to_slot_or_del(C, slot_w_uniform)
if(!H.shoes || H.dropItemToGround(H.shoes))
C = new /obj/item/clothing/shoes/clown_shoes(H)
C.flags_1 |= NODROP_1
H.equip_to_slot_or_del(C, slot_shoes)
if(!H.wear_mask || H.dropItemToGround(H.wear_mask))
C = new /obj/item/clothing/mask/gas/clown_hat(H)
C.flags_1 |= NODROP_1
H.equip_to_slot_or_del(C, slot_wear_mask)
H.dna.add_mutation(CLOWNMUT)
H.gain_trauma(/datum/brain_trauma/mild/phobia, TRAUMA_RESILIENCE_LOBOTOMY, "clowns") //MWA HA HA

View File

@@ -0,0 +1,66 @@
/datum/game_mode/nuclear/clown_ops
name = "clown ops"
config_tag = "clownops"
announce_span = "danger"
announce_text = "Clown empire forces are approaching the station in an attempt to HONK it!\n\
<span class='danger'>Operatives</span>: Secure the nuclear authentication disk and use your bananium fission explosive to HONK the station.\n\
<span class='notice'>Crew</span>: Defend the nuclear authentication disk and ensure that it leaves with you on the emergency shuttle."
operative_antag_datum_type = /datum/antagonist/nukeop/clownop
leader_antag_datum_type = /datum/antagonist/nukeop/leader/clownop
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/nuclear/clown_ops/pre_setup()
. = ..()
if(.)
for(var/obj/machinery/nuclearbomb/syndicate/S in GLOB.nuke_list)
var/turf/T = get_turf(S)
if(T)
qdel(S)
new /obj/machinery/nuclearbomb/syndicate/bananium(T)
for(var/V in pre_nukeops)
var/datum/mind/the_op = V
the_op.assigned_role = "Clown Operative"
the_op.special_role = "Clown Operative"
/datum/game_mode/nuclear/clown_ops/generate_report()
return "One of Central Command's trading routes was recently disrupted by a raid carried out by the Gorlex Marauders. They seemed to only be after one ship - a highly-sensitive \
transport containing a bananium fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \
can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders."
/datum/outfit/syndicate/clownop
name = "Clown Operative - Basic"
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/clown_shoes/combat
mask = /obj/item/clothing/mask/gas/clown_hat
gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack/clown
ears = /obj/item/device/radio/headset/syndicate/alt
l_pocket = /obj/item/pinpointer/nuke/syndicate
r_pocket = /obj/item/bikehorn
id = /obj/item/card/id/syndicate
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/kitchen/knife/combat/survival,
/obj/item/reagent_containers/spray/waterflower/lube)
implants = list(/obj/item/implant/sad_trombone)
uplink_type = /obj/item/device/radio/uplink/clownop
/datum/outfit/syndicate/clownop/no_crystals
tc = 0
/datum/outfit/syndicate/clownop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
if(visualsOnly)
return
H.dna.add_mutation(CLOWNMUT)
/datum/outfit/syndicate/clownop/leader
name = "Clown Operative Leader - Basic"
id = /obj/item/card/id/syndicate/nuke_leader
r_hand = /obj/item/device/nuclear_challenge/clownops
command_radio = TRUE

View File

@@ -0,0 +1,298 @@
/obj/item/reagent_containers/spray/waterflower/lube
name = "water flower"
desc = "A seemingly innocent sunflower...with a twist. A <i>slippery</i> twist."
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "sunflower"
item_state = "sunflower"
amount_per_transfer_from_this = 3
spray_range = 1
stream_range = 1
volume = 30
list_reagents = list("lube" = 30)
//COMBAT CLOWN SHOES
//Clown shoes with combat stats and noslip. Of course they still squeek.
/obj/item/clothing/shoes/clown_shoes/combat
name = "combat clown shoes"
desc = "advanced clown shoes that protect the wearer and render them nearly immune to slipping on their own peels. They also squeek at 100% capacity."
flags_1 = NOSLIP_1
slowdown = SHOES_SLOWDOWN
armor = list("melee" = 25, "bullet" = 25, "laser" = 25, "energy" = 25, "bomb" = 50, "bio" = 10, "rad" = 0, "fire" = 70, "acid" = 50)
strip_delay = 70
resistance_flags = NONE
permeability_coefficient = 0.05
pockets = /obj/item/storage/internal/pocket/shoes
//The super annoying version
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat
name = "mk-honk combat shoes"
desc = "The culmination of years of clown combat research, these shoes leave a trail of chaos in their wake. They will slowly recharge themselves over time, or can be manually charged with bananium."
slowdown = SHOES_SLOWDOWN
armor = list("melee" = 25, "bullet" = 25, "laser" = 25, "energy" = 25, "bomb" = 50, "bio" = 10, "rad" = 0, "fire" = 70, "acid" = 50)
strip_delay = 70
resistance_flags = NONE
permeability_coefficient = 0.05
pockets = /obj/item/storage/internal/pocket/shoes
always_noslip = TRUE
var/max_recharge = 3000 //30 peels worth
var/recharge_rate = 34 //about 1/3 of a peel per tick
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/Initialize()
. = ..()
GET_COMPONENT(bananium, /datum/component/material_container)
bananium.insert_amount(max_recharge, MAT_BANANIUM)
START_PROCESSING(SSobj, src)
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/process()
GET_COMPONENT(bananium, /datum/component/material_container)
var/bananium_amount = bananium.amount(MAT_BANANIUM)
if(bananium_amount < max_recharge)
bananium.insert_amount(min(recharge_rate, max_recharge - bananium_amount), MAT_BANANIUM)
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/attack_self(mob/user)
ui_action_click(user)
//BANANIUM SWORD
/obj/item/melee/transforming/energy/sword/bananium
name = "bananium sword"
desc = "An elegant weapon, for a more civilized age."
force = 0
throwforce = 0
force_on = 0
throwforce_on = 0
hitsound = null
attack_verb_on = list("slipped")
clumsy_check = FALSE
sharpness = IS_BLUNT
item_color = "yellow"
heat = 0
light_color = "#ffff00"
var/next_trombone_allowed = 0
/obj/item/melee/transforming/energy/sword/bananium/Initialize()
. = ..()
AddComponent(/datum/component/slippery, 60, GALOSHES_DONT_HELP)
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.enabled = active
/obj/item/melee/transforming/energy/sword/bananium/attack(mob/living/M, mob/living/user)
..()
if(active)
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.Slip(M)
/obj/item/melee/transforming/energy/sword/bananium/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
if(active)
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.Slip(hit_atom)
/obj/item/melee/transforming/energy/sword/bananium/attackby(obj/item/I, mob/living/user, params)
if((world.time > next_trombone_allowed) && istype(I, /obj/item/melee/transforming/energy/sword/bananium))
next_trombone_allowed = world.time + 50
to_chat(user, "You slap the two swords together. Sadly, they do not seem to fit.")
playsound(src, 'sound/misc/sadtrombone.ogg', 50)
return TRUE
return ..()
/obj/item/melee/transforming/energy/sword/bananium/transform_weapon(mob/living/user, supress_message_text)
..()
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.enabled = active
/obj/item/melee/transforming/energy/sword/bananium/ignition_effect(atom/A, mob/user)
return ""
/obj/item/melee/transforming/energy/sword/bananium/suicide_act(mob/user)
if(!active)
transform_weapon(user, TRUE)
user.visible_message("<span class='suicide'>[user] is [pick("slitting [user.p_their()] stomach open with", "falling on")] [src]! It looks like [user.p_theyre()] trying to commit seppuku, but the blade slips off of them harmlessly!</span>")
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.Slip(user)
return SHAME
//BANANIUM SHIELD
/obj/item/shield/energy/bananium
name = "bananium energy shield"
desc = "A shield that stops most melee attacks, protects user from almost all energy projectiles, and can be thrown to slip opponents."
throw_speed = 1
clumsy_check = 0
base_icon_state = "bananaeshield"
force = 0
throwforce = 0
throw_range = 5
on_force = 0
on_throwforce = 0
on_throw_speed = 1
/obj/item/shield/energy/bananium/Initialize()
. = ..()
AddComponent(/datum/component/slippery, 60, GALOSHES_DONT_HELP)
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.enabled = active
/obj/item/shield/energy/bananium/attack_self(mob/living/carbon/human/user)
..()
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.enabled = active
/obj/item/shield/energy/bananium/throw_at(atom/target, range, speed, mob/thrower, spin=1)
if(active)
if(iscarbon(thrower))
var/mob/living/carbon/C = thrower
C.throw_mode_on() //so they can catch it on the return.
return ..()
/obj/item/shield/energy/bananium/throw_impact(atom/hit_atom)
if(active)
var/caught = hit_atom.hitby(src, 0, 0)
if(iscarbon(hit_atom) && !caught)//if they are a carbon and they didn't catch it
GET_COMPONENT(slipper, /datum/component/slippery)
slipper.Slip(hit_atom)
if(thrownby && !caught)
throw_at(thrownby, throw_range+2, throw_speed, null, 1)
else
return ..()
//BOMBANANA
/obj/item/reagent_containers/food/snacks/grown/banana/bombanana
trash = /obj/item/grown/bananapeel/bombanana
bitesize = 1
customfoodfilling = FALSE
seed = null
tastes = list("explosives" = 10)
list_reagents = list("vitamin" = 1)
/obj/item/grown/bananapeel/bombanana
desc = "A peel from a banana. Why is it beeping?"
seed = null
var/det_time = 50
var/obj/item/grenade/syndieminibomb/bomb
/obj/item/grown/bananapeel/bombanana/Initialize()
. = ..()
AddComponent(/datum/component/slippery, det_time)
bomb = new /obj/item/grenade/syndieminibomb(src)
bomb.det_time = det_time
if(iscarbon(loc))
to_chat(loc, "[src] begins to beep.")
var/mob/living/carbon/C = loc
C.throw_mode_on()
bomb.preprime(loc, null, FALSE)
/obj/item/grown/bananapeel/bombanana/Destroy()
. = ..()
QDEL_NULL(bomb)
/obj/item/grown/bananapeel/bombanana/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is deliberately slipping on the [src.name]! It looks like \he's trying to commit suicide.</span>")
playsound(loc, 'sound/misc/slip.ogg', 50, 1, -1)
bomb.preprime(user, 0, FALSE)
return (BRUTELOSS)
//TEARSTACHE GRENADE
/obj/item/grenade/chem_grenade/teargas/moustache
name = "tear-stache grenade"
desc = "A handsomely-attired teargas grenade."
icon_state = "moustacheg"
clumsy_check = GRENADE_NONCLUMSY_FUMBLE
/obj/item/grenade/chem_grenade/teargas/moustache/prime()
var/myloc = get_turf(src)
. = ..()
for(var/mob/living/carbon/M in view(6, myloc))
if(!istype(M.wear_mask, /obj/item/clothing/mask/gas/clown_hat) && !istype(M.wear_mask, /obj/item/clothing/mask/gas/mime) )
if(!M.wear_mask || M.dropItemToGround(M.wear_mask))
var/obj/item/clothing/mask/fakemoustache/sticky/the_stash = new /obj/item/clothing/mask/fakemoustache/sticky()
M.equip_to_slot_or_del(the_stash, slot_wear_mask, TRUE, TRUE, TRUE, TRUE)
/obj/item/clothing/mask/fakemoustache/sticky
var/unstick_time = 600
/obj/item/clothing/mask/fakemoustache/sticky/Initialize()
. = ..()
flags_1 |= NODROP_1
addtimer(CALLBACK(src, .proc/unstick), unstick_time)
/obj/item/clothing/mask/fakemoustache/sticky/proc/unstick()
flags_1 &= ~NODROP_1
//DARK H.O.N.K. AND CLOWN MECH WEAPONS
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana
name = "bombanana mortar"
desc = "Equipment for clown exosuits. Launches exploding banana peels."
icon_state = "mecha_bananamrtr"
projectile = /obj/item/grown/bananapeel/bombanana
projectiles = 8
projectile_energy_cost = 1000
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana/can_attach(obj/mecha/combat/honker/M)
if(..())
if(istype(M))
return TRUE
return FALSE
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache
name = "\improper HONKeR-6 grenade launcher"
desc = "A weapon for combat exosuits. Launches primed tear-stache grenades."
icon_state = "mecha_grenadelnchr"
projectile = /obj/item/grenade/chem_grenade/teargas/moustache
fire_sound = 'sound/weapons/grenadelaunch.ogg'
projectiles = 6
missile_speed = 1.5
projectile_energy_cost = 800
equip_cooldown = 60
det_time = 20
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache/can_attach(obj/mecha/combat/honker/M)
if(..())
if(istype(M))
return TRUE
return FALSE
/obj/mecha/combat/honker/dark
desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. This one has been painted black for maximum fun. HONK!"
name = "\improper Dark H.O.N.K"
icon_state = "darkhonker"
max_integrity = 300
deflect_chance = 15
armor = list("melee" = 40, "bullet" = 40, "laser" = 50, "energy" = 35, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
max_temperature = 35000
operation_req_access = list(ACCESS_SYNDICATE)
wreckage = /obj/structure/mecha_wreckage/honker/dark
max_equip = 3
/obj/mecha/combat/honker/dark/GrantActions(mob/living/user, human_occupant = 0)
..()
thrusters_action.Grant(user, src)
/obj/mecha/combat/honker/dark/RemoveActions(mob/living/user, human_occupant = 0)
..()
thrusters_action.Remove(user)
/obj/mecha/combat/honker/dark/add_cell(obj/item/stock_parts/cell/C)
if(C)
C.forceMove(src)
cell = C
return
cell = new /obj/item/stock_parts/cell/hyper(src)
/obj/mecha/combat/honker/dark/loaded/Initialize()
. = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/honker()
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/bombanana()//Needed more offensive weapons.
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/tearstache()//The mousetrap mortar was not up-to-snuff.
ME.attach(src)
/obj/structure/mecha_wreckage/honker/dark
name = "\improper Dark H.O.N.K wreckage"
icon_state = "darkhonker-broken"

View File

@@ -19,6 +19,9 @@
var/datum/team/nuclear/nuke_team
var/operative_antag_datum_type = /datum/antagonist/nukeop
var/leader_antag_datum_type = /datum/antagonist/nukeop/leader
/datum/game_mode/nuclear/pre_setup()
var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
if(n_agents >= required_enemies)
@@ -37,12 +40,12 @@
/datum/game_mode/nuclear/post_setup()
//Assign leader
var/datum/mind/leader_mind = pre_nukeops[1]
var/datum/antagonist/nukeop/L = leader_mind.add_antag_datum(/datum/antagonist/nukeop/leader)
var/datum/antagonist/nukeop/L = leader_mind.add_antag_datum(leader_antag_datum_type)
nuke_team = L.nuke_team
//Assign the remaining operatives
for(var/i = 2 to pre_nukeops.len)
var/datum/mind/nuke_mind = pre_nukeops[i]
nuke_mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
nuke_mind.add_antag_datum(operative_antag_datum_type)
return ..()
/datum/game_mode/nuclear/OnNukeExplosion(off_station)
@@ -131,6 +134,7 @@
var/tc = 25
var/command_radio = FALSE
var/uplink_type = /obj/item/device/radio/uplink/nuclear
/datum/outfit/syndicate/leader
@@ -150,7 +154,7 @@
R.command = TRUE
if(tc)
var/obj/item/device/radio/uplink/nuclear/U = new(H, H.key, tc)
var/obj/item/device/radio/uplink/U = new uplink_type(H, H.key, tc)
H.equip_to_slot_or_del(U, slot_in_backpack)
var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)

View File

@@ -76,6 +76,11 @@
var/wall_turret_direction //The turret will try to shoot from a turf in that direction when in a wall
var/manual_control = FALSE //
var/datum/action/turret_quit/quit_action
var/datum/action/turret_toggle/toggle_action
var/mob/remote_controller
/obj/machinery/porta_turret/Initialize()
. = ..()
if(!base)
@@ -154,6 +159,7 @@
cp = null
QDEL_NULL(stored_gun)
QDEL_NULL(spark_system)
remove_control()
return ..()
@@ -179,6 +185,14 @@
dat += "Neutralize All Non-Security and Non-Command Personnel: <A href='?src=[REF(src)];operation=shootall'>[stun_all ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Unidentified Life Signs: <A href='?src=[REF(src)];operation=checkxenos'>[check_anomalies ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Non-Loyalty Implanted Personnel: <A href='?src=[REF(src)];operation=checkloyal'>[shoot_unloyal ? "Yes" : "No"]</A><BR>"
if(issilicon(user))
if(!manual_control)
var/mob/living/silicon/S = user
if(S.hack_software)
dat += "Assume direct control : <a href='?src=[REF(src)];operation=manual'>Manual Control</a><br>"
else
dat += "Warning! Remote control protocol enabled.<br>"
var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300)
popup.set_content(dat)
@@ -212,6 +226,9 @@
check_anomalies = !check_anomalies
if("checkloyal")
shoot_unloyal = !shoot_unloyal
if("manual")
if(issilicon(usr) && !manual_control)
give_control(usr)
interact(usr)
/obj/machinery/porta_turret/power_change()
@@ -359,6 +376,8 @@
popDown()
return
if(manual_control)
return
var/list/targets = list()
var/static/things_to_scan = typecacheof(list(/mob/living, /obj/mecha))
@@ -566,6 +585,66 @@
src.mode = mode
power_change()
/datum/action/turret_toggle
name = "Toggle Mode"
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_cycle_equip_off"
/datum/action/turret_toggle/Trigger()
var/obj/machinery/porta_turret/P = target
if(!istype(P))
return
P.setState(P.on,!P.mode)
/datum/action/turret_quit
name = "Release Control"
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_eject"
/datum/action/turret_quit/Trigger()
var/obj/machinery/porta_turret/P = target
if(!istype(P))
return
P.remove_control(owner)
/obj/machinery/porta_turret/proc/give_control(mob/A)
if(manual_control)
return FALSE
remote_controller = A
if(!quit_action)
quit_action = new(src)
quit_action.Grant(remote_controller)
if(!toggle_action)
toggle_action = new(src)
toggle_action.Grant(remote_controller)
remote_controller.reset_perspective(src)
remote_controller.click_intercept = src
manual_control = TRUE
always_up = TRUE
popUp()
return TRUE
/obj/machinery/porta_turret/proc/remove_control()
if(!manual_control)
return FALSE
if(remote_controller)
quit_action.Remove(remote_controller)
toggle_action.Remove(remote_controller)
remote_controller.click_intercept = null
remote_controller.reset_perspective()
always_up = initial(always_up)
manual_control = FALSE
remote_controller = null
return TRUE
/obj/machinery/porta_turret/proc/InterceptClickOn(mob/living/caller, params, atom/A)
if(!manual_control)
return FALSE
add_logs(caller,A,"fired with manual turret control at")
target(A)
return TRUE
/obj/machinery/porta_turret/syndicate
installation = null
always_up = 1

View File

@@ -11,7 +11,7 @@
var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff)
var/energy_drain = 0
var/obj/mecha/chassis = null
var/range = MELEE //bitflags
var/range = MELEE //bitFflags
var/salvageable = 1
var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates
var/pacifist_safe = TRUE //Controls if equipment can be used to attack by a pacifist.
@@ -94,9 +94,16 @@
chassis.use_power(energy_drain)
. = do_after(chassis.occupant, equip_cooldown, target=target)
set_ready_state(1)
if(!chassis || chassis.loc != C || src != chassis.selected)
if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir))
return 0
/obj/item/mecha_parts/mecha_equipment/proc/do_after_mecha(atom/target, delay)
if(!chassis)
return
var/C = chassis.loc
. = do_after(chassis.occupant, delay, target=target)
if(!chassis || chassis.loc != C || src != chassis.selected || !(get_dir(chassis, target)&chassis.dir))
return 0
/obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M)
if(M.equipment.len<M.max_equip)

View File

@@ -1,6 +1,9 @@
// Drill, Diamond drill, Mining scanner
#define DRILL_BASIC 1
#define DRILL_HARDENED 2
/obj/item/mecha_parts/mecha_equipment/drill
name = "exosuit drill"
@@ -10,6 +13,8 @@
energy_drain = 10
force = 15
pacifist_safe = FALSE
var/drill_delay = 7
var/drill_level = DRILL_BASIC
/obj/item/mecha_parts/mecha_equipment/drill/Initialize()
. = ..()
@@ -29,27 +34,39 @@
"<span class='italics'>You hear drilling.</span>")
if(do_after_cooldown(target))
set_ready_state(FALSE)
log_message("Started drilling [target]")
if(isturf(target))
var/turf/T = target
T.drill_act(src)
else
log_message("Drilled through [target]")
set_ready_state(TRUE)
return
while(do_after_mecha(target, drill_delay))
if(isliving(target))
if(istype(src , /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill))
drill_mob(target, chassis.occupant, 120)
else
drill_mob(target, chassis.occupant)
drill_mob(target, chassis.occupant)
playsound(src,'sound/weapons/drill.ogg',40,1)
else if(isobj(target))
var/obj/O = target
O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target))
playsound(src,'sound/weapons/drill.ogg',40,1)
else
target.ex_act(EXPLODE_HEAVY)
set_ready_state(TRUE)
return
set_ready_state(TRUE)
/turf/proc/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill)
return
/turf/closed/wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill)
if(drill.do_after_mecha(src, 60 / drill.drill_level))
drill.log_message("Drilled through [src]")
dismantle_wall(TRUE, FALSE)
/turf/closed/wall/r_wall/drill_act(obj/item/mecha_parts/mecha_equipment/drill/drill)
if(istype(drill, /obj/item/mecha_parts/mecha_equipment/drill/diamonddrill))
if(drill.do_after_cooldown(src))//To slow down how fast mechs can drill through the station
if(drill.drill_level >= DRILL_HARDENED)
if(drill.do_after_mecha(src, 120 / drill.drill_level))
drill.log_message("Drilled through [src]")
ex_act(EXPLODE_LIGHT)
dismantle_wall(TRUE, FALSE)
else
drill.occupant_message("<span class='danger'>[src] is too durable to drill through.</span>")
@@ -91,30 +108,40 @@
GET_COMPONENT_FROM(butchering, /datum/component/butchering, src)
butchering.butchering_enabled = FALSE
/obj/item/mecha_parts/mecha_equipment/drill/proc/drill_mob(mob/living/target, mob/user, var/drill_damage=80)
target.visible_message("<span class='danger'>[chassis] drills [target] with [src].</span>", \
"<span class='userdanger'>[chassis] drills [target] with [src].</span>")
add_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
if(target.stat == DEAD)
/obj/item/mecha_parts/mecha_equipment/drill/proc/drill_mob(mob/living/target, mob/user)
target.visible_message("<span class='danger'>[chassis] is drilling [target] with [src]!</span>", \
"<span class='userdanger'>[chassis] is drilling you with [src]!</span>")
add_logs(user, target, "drilled", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
if(target.stat == DEAD && target.getBruteLoss() >= 200)
add_logs(user, target, "gibbed", name)
if(target.butcher_results.len || target.guaranteed_butcher_results.len)
if(LAZYLEN(target.butcher_results) || LAZYLEN(target.guaranteed_butcher_results))
GET_COMPONENT_FROM(butchering, /datum/component/butchering, src)
butchering.Butcher(chassis, target)
else
target.gib()
else
target.take_bodypart_damage(drill_damage)
//drill makes a hole
var/obj/item/bodypart/target_part = target.get_bodypart(ran_zone("chest"))
target.apply_damage(10, BRUTE, "chest", target.run_armor_check(target_part, "melee"))
if(target)
target.Unconscious(200)
target.updatehealth()
//blood splatters
var/splatter_dir = get_dir(chassis, target)
if(isalien(target))
new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target.drop_location(), splatter_dir)
else
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir)
//organs go everywhere
if(target_part && prob(10 * drill_level))
target_part.dismember(BRUTE)
/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill
name = "diamond-tipped exosuit drill"
desc = "Equipment for engineering and combat exosuits. This is an upgraded version of the drill that'll pierce the heavens!"
icon_state = "mecha_diamond_drill"
equip_cooldown = 10
drill_delay = 4
drill_level = DRILL_HARDENED
force = 15
@@ -140,3 +167,6 @@
return
scanning_time = world.time + equip_cooldown
mineral_scan_pulse(get_turf(src))
#undef DRILL_BASIC
#undef DRILL_HARDENED

View File

@@ -138,16 +138,16 @@
return ..()
/obj/effect/portal/attack_ghost(mob/dead/observer/O)
if(!teleport(O))
if(!teleport(O, TRUE))
return ..()
/obj/effect/portal/proc/teleport(atom/movable/M)
if(!istype(M) || istype(M, /obj/effect) || (ismecha(M) && !mech_sized) || (!isobj(M) && !ismob(M))) //Things that shouldn't teleport.
/obj/effect/portal/proc/teleport(atom/movable/M, force = FALSE)
if(!force && (!istype(M) || istype(M, /obj/effect) || (ismecha(M) && !mech_sized) || (!isobj(M) && !ismob(M)))) //Things that shouldn't teleport.
return
var/turf/real_target = get_link_target_turf()
if(!istype(real_target))
return FALSE
if(!ismecha(M) && !istype(M, /obj/item/projectile) && M.anchored && !allow_anchored)
if(!force && (!ismecha(M) && !istype(M, /obj/item/projectile) && M.anchored && !allow_anchored))
return
if(ismegafauna(M))
message_admins("[M] has used a portal at [ADMIN_COORDJMP(src)] made by [usr].")

View File

@@ -599,8 +599,8 @@
/obj/item/stock_parts/capacitor = 6)
/obj/item/circuitboard/machine/chem_dispenser
name = "Portable Chem Dispenser (Machine Board)"
build_path = /obj/machinery/chem_dispenser/constructable
name = "Chem Dispenser (Machine Board)"
build_path = /obj/machinery/chem_dispenser
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/capacitor = 1,

View File

@@ -202,6 +202,6 @@
var/turf/T = get_turf(loc)
if(isopenturf(T))
var/turf/open/theturf = T
theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "<span class='info'>You quietly empty out \the [src] using its release valve.</span>")

View File

@@ -16,6 +16,7 @@
var/active = 0
var/det_time = 50
var/display_timer = 1
var/clumsy_check = GRENADE_CLUMSY_FUMBLE
/obj/item/grenade/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] primes [src], then eats it! It looks like [user.p_theyre()] trying to commit suicide!</span>")
@@ -32,8 +33,14 @@
qdel(src)
/obj/item/grenade/proc/clown_check(mob/living/carbon/human/user)
if(user.has_trait(TRAIT_CLUMSY) && prob(50))
to_chat(user, "<span class='warning'>Huh? How does this thing work?</span>")
var/clumsy = user.has_trait(TRAIT_CLUMSY)
if(clumsy && (clumsy_check == GRENADE_CLUMSY_FUMBLE))
if(prob(50))
to_chat(user, "<span class='warning'>Huh? How does this thing work?</span>")
preprime(user, 5, FALSE)
return FALSE
else if(!clumsy && (clumsy_check == GRENADE_NONCLUMSY_FUMBLE))
to_chat(user, "<span class='warning'>You pull the pin on [src]. Attached to it is a pink ribbon that says, \"<span class='clown'>HONK</span>\"</span>")
preprime(user, 5, FALSE)
return FALSE
return TRUE

View File

@@ -43,8 +43,7 @@
for(var/turf/T in view(freeze_range,loc))
if(isfloorturf(T))
var/turf/open/floor/F = T
F.wet = TURF_WET_PERMAFROST
addtimer(CALLBACK(F, /turf/open/floor.proc/MakeDry, TURF_WET_PERMAFROST), rand(3000, 3100))
F.MakeSlippery(TURF_WET_PERMAFROST, 6 MINUTES)
for(var/mob/living/carbon/L in T)
L.adjustStaminaLoss(stamina_damage)
L.adjust_bodytemperature(-230)

View File

@@ -17,6 +17,8 @@
return ..()
/obj/item/melee/transforming/energy/suicide_act(mob/user)
if(!active)
transform_weapon(user, TRUE)
user.visible_message("<span class='suicide'>[user] is [pick("slitting [user.p_their()] stomach open with", "falling on")] [src]! It looks like [user.p_theyre()] trying to commit seppuku!</span>")
return (BRUTELOSS|FIRELOSS)

View File

@@ -1,4 +1,5 @@
/obj/item/melee/transforming
sharpness = IS_SHARP
var/active = FALSE
var/force_on = 30 //force when active
var/faction_bonus_force = 0 //Bonus force dealt against certain factions
@@ -8,10 +9,10 @@
var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
var/list/attack_verb_off = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
w_class = WEIGHT_CLASS_SMALL
sharpness = IS_SHARP
var/bonus_active = FALSE //If the faction damage bonus is active
var/list/nemesis_factions //Any mob with a faction that exists in this list will take bonus damage/effects
var/w_class_on = WEIGHT_CLASS_BULKY
var/clumsy_check = TRUE
/obj/item/melee/transforming/Initialize()
. = ..()
@@ -81,6 +82,6 @@
to_chat(user, "<span class='notice'>[src] [active ? "is now active":"can now be concealed"].</span>")
/obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user)
if(user.has_trait(TRAIT_CLUMSY) && prob(50))
if(clumsy_check && user.has_trait(TRAIT_CLUMSY) && prob(50))
to_chat(user, "<span class='warning'>You accidentally cut yourself with [src], like a doofus!</span>")
user.take_bodypart_damage(5,5)

View File

@@ -60,16 +60,24 @@
name = "energy combat shield"
desc = "A shield that reflects almost all energy projectiles, but is useless against physical attacks. It can be retracted, expanded, and stored anywhere."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "eshield0" // eshield1 for expanded
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
attack_verb = list("shoved", "bashed")
throw_range = 5
force = 3
throwforce = 3
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
attack_verb = list("shoved", "bashed")
var/base_icon_state = "eshield" // [base_icon_state]1 for expanded, [base_icon_state]0 for contracted
var/on_force = 10
var/on_throwforce = 8
var/on_throw_speed = 2
var/active = 0
var/clumsy_check = TRUE
/obj/item/shield/energy/Initialize()
. = ..()
icon_state = "[base_icon_state]0"
/obj/item/shield/energy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
@@ -78,23 +86,23 @@
return (active)
/obj/item/shield/energy/attack_self(mob/living/carbon/human/user)
if(user.has_trait(TRAIT_CLUMSY) && prob(50))
if(clumsy_check && user.has_trait(TRAIT_CLUMSY) && prob(50))
to_chat(user, "<span class='warning'>You beat yourself in the head with [src].</span>")
user.take_bodypart_damage(5)
active = !active
icon_state = "eshield[active]"
icon_state = "[base_icon_state][active]"
if(active)
force = 10
throwforce = 8
throw_speed = 2
force = on_force
throwforce = on_throwforce
throw_speed = on_throw_speed
w_class = WEIGHT_CLASS_BULKY
playsound(user, 'sound/weapons/saberon.ogg', 35, 1)
to_chat(user, "<span class='notice'>[src] is now active.</span>")
else
force = 3
throwforce = 3
throw_speed = 3
force = initial(force)
throwforce = initial(throwforce)
throw_speed = initial(throw_speed)
w_class = WEIGHT_CLASS_TINY
playsound(user, 'sound/weapons/saberoff.ogg', 35, 1)
to_chat(user, "<span class='notice'>[src] can now be concealed.</span>")

View File

@@ -227,6 +227,14 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
tesla_zap(src, 3, power_bounced)
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
//The surgeon general warns that being buckled to certain objects recieving powerful shocks is greatly hazardous to your health
//Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
/obj/proc/tesla_buckle_check(var/strength)
if(has_buckled_mobs())
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
buckled_mob.electrocute_act((CLAMP(round(strength/400), 10, 90) + rand(-5, 5)), src, tesla_shock = 1)
/obj/proc/reset_shocked()
obj_flags &= ~BEING_SHOCKED

View File

@@ -7,11 +7,7 @@
anchored = TRUE
icon = 'icons/turf/walls/wall.dmi'
icon_state = "wall"
var/mineral = /obj/item/stack/sheet/metal
var/mineral_amount = 2
var/walltype = /turf/closed/wall
var/girder_type = /obj/structure/girder/displaced
var/opening = FALSE
layer = CLOSED_TURF_LAYER
density = TRUE
opacity = 1
max_integrity = 100
@@ -28,6 +24,11 @@
smooth = SMOOTH_TRUE
can_be_unanchored = FALSE
CanAtmosPass = ATMOS_PASS_DENSITY
var/mineral = /obj/item/stack/sheet/metal
var/mineral_amount = 2
var/walltype = /turf/closed/wall
var/girder_type = /obj/structure/girder/displaced
var/opening = FALSE
/obj/structure/falsewall/Initialize()
. = ..()

View File

@@ -534,9 +534,6 @@
new/obj/structure/showcase/machinery/oldpod/used(drop_location())
return ..()
#define PIRATE_NAMES_FILE "pirates.json"
/obj/effect/mob_spawn/human/pirate
name = "space pirate sleeper"
desc = "A cryo sleeper smelling faintly of rum."

View File

@@ -60,7 +60,7 @@
attack_hand(user)
/obj/structure/table/attack_hand(mob/living/user)
if(user.pulling && isliving(user.pulling))
if(Adjacent(user) && user.pulling && isliving(user.pulling))
var/mob/living/pushed_mob = user.pulling
if(pushed_mob.buckled)
to_chat(user, "<span class='warning'>[pushed_mob] is buckled to [pushed_mob.buckled]!</span>")
@@ -81,6 +81,9 @@
else
..()
/obj/structure/table/attack_tk()
return FALSE
/obj/structure/table/CanPass(atom/movable/mover, turf/target)
if(istype(mover) && (mover.pass_flags & PASSTABLE))
return 1

View File

@@ -247,7 +247,7 @@
soundloop.stop()
if(isopenturf(loc))
var/turf/open/tile = loc
tile.MakeSlippery(TURF_WET_WATER, min_wet_time = 5, wet_time_to_add = 1)
tile.MakeSlippery(TURF_WET_WATER, min_wet_time = 5 SECONDS, wet_time_to_add = 1 SECONDS)
/obj/machinery/shower/attackby(obj/item/I, mob/user, params)

View File

@@ -1,12 +1,16 @@
/turf/open
var/slowdown = 0 //negative for faster, positive for slower
var/wet = 0
var/wet_time = 0 // Time in seconds that this floor will be wet for.
var/mutable_appearance/wet_overlay
var/postdig_icon_change = FALSE
var/postdig_icon
var/list/archdrops
var/wet
/turf/open/Initialize()
. = ..()
if(wet)
AddComponent(/datum/component/wet_floor, wet, INFINITY, 0, INFINITY, TRUE)
/turf/open/indestructible
name = "floor"
@@ -164,11 +168,11 @@
for(var/mob/living/L in contents)
if(L.bodytemperature <= 50)
L.apply_status_effect(/datum/status_effect/freon)
MakeSlippery(TURF_WET_PERMAFROST, 5)
MakeSlippery(TURF_WET_PERMAFROST, 50)
return 1
/turf/open/proc/water_vapor_gas_act()
MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
MakeSlippery(TURF_WET_WATER, min_wet_time = 100, wet_time_to_add = 50)
for(var/mob/living/simple_animal/slime/M in src)
M.apply_water()
@@ -177,7 +181,7 @@
for(var/obj/effect/O in src)
if(is_cleanable(O))
qdel(O)
return 1
return TRUE
/turf/open/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube)
if(C.movement_type & FLYING)
@@ -224,132 +228,23 @@
/turf/open/copyTurf(turf/T)
. = ..()
if(. && isopenturf(T) && wet_time)
var/turf/open/O = T
O.MakeSlippery(wet_setting = wet, wet_time_to_add = wet_time) //we're copied, copy how wet we are also
if(. && isopenturf(T))
GET_COMPONENT(slip, /datum/component/wet_floor)
if(slip)
var/datum/component/wet_floor/WF = T.AddComponent(/datum/component/wet_floor)
WF.InheritComponent(slip)
/turf/open/proc/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0) // 1 = Water, 2 = Lube, 3 = Ice, 4 = Permafrost, 5 = Slide
wet_time = max(wet_time+wet_time_to_add, min_wet_time)
if(wet >= wet_setting)
return
wet = wet_setting
UpdateSlip()
if(wet_setting != TURF_DRY)
if(wet_overlay)
cut_overlay(wet_overlay)
else
wet_overlay = mutable_appearance()
var/turf/open/floor/F = src
if(istype(F))
if(wet_setting == TURF_WET_PERMAFROST)
wet_overlay.icon = 'icons/effects/water.dmi'
wet_overlay.icon_state = "ice_floor"
else if(wet_setting == TURF_WET_ICE)
wet_overlay.icon = 'icons/turf/overlays.dmi'
wet_overlay.icon_state = "snowfloor"
else
wet_overlay.icon = 'icons/effects/water.dmi'
wet_overlay.icon_state = "wet_floor_static"
else
wet_overlay.icon = 'icons/effects/water.dmi'
wet_overlay.icon_state = "wet_static"
add_overlay(wet_overlay)
HandleWet()
/turf/open/proc/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0, max_wet_time = MAXIMUM_WET_TIME, permanent)
AddComponent(/datum/component/wet_floor, wet_setting, min_wet_time, wet_time_to_add, max_wet_time, permanent)
/turf/open/proc/UpdateSlip()
var/intensity
var/lube_flags
switch(wet)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
else
qdel(GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/turf/open/proc/AfterSlip(mob/living/L)
if(wet == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/turf/open/proc/MakeDry(wet_setting = TURF_WET_WATER)
if(wet > wet_setting || !wet)
return
spawn(rand(0,20))
if(wet == TURF_WET_PERMAFROST)
wet = TURF_WET_ICE
else if(wet == TURF_WET_ICE)
wet = TURF_WET_WATER
else
wet = TURF_DRY
if(wet_overlay)
cut_overlay(wet_overlay)
UpdateSlip()
/turf/open/proc/HandleWet()
if(!wet)
//It's possible for this handler to get called after all the wetness is
//cleared, so bail out if that is the case
return
if(!wet_time && wet < TURF_WET_ICE)
MakeDry(TURF_WET_ICE)
if(wet_time > MAXIMUM_WET_TIME)
wet_time = MAXIMUM_WET_TIME
if(wet == TURF_WET_ICE && air.temperature > T0C)
for(var/obj/O in contents)
if(O.flags_2 & FROZEN_2)
O.make_unfrozen()
MakeDry(TURF_WET_ICE)
MakeSlippery(TURF_WET_WATER)
if(wet != TURF_WET_PERMAFROST)
switch(air.temperature)
if(-INFINITY to T0C)
if(wet != TURF_WET_ICE && wet)
MakeDry(TURF_WET_ICE)
MakeSlippery(TURF_WET_ICE)
if(T0C to T20C)
wet_time = max(0, wet_time-1)
if(T20C to T0C + 40)
wet_time = max(0, wet_time-2)
if(T0C + 40 to T0C + 60)
wet_time = max(0, wet_time-3)
if(T0C + 60 to T0C + 80)
wet_time = max(0, wet_time-5)
if(T0C + 80 to T0C + 100)
wet_time = max(0, wet_time-10)
if(T0C + 100 to INFINITY)
wet_time = 0
else if (GetTemperature() > BODYTEMP_COLD_DAMAGE_LIMIT) //seems like a good place
MakeDry(TURF_WET_PERMAFROST)
else
wet_time = max(0, wet_time-5)
if(wet && wet < TURF_WET_ICE && !wet_time)
MakeDry(TURF_WET_ICE)
if(!wet && wet_time)
wet_time = 0
if(wet)
addtimer(CALLBACK(src, .proc/HandleWet), 15, TIMER_UNIQUE)
/turf/open/proc/MakeDry(wet_setting = TURF_WET_WATER, immediate = FALSE, amount = INFINITY)
SendSignal(COMSIG_TURF_MAKE_DRY, wet_setting, immediate, amount)
/turf/open/get_dumping_location()
return src
/turf/open/proc/ClearWet()//Nuclear option of immediately removing slipperyness from the tile instead of the natural drying over time
wet = TURF_DRY
UpdateSlip()
if(wet_overlay)
cut_overlay(wet_overlay)
qdel(GetComponent(/datum/component/wet_floor))
/turf/open/rad_act(pulse_strength)
. = ..()

View File

@@ -21,10 +21,10 @@
GET_COMPONENT(chasm_component, /datum/component/chasm)
chasm_component.drop(AM)
/turf/open/chasm/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0)
/turf/open/chasm/MakeSlippery()
return
/turf/open/chasm/MakeDry(wet_setting = TURF_WET_WATER)
/turf/open/chasm/MakeDry()
return
/turf/open/chasm/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)

View File

@@ -33,10 +33,10 @@
/turf/open/floor/plating/asteroid/burn_tile()
return
/turf/open/floor/plating/asteroid/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0)
/turf/open/floor/plating/asteroid/MakeSlippery()
return
/turf/open/floor/plating/asteroid/MakeDry(wet_setting = TURF_WET_WATER)
/turf/open/floor/plating/asteroid/MakeDry()
return
/turf/open/floor/plating/asteroid/attackby(obj/item/W, mob/user, params)

View File

@@ -143,22 +143,15 @@
planetary_atmos = TRUE
baseturfs = /turf/open/floor/plating/ice
slowdown = 1
wet = TURF_WET_PERMAFROST
attachment_holes = FALSE
/turf/open/floor/plating/ice/Initialize()
. = ..()
UpdateSlip()
MakeSlippery(TURF_WET_PERMAFROST, INFINITY, 0, INFINITY, TRUE)
/turf/open/floor/plating/ice/try_replace_tile(obj/item/stack/tile/T, mob/user, params)
return
/turf/open/floor/plating/ice/HandleWet()
if(wet == TURF_WET_ICE)
return
..()
MakeSlippery(TURF_WET_ICE) //rewet after ..() clears out lube/ice etc.
/turf/open/floor/plating/ice/smooth
icon_state = "smooth"
smooth = SMOOTH_MORE | SMOOTH_BORDER

View File

@@ -14,7 +14,7 @@
/turf/open/lava/ex_act(severity, target)
contents_explosion(severity, target)
/turf/open/lava/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0)
/turf/open/lava/MakeSlippery()
return
/turf/open/lava/MakeDry(wet_setting = TURF_WET_WATER)

View File

@@ -7,10 +7,7 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
planetary_atmos = TRUE
slowdown = 1
wet = TURF_WET_WATER
/turf/open/water/HandleWet()
if(wet == TURF_WET_WATER)
return
..()
MakeSlippery(TURF_WET_WATER) //rewet after ..() clears out lube/ice etc.
/turf/open/water/Initialize()
. = ..()
MakeSlippery(TURF_WET_WATER, INFINITY, 0, INFINITY, TRUE)

View File

@@ -84,6 +84,9 @@
/turf/open/space/proc/CanBuildHere()
return TRUE
/turf/open/space/handle_slip()
return
/turf/open/space/attackby(obj/item/C, mob/user, params)
..()
if(!CanBuildHere())
@@ -162,10 +165,7 @@
A.newtonian_move(A.inertia_dir)
/turf/open/space/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0)
return
/turf/open/space/handle_slip()
/turf/open/space/MakeSlippery()
return
/turf/open/space/singularity_act()

View File

@@ -226,8 +226,8 @@ GLOBAL_PROTECT(protected_ranks)
dbfail = 1
else
while(query_load_admins.NextRow())
var/admin_ckey = query_load_admins.item[1]
var/admin_rank = query_load_admins.item[2]
var/admin_ckey = ckey(query_load_admins.item[1])
var/admin_rank = ckeyEx(query_load_admins.item[2])
var/skip
if(rank_names[admin_rank] == null)
message_admins("[admin_ckey] loaded with invalid admin rank [admin_rank].")
@@ -248,7 +248,7 @@ GLOBAL_PROTECT(protected_ranks)
for(var/A in GLOB.admin_datums + GLOB.deadmins)
if(A == "[J]") //this admin was already loaded from txt override
continue
new /datum/admins(rank_names[json["admins"]["[J]"]], "[J]")
new /datum/admins(ckeyEx(rank_names[json["admins"]["[J]"]]), ckey("[J]"))
#ifdef TESTING
var/msg = "Admins Built:\n"
for(var/ckey in GLOB.admin_datums)

View File

@@ -15,7 +15,7 @@
msg = "<span class='admin'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message'>[msg]</span></span>"
to_chat(GLOB.admins, msg)
else
msg = "<span class='adminobserver'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]:</EM> <span class='message'>[msg]</span></span>"
msg = "<span class='adminobserver'><span class='prefix'>ADMIN:</span> <EM>[key_name(usr, 1)]</EM> [ADMIN_FLW(mob)]: <span class='message'>[msg]</span></span>"
to_chat(GLOB.admins, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Asay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -73,7 +73,7 @@
C.prefs.copy_to(M)
M.key = C.key
var/datum/mind/app_mind = M.mind
var/datum/antagonist/wizard/apprentice/app = new()
app.master = user
app.school = kind
@@ -145,6 +145,26 @@
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
M.mind.special_role = "Nuclear Operative"
//////CLOWN OP
/obj/item/antag_spawner/nuke_ops/clown
name = "clown operative teleporter"
desc = "A single-use teleporter designed to quickly reinforce clown operatives in the field."
/obj/item/antag_spawner/nuke_ops/clown/spawn_antag(client/C, turf/T, kind, datum/mind/user)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
var/datum/antagonist/nukeop/clownop/new_op = new /datum/antagonist/nukeop/clownop()
new_op.send_to_spawnpoint = FALSE
new_op.nukeop_outfit = /datum/outfit/syndicate/clownop/no_crystals
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop/clownop,TRUE)
if(creator_op)
M.mind.add_antag_datum(new_op, creator_op.nuke_team)
M.mind.special_role = "Clown Operative"
//////SYNDICATE BORG
/obj/item/antag_spawner/nuke_ops/borg_tele
name = "syndicate cyborg teleporter"
@@ -187,7 +207,7 @@
R.real_name = R.name
R.key = C.key
var/datum/antagonist/nukeop/new_borg = new()
new_borg.send_to_spawnpoint = FALSE
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)

View File

@@ -6,8 +6,8 @@ the new instance inside the host to be updated to the template's stats.
*/
/mob/camera/disease
name = ""
real_name = ""
name = "Sentient Disease"
real_name = "Sentient Disease"
desc = ""
icon = 'icons/mob/blob.dmi'
icon_state = "marker"
@@ -225,7 +225,6 @@ the new instance inside the host to be updated to the template's stats.
disease_instances -= V
hosts -= V.affected_mob
else
points -= 1
to_chat(src, "<span class='notice'>One of your hosts, <b>[V.affected_mob.real_name]</b>, has been purged of your infection.</span>")
var/datum/atom_hud/my_hud = GLOB.huds[DATA_HUD_SENTIENT_DISEASE]

View File

@@ -0,0 +1,25 @@
/datum/antagonist/nukeop/clownop
name = "Clown Operative"
roundend_category = "clown operatives"
antagpanel_category = "ClownOp"
nukeop_outfit = /datum/outfit/syndicate/clownop
/datum/antagonist/nukeop/leader/clownop
name = "Clown Operative Leader"
roundend_category = "clown operatives"
antagpanel_category = "ClownOp"
nukeop_outfit = /datum/outfit/syndicate/clownop/leader
/datum/antagonist/nukeop/leader/clownop/give_alias()
title = pick("Head Honker", "Slipmaster", "Clown King", "Honkbearer")
if(nuke_team && nuke_team.syndicate_name)
owner.current.real_name = "[nuke_team.syndicate_name] [title]"
else
owner.current.real_name = "Syndicate [title]"
/datum/antagonist/nukeop/clownop/admin_add(datum/mind/new_owner,mob/admin)
new_owner.assigned_role = "Clown Operative"
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has clown op'ed [new_owner.current].")
log_admin("[key_name(admin)] has clown op'ed [new_owner.current].")

View File

@@ -15,6 +15,7 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
Such a brazen move will attract the attention of powerful benefactors within the Syndicate, who will supply your team with a massive amount of bonus telecrystals. \
Must be used within five minutes, or your benefactors will lose interest."
var/declaring_war = FALSE
var/uplink_type = /obj/item/device/radio/uplink/nuclear
/obj/item/device/nuclear_challenge/attack_self(mob/living/user)
if(!check_allowed(user))
@@ -59,7 +60,7 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
for(var/obj/machinery/computer/camera_advanced/shuttle_docker/D in GLOB.jam_on_wardec)
D.jammed = TRUE
new /obj/item/device/radio/uplink/nuclear(get_turf(user), user.key, CHALLENGE_TELECRYSTALS)
new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS)
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
@@ -85,6 +86,9 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
return FALSE
return TRUE
/obj/item/device/nuclear_challenge/clownops
uplink_type = /obj/item/device/radio/uplink/clownop
#undef CHALLENGE_TELECRYSTALS
#undef CHALLENGE_TIME_LIMIT
#undef CHALLENGE_MIN_PLAYERS

View File

@@ -1,16 +1,3 @@
#define NUKESTATE_INTACT 5
#define NUKESTATE_UNSCREWED 4
#define NUKESTATE_PANEL_REMOVED 3
#define NUKESTATE_WELDED 2
#define NUKESTATE_CORE_EXPOSED 1
#define NUKESTATE_CORE_REMOVED 0
#define NUKE_OFF_LOCKED 0
#define NUKE_OFF_UNLOCKED 1
#define NUKE_ON_TIMING 2
#define NUKE_ON_EXPLODING 3
/obj/machinery/nuclearbomb
name = "nuclear fission explosive"
desc = "You probably shouldn't stick around to see if this is armed."
@@ -59,9 +46,8 @@
set_safety()
GLOB.poi_list -= src
GLOB.nuke_list -= src
if(countdown)
qdel(countdown)
countdown = null
QDEL_NULL(countdown)
QDEL_NULL(core)
. = ..()
/obj/machinery/nuclearbomb/examine(mob/user)
@@ -459,11 +445,13 @@
//Cinematic
SSticker.mode.OnNukeExplosion(off_station)
var/bombz = z
Cinematic(get_cinematic_type(off_station),world,CALLBACK(SSticker,/datum/controller/subsystem/ticker/proc/station_explosion_detonation,src))
INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel,bombz)
really_actually_explode(off_station)
SSticker.roundend_check_paused = FALSE
/obj/machinery/nuclearbomb/proc/really_actually_explode(off_station)
Cinematic(get_cinematic_type(off_station),world,CALLBACK(SSticker,/datum/controller/subsystem/ticker/proc/station_explosion_detonation,src))
INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel, z)
/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station)
if(off_station < 2)
return CINEMATIC_SELFDESTRUCT

View File

@@ -0,0 +1,37 @@
/datum/team/xeno
name = "Aliens"
//Simply lists them.
/datum/team/xeno/roundend_report()
var/list/parts = list()
parts += "<span class='header'>The [name] were:</span>"
parts += printplayerlist(members)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/antagonist/xeno
name = "Xenomorph"
job_rank = ROLE_ALIEN
show_in_antagpanel = FALSE
var/datum/team/xeno/xeno_team
/datum/antagonist/xeno/create_team(datum/team/xeno/new_team)
if(!new_team)
for(var/datum/antagonist/xeno/X in GLOB.antagonists)
if(!X.owner || !X.xeno_team)
continue
xeno_team = X.xeno_team
return
xeno_team = new
else
if(!istype(new_team))
CRASH("Wrong xeno team type provided to create_team")
xeno_team = new_team
/datum/antagonist/xeno/get_team()
return xeno_team
//XENO
/mob/living/carbon/alien/mind_initialize()
..()
if(!mind.has_antag_datum(/datum/antagonist/xeno))
mind.add_antag_datum(/datum/antagonist/xeno)

View File

@@ -1274,24 +1274,45 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["taur"] = "None"
if("tail_human")
var/list/snowflake_tails_list = list("Normal" = null)
for(var/path in GLOB.tails_list_human)
var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_tails_list[S.name] = path
var/new_tail
new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_human
new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
if(new_tail)
features["tail_human"] = new_tail
if(new_tail != "None")
features["taur"] = "None"
if("mam_tail")
var/list/snowflake_tails_list = list("Normal" = null)
for(var/path in GLOB.mam_tails_list)
var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_tails_list[S.name] = path
var/new_tail
new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.mam_tails_list
new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list
if(new_tail)
features["mam_tail"] = new_tail
if(new_tail != "None")
features["taur"] = "None"
if("taur")
var/list/snowflake_taur_list = list("Normal" = null)
for(var/path in GLOB.taur_list)
var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_taur_list[S.name] = path
var/new_taur
new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in GLOB.taur_list
new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list
if(new_taur)
features["taur"] = new_taur
if(new_taur != "None")
@@ -1305,8 +1326,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["snout"] = new_snout
if("mam_ears")
var/list/snowflake_ears_list = list("Normal" = null)
for(var/path in GLOB.mam_ears_list)
var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_ears_list[S.name] = path
var/new_ears
new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.mam_ears_list
new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
if(new_ears)
features["mam_ears"] = new_ears
@@ -1317,8 +1345,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["horns"] = new_horns
if("ears")
var/list/snowflake_ears_list = list("Normal" = null)
for(var/path in GLOB.ears_list)
var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_ears_list[S.name] = path
var/new_ears
new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in GLOB.ears_list
new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list
if(new_ears)
features["ears"] = new_ears
@@ -1353,8 +1388,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["body_markings"] = new_body_markings
if("mam_body_markings")
var/list/snowflake_markings_list = list("Normal" = null)
for(var/path in GLOB.mam_body_markings_list)
var/datum/sprite_accessory/mam_body_markings/instance = GLOB.mam_body_markings_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey)))
snowflake_markings_list[S.name] = path
var/new_mam_body_markings
new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in GLOB.mam_body_markings_list
new_mam_body_markings = input(user, "Choose your character's body markings:", "Character Preference") as null|anything in snowflake_markings_list
if(new_mam_body_markings)
features["mam_body_markings"] = new_mam_body_markings

View File

@@ -4,25 +4,30 @@
name = "mk-honk prototype shoes"
desc = "Lost prototype of advanced clown tech. Powered by bananium, these shoes leave a trail of chaos in their wake."
icon_state = "clown_prototype_off"
var/on = FALSE
actions_types = list(/datum/action/item_action/toggle)
var/on = FALSE
var/always_noslip = FALSE
/obj/item/clothing/shoes/clown_shoes/banana_shoes/Initialize()
. = ..()
AddComponent(/datum/component/material_container, list(MAT_BANANIUM), 200000, TRUE)
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 75)
if(always_noslip)
flags_1 |= NOSLIP_1
/obj/item/clothing/shoes/clown_shoes/banana_shoes/step_action()
. = ..()
GET_COMPONENT(bananium, /datum/component/material_container)
if(on)
new/obj/item/grown/bananapeel/specialpeel(get_step(src,turn(usr.dir, 180))) //honk
GET_COMPONENT(bananium, /datum/component/material_container)
bananium.use_amount_type(100, MAT_BANANIUM)
if(bananium.amount(MAT_BANANIUM) < 100)
on = !on
flags_1 &= ~NOSLIP_1
if(!always_noslip)
flags_1 &= ~NOSLIP_1
update_icon()
to_chat(loc, "<span class='warning'>You ran out of bananium!</span>")
else
new /obj/item/grown/bananapeel/specialpeel(get_step(src,turn(usr.dir, 180))) //honk
bananium.use_amount_type(100, MAT_BANANIUM)
/obj/item/clothing/shoes/clown_shoes/banana_shoes/attack_self(mob/user)
GET_COMPONENT(bananium, /datum/component/material_container)
@@ -42,10 +47,11 @@
on = !on
update_icon()
to_chat(user, "<span class='notice'>You [on ? "activate" : "deactivate"] the prototype shoes.</span>")
if(on)
flags_1 |= NOSLIP_1
else
flags_1 &= ~NOSLIP_1
if(!always_noslip)
if(on)
flags_1 |= NOSLIP_1
else
flags_1 &= ~NOSLIP_1
else
to_chat(user, "<span class='warning'>You need bananium to turn the prototype shoes on!</span>")

View File

@@ -64,9 +64,7 @@
/obj/item/clothing/shoes/galoshes/dry/step_action()
var/turf/open/t_loc = get_turf(src)
if(istype(t_loc) && t_loc.wet)
t_loc.MakeDry(TURF_WET_WATER)
t_loc.wet_time = 0
t_loc.SendSignal(COMSIG_TURF_MAKE_DRY, TURF_WET_WATER, TRUE, INFINITY)
/obj/item/clothing/shoes/clown_shoes
desc = "The prankster's standard-issue clowning shoes. Damn, they're huge!"

View File

@@ -1,6 +1,5 @@
#define ION_RANDOM 0
#define ION_ANNOUNCE 1
#define ION_FILE "ion_laws.json"
/datum/round_event_control/ion_storm
name = "Ion Storm"
typepath = /datum/round_event/ion_storm

View File

@@ -23,6 +23,21 @@
bonus_reagents = list("sprinkles" = 2, "sugar" = 1)
filling_color = "#FF69B4"
/obj/item/reagent_containers/food/snacks/donut/checkLiked(fraction, mob/M) //Sec officers always love donuts
if(last_check_time + 50 < world.time)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.mind && H.mind.assigned_role == "Security Officer" && !H.has_trait(TRAIT_AGEUSIA))
to_chat(H,"<span class='notice'>I love this taste!</span>")
H.adjust_disgust(-5 + -2.5 * fraction)
GET_COMPONENT_FROM(mood, /datum/component/mood, H)
if(mood)
mood.add_event("fav_food", /datum/mood_event/favorite_food)
last_check_time = world.time
return
..()
/obj/item/reagent_containers/food/snacks/donut/chaos
name = "chaos donut"
desc = "Like life, it never quite tastes the same."

View File

@@ -25,6 +25,7 @@
"sugar" = 5,
"ice" = 5,
"cocoa" = 5,
"vanilla" = 5,
"berryjuice" = 5,
"singulo" = 5)
@@ -40,8 +41,8 @@
return list("flour", "sugar")
if(CONE_CHOC)
return list("flour", "sugar", "cocoa")
else
return list("milk", "ice")
else //ICECREAM_VANILLA
return list("milk", "ice", "vanilla")
/obj/machinery/icecream_vat/proc/get_flavour_name(flavour_type)
@@ -56,7 +57,7 @@
return "waffle"
if(CONE_CHOC)
return "chocolate"
else
else //ICECREAM_VANILLA
return "vanilla"

View File

@@ -146,6 +146,7 @@
icon = 'icons/obj/lavaland/artefacts.dmi'
icon_state = "asclepius_dormant"
var/activated = FALSE
var/usedHand
/obj/item/rod_of_asclepius/attack_self(mob/user)
if(activated)
@@ -154,6 +155,10 @@
to_chat(user, "<span class='warning'>The snake carving seems to come alive, if only for a moment, before returning to it's dormant state, almost as if it finds you incapable of holding it's oath.</span>")
return
var/mob/living/carbon/itemUser = user
usedHand = itemUser.get_held_index_of_item(src)
if(itemUser.has_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH))
to_chat(user, "<span class='warning'>You can't possibly handle the responsibility of more than one rod!</span>")
return
var/failText = "<span class='warning'>The snake seems unsatisfied with your incomplete oath and returns to it's previous place on the rod, returning to its dormant, wooden state. You must stand still while completing your oath!</span>"
to_chat(itemUser, "<span class='notice'>The wooden snake that was carved into the rod seems to suddenly come alive and begins to slither down your arm! The compulsion to help others grows abnormally strong...</span>")
if(do_after(itemUser, 40, target = itemUser))
@@ -178,7 +183,7 @@
return
to_chat(itemUser, "<span class='notice'>The snake, satisfied with your oath, attaches itself and the rod to your forearm with an inseparable grip. Your thoughts seem to only revolve around the core idea of helping others, and harm is nothing more than a distant, wicked memory...</span>")
var/datum/status_effect/hippocraticOath/effect = itemUser.apply_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH)
effect.hand = itemUser.get_held_index_of_item(src)
effect.hand = usedHand
activated()
/obj/item/rod_of_asclepius/proc/activated()

View File

@@ -5,7 +5,7 @@
var/extra2 = FALSE
var/extra2_icon = 'icons/mob/mam_bodyparts.dmi'
var/extra2_color_src = MUTCOLORS3
// var/list/ckeys_allowed = null
var/list/ckeys_allowed
/* tbi eventually idk
/datum/sprite_accessory/legs/digitigrade_mam
@@ -97,6 +97,12 @@
extra = TRUE
icon = 'icons/mob/mam_bodyparts.dmi'
//datum/sprite_accessory/ears/elf
// name = "Elf"
// icon_state = "elf"
// icon = 'icons/mob/mam_bodyparts.dmi'
// ckeys_allowed = list("atiefling")
/datum/sprite_accessory/ears/fennec
name = "Fennec"
icon_state = "fennec"
@@ -950,34 +956,44 @@
/datum/sprite_accessory/mam_ears/guilmon
name = "Guilmon"
icon_state = "guilmon"
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/snout/guilmon
name = "Guilmon"
icon_state = "guilmon"
/datum/sprite_accessory/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
// ckeys_allowed = list("rubyflamewing")
ckeys_allowed = list("rubyflamewing")
/datum/sprite_accessory/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = 0
/*
//Till I get my snowflake only ckey lock, these are locked-locked :D
/datum/sprite_accessory/mam_body_markings/shark/datashark
name = "DataShark"
icon_state = "datashark"
color_src = MUTCOLORS2
ckeys_allowed = list("rubyflamewing")
//Sabresune
/datum/sprite_accessory/mam_ears/sabresune
name = "sabresune"
icon_state = "sabresune"
hasinner = 1
extra = TRUE
extra_color_src = MUTCOLORS3
locked = TRUE
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails/sabresune
name = "sabresune"
icon_state = "sabresune"
extra = TRUE
locked = TRUE
ckeys_allowed = list("poojawa")
/datum/sprite_accessory/mam_tails_animated/sabresune
name = "sabresune"
@@ -990,5 +1006,5 @@
color_src = MUTCOLORS2
extra = FALSE
extra2 = FALSE
locked = TRUE
*/
ckeys_allowed = list("poojawa")

View File

@@ -170,8 +170,12 @@
return FALSE
return !held_items[hand_index]
/mob/proc/put_in_hand(obj/item/I, hand_index)
if(can_put_in_hand(I, hand_index))
/mob/proc/put_in_hand(obj/item/I, hand_index, forced = FALSE)
if(forced || can_put_in_hand(I, hand_index))
if(hand_index == null)
return FALSE
if(get_item_for_held_index(hand_index) != null)
dropItemToGround(get_item_for_held_index(hand_index), force = TRUE)
I.forceMove(src)
held_items[hand_index] = I
I.layer = ABOVE_HUD_LAYER
@@ -185,7 +189,6 @@
return hand_index || TRUE
return FALSE
//Puts the item into the first available left hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(obj/item/I)
return put_in_hand(I, get_empty_held_index_for_side("l"))

View File

@@ -272,7 +272,7 @@
else if(check_zone(M.zone_selected) == "head")
M.visible_message("<span class='notice'>[M] gives [src] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>")
if(dna && dna.species && (("tail_lizard" in dna.species.mutant_bodyparts) || (dna.features["tail_human"] != "None") || ("mam_tail" in dna.species.mutant_bodyparts)))
if(dna && dna.species && ((("tail_lizard" || "tail_human" || "mam_tail") in dna.species.mutant_bodyparts && (dna.features["tail_lizard"] || dna.features["tail_human"] || dna.features["mam_tail"])!= "None")))
emote("wag") //lewd
else
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \

View File

@@ -27,7 +27,6 @@
add_logs(src,, "slipped",, "on [O ? O.name : "floor"]")
return loc.handle_slip(src, knockdown_amount, O, lube)
/mob/living/carbon/Process_Spacemove(movement_dir = 0)
if(..())
return 1

View File

@@ -54,7 +54,7 @@
liked_food = MEAT
disliked_food = TOXIC
meat = /obj/item/reagent_containers/food/snacks/carpmeat/aquatic
/datum/species/aquatic/spec_death(gibbed, mob/living/carbon/human/H)
if(H)
H.endTailWag()
@@ -82,7 +82,6 @@
/datum/species/insect/qualifies_for_rank(rank, list/features)
return TRUE
//HERBIVOROUS//
//Alien//
/datum/species/xeno
@@ -159,89 +158,9 @@
description = "A highly corrosive substance, it is capable of burning through most natural or man-made materials in short order."
color = "#66CC00"
toxpwr = 0
acidpwr = 12
acidpwr = 12 */
/datum/species/yautja
name = "Yautja"
id = "pred"
say_mod = "clicks"
eyes = "predeyes"
mutant_organs = list(/obj/item/organ/tongue/yautja)
specflags = list(EYECOLOR)
lang_spoken = YAUTJA
lang_understood = HUMAN|YAUTJA|ALIEN
no_equip = list(slot_head)
punchdamagelow = 4
punchdamagehigh = 14
punchstunthreshold = 13
blacklisted = 1
whitelist = 1
whitelist = list("talkingcactus")
/datum/outfit/yautja_basic
name = "Yautja, Basic"
uniform = /obj/item/clothing/under/mesh
suit = /obj/item/clothing/suit/armor/yautja_fake
shoes = /obj/item/clothing/shoes/yautja_fake
mask = /obj/item/clothing/mask/gas/yautja_fake
/datum/species/yautja/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE)
var/datum/outfit/yautja_basic/O = new /datum/outfit/yautja_basic//Just basic gear. Doesn't include anything that gives any meaningful advantage.
H.equipOutfit(O, visualsOnly)
return 0
/datum/species/octopus
blacklisted = 1
/datum/species/carp
blacklisted = 1
/datum/species/horse
blacklisted = 1*/
///////////////////
//DONATOR SPECIES//
///////////////////
//ChronoFlux: Slimecoon
/*
/datum/species/jelly/slime/slimecoon
name = "Slime Raccoon"
id = "slimecoon"
limbs_id = "slime"
whitelisted = 1
whitelist = list("chronoflux")
blacklisted = 1
mutant_bodyparts = list("slimecoontail", "slimecoonears", "slimecoonsnout")
default_features = list("slimecoontail" = "Slimecoon Tail", "slimecoonears" = "Slimecoon Ears", "slimecoonsnout" = "Slimecoon Snout")*/
// Fat Shark <3
/*
/datum/species/shark/datashark
name = "DataShark"
id = "datashark"
default_color = "BCAC9B"
species_traits = list(MUTCOLORS_PARTSONLY,EYECOLOR,LIPS,HAIR,SPECIES_ORGANIC)
mutant_bodyparts = list("mam_tail", "mam_body_markings")
default_features = list("mam_tail" = "datashark", "mam_body_markings" = "None")
attack_verb = "bite"
attack_sound = 'sound/weapons/bite.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
whitelisted = 1
whitelist = list("rubyflamewing")
blacklisted = 0
*/
/datum/species/guilmon
name = "Guilmon"
id = "guilmon"
default_color = "4B4B4B"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,SPECIES_ORGANIC)
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings")
default_features = list("mcolor" = "FFF", "mcolor2" = "FFF", "mcolor3" = "FFF", "mam_tail" = "guilmon", "mam_ears" = "guilmon", "mam_body_markings" = "guilmon")
attack_verb = "claw"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
//##########SLIMEPEOPLE##########
/datum/species/jelly/roundstartslime

View File

@@ -246,7 +246,7 @@
if(prob(75))
var/turf/open/T = loc
if(istype(T))
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 20, wet_time_to_add = 15)
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 20 SECONDS, wet_time_to_add = 15 SECONDS)
else
visible_message("<span class='danger'>[src] whirs and bubbles violently, before releasing a plume of froth!</span>")
new /obj/effect/particle_effect/foam(loc)

View File

@@ -137,8 +137,8 @@
name = "Syndicate Stormtrooper"
maxHealth = 200
health = 200
casingtype = /obj/item/ammo_casing/shotgun/tengauge
projectilesound = 'sound/weapons/gunshot.ogg'
casingtype = /obj/item/ammo_casing/shotgun/buckshot
loot = list(/obj/effect/gibspawner/human)
///////////////Misc////////////

View File

@@ -425,5 +425,8 @@
if(..())
return 3
/mob/living/simple_animal/slime/can_be_implanted()
return TRUE
/mob/living/simple_animal/slime/random/Initialize(mapload, new_colour, new_is_adult)
. = ..(mapload, pick(slime_colours), prob(50))

View File

@@ -102,3 +102,5 @@
var/list/progressbars = null //for stacking do_after bars
var/list/mousemove_intercept_objects
var/datum/click_intercept

View File

@@ -87,6 +87,7 @@
if(istype(linked_techweb))
linked_techweb.research_points += min(power_produced, 1)
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
tesla_buckle_check(power)
else
..()
@@ -100,6 +101,7 @@
add_load(power)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 10, power/(coeff/2))
tesla_buckle_check(power/(coeff/2))
// Tesla R&D researcher
/obj/machinery/power/tesla_coil/research
@@ -120,6 +122,7 @@
if(istype(linked_techweb))
linked_techweb.research_points += min(power_produced, 3) // 4 coils makes ~720/m bonus for R&D,
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
tesla_buckle_check(power)
else
..()
@@ -136,6 +139,10 @@
return
return ..()
/obj/machinery/power/tesla_coil/research/on_construction()
if(anchored)
connect_to_network()
/obj/machinery/power/grounding_rod
name = "grounding rod"
desc = "Keep an area from being fried from Edison's Bane."
@@ -179,5 +186,6 @@
/obj/machinery/power/grounding_rod/tesla_act(var/power)
if(anchored && !panel_open)
flick("grounding_rodhit", src)
tesla_buckle_check(power)
else
..()
..()

View File

@@ -7,6 +7,11 @@
caliber = "shotgun"
projectile_type = /obj/item/projectile/bullet/shotgun_slug
materials = list(MAT_METAL=4000)
/obj/item/ammo_casing/shotgun/tengauge
name = "10g shotgun slug"
desc = "A 10 gauge lead slug."
projectile_type = /obj/item/projectile/bullet/shotgun_slug/tengauge
/obj/item/ammo_casing/shotgun/beanbag
name = "beanbag slug"

View File

@@ -54,7 +54,7 @@
force = 0
throwforce = 0
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy
clumsy_check = 0
clumsy_check = FALSE
item_flags = NONE
casing_ejector = FALSE
can_suppress = FALSE
@@ -87,6 +87,7 @@
item_flags = NONE
mag_type = /obj/item/ammo_box/magazine/toy/smgm45/riot
casing_ejector = FALSE
clumsy_check = FALSE
/obj/item/gun/ballistic/automatic/c20r/toy/unrestricted //Use this for actual toys
pin = /obj/item/device/firing_pin
@@ -103,6 +104,7 @@
item_flags = NONE
mag_type = /obj/item/ammo_box/magazine/toy/m762/riot
casing_ejector = FALSE
clumsy_check = FALSE
/obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted //Use this for actual toys
pin = /obj/item/device/firing_pin

View File

@@ -1,6 +1,10 @@
/obj/item/projectile/bullet/shotgun_slug
name = "12g shotgun slug"
damage = 60
/obj/item/projectile/bullet/shotgun_slug/tengauge
name = "10g shotgun slug"
damage = 72.5
/obj/item/projectile/bullet/shotgun_beanbag
name = "beanbag slug"

View File

@@ -9,15 +9,17 @@
idle_power_usage = 40
interact_offline = TRUE
resistance_flags = FIRE_PROOF | ACID_PROOF
circuit = /obj/item/circuitboard/machine/chem_dispenser
var/cell_type = /obj/item/stock_parts/cell/high
var/obj/item/stock_parts/cell/cell
var/powerefficiency = 0.01
var/powerefficiency = 0.1
var/amount = 30
var/recharged = 0
var/recharge_delay = 5
var/mutable_appearance/beaker_overlay
var/working_state = "dispenser_working"
var/nopower_state = "dispenser_nopower"
var/macrotier = 1
var/obj/item/reagent_containers/beaker = null
var/list/dispensable_reagents = list(
"hydrogen",
@@ -199,7 +201,7 @@ obj/machinery/chem_dispenser/update_icon()
var/actual = min(amount, (cell.charge * powerefficiency)*10, free)
R.add_reagent(reagent, actual)
cell.use((actual / 10) / powerefficiency)
cell.use(actual / powerefficiency)
work_animation()
. = TRUE
if("remove")
@@ -219,16 +221,17 @@ obj/machinery/chem_dispenser/update_icon()
if("dispense_recipe")
var/recipe_to_use = params["recipe"]
var/list/chemicals_to_dispense = process_recipe_list(recipe_to_use)
var/res = get_macro_resolution()
for(var/key in chemicals_to_dispense) // i suppose you could edit the list locally before passing it
var/list/keysplit = splittext(key," ")
var/r_id = keysplit[1]
if(beaker && dispensable_reagents.Find(r_id)) // but since we verify we have the reagent, it'll be fine
var/datum/reagents/R = beaker.reagents
var/free = R.maximum_volume - R.total_volume
var/actual = min(chemicals_to_dispense[key], (cell.charge * powerefficiency)*10, free)
var/actual = min(round(chemicals_to_dispense[key], res), (cell.charge * powerefficiency)*10, free)
if(actual)
R.add_reagent(r_id, actual)
cell.use((actual / 10) / powerefficiency)
cell.use(actual / powerefficiency)
work_animation()
if("clear_recipes")
var/yesno = alert("Clear all recipes?",, "Yes","No")
@@ -241,21 +244,35 @@ obj/machinery/chem_dispenser/update_icon()
var/list/first_process = splittext(recipe, ";")
if(!LAZYLEN(first_process))
return
var/res = get_macro_resolution()
var/resmismatch = FALSE
for(var/reagents in first_process)
var/list/fuck = splittext(reagents, "=")
if(dispensable_reagents.Find(fuck[1]))
var/list/reagent = splittext(reagents, "=")
if(dispensable_reagents.Find(reagent[1]))
if (!resmismatch && !check_macro_part(reagents, res))
resmismatch = TRUE
continue
else
var/temp = fuck[1]
var/chemid = reagent[1]
visible_message("<span class='warning'>[src] buzzes.</span>", "<span class='italics'>You hear a faint buzz.</span>")
to_chat(usr, "<span class ='danger'>[src] cannot find Chemical ID: <b>[temp]</b>!</span>")
to_chat(usr, "<span class ='danger'>[src] cannot find Chemical ID: <b>[chemid]</b>!</span>")
playsound(src, "sound/machines/buzz-two.ogg", 50, 1)
return
if (resmismatch && alert("[src] is not yet capable of replicating this recipe with the precision it needs, do you want to save it anyway?",, "Yes","No") == "No")
return
saved_recipes += list(list("recipe_name" = name, "contents" = recipe))
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
if(default_unfasten_wrench(user, I))
return
if(default_deconstruction_screwdriver(user, "dispenser-o", "dispenser", I))
return
if(exchange_parts(user, I))
return
if(default_deconstruction_crowbar(I))
return
if(istype(I, /obj/item/reagent_containers) && !(I.flags_1 & ABSTRACT_1) && I.is_open_container())
var/obj/item/reagent_containers/B = I
. = 1 //no afterattack
@@ -294,92 +311,48 @@ obj/machinery/chem_dispenser/update_icon()
visible_message("<span class='danger'>[src] malfunctions, spraying chemicals everywhere!</span>")
..()
/obj/machinery/chem_dispenser/constructable
name = "portable chem dispenser"
icon = 'icons/obj/chemical.dmi'
icon_state = "minidispenser"
powerefficiency = 0.001
amount = 5
recharge_delay = 20
dispensable_reagents = list()
circuit = /obj/item/circuitboard/machine/chem_dispenser
working_state = "minidispenser_working"
nopower_state = "minidispenser_nopower"
var/static/list/dispensable_reagent_tiers = list(
list(
"hydrogen",
"oxygen",
"silicon",
"phosphorus",
"sulfur",
"carbon",
"nitrogen",
"water"
),
list(
"lithium",
"sugar",
"sacid",
"copper",
"mercury",
"sodium",
"iodine",
"bromine"
),
list(
"ethanol",
"chlorine",
"potassium",
"aluminium",
"radium",
"fluorine",
"iron",
"welding_fuel",
"silver",
"stable_plasma"
),
list(
"oil",
"ash",
"acetone",
"saltpetre",
"ammonia",
"diethylamine"
)
)
/obj/machinery/chem_dispenser/constructable/RefreshParts()
/obj/machinery/chem_dispenser/RefreshParts()
var/time = 0
var/i
var/newpowereff = 0.0666666
for(var/obj/item/stock_parts/cell/P in component_parts)
cell = P
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
time += M.rating
newpowereff += 0.0166666666*M.rating
for(var/obj/item/stock_parts/capacitor/C in component_parts)
time += C.rating
recharge_delay = 30/(time/2) //delay between recharges, double the usual time on lowest 50% less than usual on highest
for(var/obj/item/stock_parts/manipulator/M in component_parts)
for(i=1, i<=M.rating, i++)
dispensable_reagents |= dispensable_reagent_tiers[i]
dispensable_reagents = sortList(dispensable_reagents)
if (M.rating > macrotier)
macrotier = M.rating
powerefficiency = round(newpowereff, 0.01)
/obj/machinery/chem_dispenser/constructable/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I))
return
if(exchange_parts(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/chem_dispenser/constructable/on_deconstruction()
/obj/machinery/chem_dispenser/on_deconstruction()
if(beaker)
beaker.forceMove(drop_location())
beaker = null
return ..()
/obj/machinery/chem_dispenser/proc/get_macro_resolution()
. = 5
if (macrotier > 1)
. -= macrotier // 5 for tier1, 3 for 2, 2 for 3, 1 for 4.
/obj/machinery/chem_dispenser/proc/check_macro(var/macro)
var/res = get_macro_resolution()
for (var/reagent in splittext(macro, ";"))
if (!check_macro_part(reagent, res))
return FALSE
return TRUE
/obj/machinery/chem_dispenser/proc/check_macro_part(var/part, var/res = get_macro_resolution())
var/detail = splittext(part, "=")
if (round(text2num(detail[2]), res) != text2num(detail[2]))
return FALSE
return TRUE
/obj/machinery/chem_dispenser/proc/process_recipe_list(var/fucking_hell)
var/list/key_list = list()
var/list/final_list = list()
@@ -389,12 +362,6 @@ obj/machinery/chem_dispenser/update_icon()
final_list += list(avoid_assoc_duplicate_keys(fuck[1],key_list) = text2num(fuck[2]))
return final_list
/obj/machinery/chem_dispenser/constructable/display_beaker()
var/mutable_appearance/b_o = beaker_overlay || mutable_appearance(icon, "disp_beaker")
b_o.pixel_y = -4
b_o.pixel_x = -4
return b_o
/obj/machinery/chem_dispenser/drinks/display_beaker()
var/mutable_appearance/b_o = beaker_overlay || mutable_appearance(icon, "disp_beaker")
switch(dir)

View File

@@ -459,7 +459,7 @@
reac_volume = ..()
var/turf/open/T = get_turf(M)
if(istype(T) && prob(reac_volume))
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
M.adjust_fire_stacks(-(reac_volume / 10))
M.ExtinguishMob()
M.apply_damage(0.4*reac_volume, BRUTE)
@@ -481,7 +481,7 @@
/datum/reagent/blob/pressurized_slime/proc/extinguisharea(obj/structure/blob/B, probchance)
for(var/turf/open/T in range(1, B))
if(prob(probchance))
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
for(var/obj/O in T)
O.extinguish()
for(var/mob/living/L in T)

View File

@@ -124,7 +124,7 @@
if(!istype(T))
return
if(reac_volume >= 5)
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10, wet_time_to_add = reac_volume * 1.5)
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = reac_volume * 1.5 SECONDS)
T.name = "deep-fried [initial(T.name)]"
T.add_atom_colour(color, TEMPORARY_COLOUR_PRIORITY)
@@ -249,7 +249,7 @@
if(reac_volume >= 1) // Make Freezy Foam and anti-fire grenades!
if(isopenturf(T))
var/turf/open/OT = T
OT.MakeSlippery(wet_setting=TURF_WET_ICE, min_wet_time=10, wet_time_to_add=reac_volume) // Is less effective in high pressure/high heat capacity environments. More effective in low pressure.
OT.MakeSlippery(wet_setting=TURF_WET_ICE, min_wet_time=100, wet_time_to_add=reac_volume SECONDS) // Is less effective in high pressure/high heat capacity environments. More effective in low pressure.
OT.air.temperature -= MOLES_CELLSTANDARD*100*reac_volume/OT.air.heat_capacity() // reduces environment temperature by 5K per unit.
/datum/reagent/consumable/condensedcapsaicin
@@ -433,7 +433,7 @@
/datum/reagent/consumable/cornoil/reaction_turf(turf/open/T, reac_volume)
if (!istype(T))
return
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10, wet_time_to_add = reac_volume*2)
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = reac_volume*2 SECONDS)
var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
if(hotspot)
var/datum/gas_mixture/lowertemp = T.remove_air(T.air.total_moles())

View File

@@ -135,7 +135,7 @@
var/CT = cooling_temperature
if(reac_volume >= 5)
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = min(reac_volume*1.5, 60))
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = min(reac_volume*1.5 SECONDS, 60 SECONDS))
for(var/mob/living/simple_animal/slime/M in T)
M.apply_water()
@@ -329,7 +329,7 @@
if (!istype(T))
return
if(reac_volume >= 1)
T.MakeSlippery(TURF_WET_LUBE, 15, min(reac_volume * 2, 120))
T.MakeSlippery(TURF_WET_LUBE, 15 SECONDS, min(reac_volume * 2 SECONDS, 120))
/datum/reagent/spraytan
name = "Spray Tan"
@@ -1613,9 +1613,8 @@
taste_description = "dryness"
/datum/reagent/drying_agent/reaction_turf(turf/open/T, reac_volume)
if(istype(T) && T.wet)
T.wet_time = max(0, T.wet_time-reac_volume*5) // removes 5 seconds of wetness for every unit.
T.HandleWet()
if(istype(T))
T.MakeDry(ALL, TRUE, reac_volume * 5 SECONDS) //50 deciseconds per unit
/datum/reagent/drying_agent/reaction_obj(obj/O, reac_volume)
if(O.type == /obj/item/clothing/shoes/galoshes)

View File

@@ -513,7 +513,7 @@
required_other = 1
/datum/chemical_reaction/slime/slimeradio/on_reaction(datum/reagents/holder, created_volume)
new /obj/item/slimepotion/slimeradio(get_turf(holder.my_atom))
new /obj/item/slimepotion/slime/slimeradio(get_turf(holder.my_atom))
..()
//Cerulean

View File

@@ -49,22 +49,22 @@
/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user)
..()
if(slime_up_action)
if(slime_up_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
slime_up_action.target = src
slime_up_action.Grant(user)
actions += slime_up_action
if(slime_place_action)
if(slime_place_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
slime_place_action.target = src
slime_place_action.Grant(user)
actions += slime_place_action
if(feed_slime_action)
if(feed_slime_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
feed_slime_action.target = src
feed_slime_action.Grant(user)
actions += feed_slime_action
if(monkey_recycle_action)
if(monkey_recycle_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes remote monkey recycling require XENOBIO_UPGRADE_MONKEYS
monkey_recycle_action.target = src
monkey_recycle_action.Grant(user)
actions += monkey_recycle_action
@@ -74,18 +74,18 @@
scan_action.Grant(user)
actions += scan_action
if(potion_action)
if(potion_action && (upgradetier & XENOBIO_UPGRADE_SLIMEADV)) // CIT CHANGE - makes giving slimes potions via console require XENOBIO_UPGRADE_SLIMEADV
potion_action.target = src
potion_action.Grant(user)
actions += potion_action
/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube))
if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube) && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
monkeys++
to_chat(user, "<span class='notice'>You feed [O] to [src]. It now has [monkeys] monkey cubes stored.</span>")
qdel(O)
return
else if(istype(O, /obj/item/storage/bag))
else if(istype(O, /obj/item/storage/bag) && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
var/obj/item/storage/P = O
var/loaded = 0
for(var/obj/G in P.contents)
@@ -96,7 +96,7 @@
if (loaded)
to_chat(user, "<span class='notice'>You fill [src] with the monkey cubes stored in [O]. [src] now has [monkeys] monkey cubes stored.</span>")
return
else if(istype(O, /obj/item/slimepotion/slime))
else if(istype(O, /obj/item/slimepotion/slime) && (upgradetier & XENOBIO_UPGRADE_SLIMEADV)) // CIT CHANGE - makes giving slimes potions via console require XENOBIO_UPGRADE_SLIMEADV
var/replaced = FALSE
if(user && !user.transferItemToLoc(O, src))
return

View File

@@ -825,9 +825,11 @@
L.regenerate_icons()
qdel(src)
/obj/item/slimepotion/slimeradio
/obj/item/slimepotion/slime/slimeradio
name = "bluespace radio potion"
desc = "A strange chemical that grants those who ingest it the ability to broadcast and recieve subscape radio waves."
icon = 'icons/obj/chemical.dmi'
icon_state = "potgrey"
/obj/item/slimepotion/slime/slimeradio/attack(mob/living/M, mob/user)
if(!ismob(M))

View File

@@ -108,10 +108,14 @@
return FALSE
/obj/docking_port/mobile/arrivals/proc/PersonCheck()
for(var/M in (GLOB.alive_mob_list & GLOB.player_list))
var/mob/living/L = M
if((get_area(M) in areas) && L.stat != DEAD)
return TRUE
for(var/V in GLOB.player_list)
var/mob/M = V
if((get_area(M) in areas) && M.stat != DEAD)
if(!iscameramob(M))
return TRUE
var/mob/camera/C = M
if(C.move_on_shuttle)
return TRUE
return FALSE
/obj/docking_port/mobile/arrivals/proc/NukeDiskCheck()

View File

@@ -67,7 +67,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
else
return
user.ranged_ability = src
user.client.click_intercept = user.ranged_ability
user.click_intercept = src
add_mousepointer(user.client)
ranged_ability_user = user
if(msg)
@@ -87,7 +87,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(!ranged_ability_user || !ranged_ability_user.client || (ranged_ability_user.ranged_ability && ranged_ability_user.ranged_ability != src)) //To avoid removing the wrong ability
return
ranged_ability_user.ranged_ability = null
ranged_ability_user.client.click_intercept = null
ranged_ability_user.click_intercept = null
remove_mousepointer(ranged_ability_user.client)
if(msg)
to_chat(ranged_ability_user, msg)

View File

@@ -12,6 +12,11 @@
GET_COMPONENT(hidden_uplink, /datum/component/uplink)
hidden_uplink.set_gamemode(/datum/game_mode/nuclear)
/obj/item/device/radio/uplink/clownop/Initialize()
. = ..()
GET_COMPONENT(hidden_uplink, /datum/component/uplink)
hidden_uplink.set_gamemode(/datum/game_mode/nuclear/clown_ops)
/obj/item/device/multitool/uplink/Initialize(mapload, _owner, _tc_amount = 20)
. = ..()
AddComponent(/datum/component/uplink, _owner, FALSE, TRUE, null, _tc_amount)

View File

@@ -157,6 +157,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
with suppressors."
item = /obj/item/gun/ballistic/automatic/pistol
cost = 7
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/revolver
name = "Syndicate Revolver"
@@ -164,6 +165,15 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/gun/ballistic/revolver
cost = 13
surplus = 50
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/pie_cannon
name = "Banana Cream Pie Cannon"
desc = "A special pie cannon for a special clown, this gadget can hold up to 20 pies and automatically fabricates one every two seconds!"
cost = 10
item = /obj/item/pneumatic_cannon/pie/selfcharge
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/shotgun
name = "Bulldog Shotgun"
@@ -243,6 +253,16 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
pocketed when inactive. Activating it produces a loud, distinctive noise."
item = /obj/item/melee/transforming/energy/sword/saber
cost = 8
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/clownsword
name = "Bananium Energy Sword"
desc = "An energy sword that deals no damage, but will slip anyone it contacts, be it by melee attack, thrown \
impact, or just stepping on it. Beware friendly fire, as even anti-slip shoes will not protect against it."
item = /obj/item/melee/transforming/energy/sword/bananium
cost = 3
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/doublesword
name = "Double-Bladed Energy Sword"
@@ -251,6 +271,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/twohanded/dualsaber
player_minimum = 25
cost = 16
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/doublesword/get_discount()
return pick(4;0.8,2;0.65,1;0.5)
@@ -277,6 +298,25 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
in addition to dealing high amounts of damage to nearby personnel."
item = /obj/item/grenade/syndieminibomb
cost = 6
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/bombanana
name = "Bombanana"
desc = "A banana with an explosive taste! discard the peel quickly, as it will explode with the force of a syndicate minibomb \
a few seconds after the banana is eaten."
item = /obj/item/reagent_containers/food/snacks/grown/banana/bombanana
cost = 4 //it is a bit cheaper than a minibomb because you have to take off your helmet to eat it, which is how you arm it
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/tearstache
name = "Teachstache Grenade"
desc = "A teargas grenade that launches sticky moustaches onto the face of anyone not wearing a clown or mime mask. The moustaches will \
remain attached to the face of all targets for one minute, preventing the use of breath masks and other such devices."
item = /obj/item/grenade/chem_grenade/teargas/moustache
cost = 3
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/foamsmg
name = "Toy Submachine Gun"
@@ -284,7 +324,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/gun/ballistic/automatic/c20r/toy
cost = 5
surplus = 0
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/foammachinegun
name = "Toy Machine Gun"
@@ -293,7 +333,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/gun/ballistic/automatic/l6_saw/toy
cost = 10
surplus = 0
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/viscerators
name = "Viscerator Delivery Grenade"
@@ -302,7 +342,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/grenade/spawnergrenade/manhacks
cost = 5
surplus = 35
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/bioterrorfoam
name = "Chemical Foam Grenade"
@@ -312,7 +352,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/grenade/chem_grenade/bioterrorfoam
cost = 5
surplus = 35
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/bioterror
name = "Biohazardous Chemical Sprayer"
@@ -322,7 +362,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/reagent_containers/spray/chemsprayer/bioterror
cost = 20
surplus = 0
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/stealthy_weapons/virus_grenade
name = "Fungal Tuberculosis Grenade"
@@ -332,7 +372,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/storage/box/syndie_kit/tuberculosisgrenade
cost = 12
surplus = 35
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/guardian
name = "Holoparasites"
@@ -341,7 +381,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/storage/box/syndie_kit/guardian
cost = 18
surplus = 0
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
player_minimum = 25
// Ammunition
@@ -355,24 +395,28 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
are dirt cheap but are half as effective as .357 rounds."
item = /obj/item/ammo_box/magazine/m10mm
cost = 1
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/ammo/pistolap
name = "10mm Armour Piercing Magazine"
desc = "An additional 8-round 10mm magazine; compatible with the Stechkin Pistol. These rounds are less effective at injuring the target but penetrate protective gear."
item = /obj/item/ammo_box/magazine/m10mm/ap
cost = 2
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/ammo/pistolfire
name = "10mm Incendiary Magazine"
desc = "An additional 8-round 10mm magazine; compatible with the Stechkin Pistol. Loaded with incendiary rounds which ignite the target."
item = /obj/item/ammo_box/magazine/m10mm/fire
cost = 2
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/ammo/pistolhp
name = "10mm Hollow Point Magazine"
desc = "An additional 8-round 10mm magazine; compatible with the Stechkin Pistol. These rounds are more damaging but ineffective against armour."
item = /obj/item/ammo_box/magazine/m10mm/hp
cost = 3
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/ammo/pistolaps
name = "9mm Handgun Magazine"
@@ -394,6 +438,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
For when you really need a lot of things dead."
item = /obj/item/ammo_box/a357
cost = 4
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/ammo/shotgun
cost = 2
@@ -517,7 +562,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
and broca systems, making it impossible for them to move or speak for some time."
item = /obj/item/storage/box/syndie_kit/bioterror
cost = 6
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
//Support and Mechs
/datum/uplink_item/support
@@ -532,6 +577,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/antag_spawner/nuke_ops
cost = 25
refundable = TRUE
include_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/support/reinforcement/assault_borg
name = "Syndicate Assault Cyborg"
@@ -562,6 +608,20 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/mecha/combat/marauder/mauler/loaded
cost = 140
/datum/uplink_item/support/honker
name = "Dark H.O.N.K."
desc = "A clown combat mech equipped with bombanana peel and tearstache grenade launchers, as well as the ubiquitous HoNkER BlAsT 5000."
item = /obj/mecha/combat/honker/dark/loaded
cost = 80
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/support/clown_reinforcement
name = "Clown Reinforcements"
desc = "Call in an additional clown to share the fun, equipped with full starting gear, but no telecrystals."
item = /obj/item/antag_spawner/nuke_ops/clown
cost = 20
include_modes = list(/datum/game_mode/nuclear/clown_ops)
// Stealthy Weapons
/datum/uplink_item/stealthy_weapons
category = "Stealthy and Inconspicuous Weapons"
@@ -573,13 +633,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/sleeping_carp_scroll
cost = 17
surplus = 0
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/stealthy_weapons/cqc
name = "CQC Manual"
desc = "A manual that teaches a single user tactical Close-Quarters Combat before self-destructing."
item = /obj/item/cqc_manual
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
cost = 13
surplus = 0
@@ -661,6 +721,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/suppressor
cost = 3
surplus = 10
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/stealthy_weapons/pizza_bomb
name = "Pizza Bomb"
@@ -700,7 +761,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
They do not work on heavily lubricated surfaces."
item = /obj/item/clothing/shoes/chameleon/noslip
cost = 2
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
player_minimum = 20
/datum/uplink_item/stealthy_tools/syndigaloshes/nuke
@@ -709,6 +770,16 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
exclude_modes = list()
include_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/stealthy_tools/combatbananashoes
name = "Combat Banana Shoes"
desc = "While making the wearer immune to most slipping attacks like regular combat clown shoes, these shoes \
can generate a large number of synthetic banana peels as the wearer walks, slipping up would-be pursuers. They also \
squeek significantly louder."
item = /obj/item/clothing/shoes/clown_shoes/banana_shoes/combat
cost = 6
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/stealthy_tools/frame
name = "F.R.A.M.E. PDA Cartridge"
desc = "When inserted into a personal digital assistant, this cartridge gives you five PDA viruses which \
@@ -767,7 +838,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/reagent_containers/syringe/mulligan
cost = 4
surplus = 30
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/stealthy_tools/emplight
name = "EMP Flashlight"
@@ -823,7 +894,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
provides the user with superior armor and mobility compared to the standard syndicate hardsuit."
item = /obj/item/clothing/suit/space/hardsuit/syndi/elite
cost = 8
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
exclude_modes = list()
/datum/uplink_item/suits/hardsuit/shielded
@@ -832,7 +903,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
The shields can handle up to three impacts within a short duration and will rapidly recharge while not under fire."
item = /obj/item/clothing/suit/space/hardsuit/shielded/syndi
cost = 30
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
exclude_modes = list()
// Devices and Tools
@@ -882,7 +953,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
and other supplies helpful for a field medic."
item = /obj/item/storage/firstaid/tactical
cost = 4
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/syndietome
name = "Syndicate Tome"
@@ -952,7 +1023,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
'Advanced Magboots' slow you down in simulated-gravity environments much like the standard issue variety."
item = /obj/item/clothing/shoes/magboots/syndie
cost = 2
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/c4
name = "Composition C-4"
@@ -1004,6 +1075,18 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/device/sbeacondrop/bomb
cost = 11
/datum/uplink_item/device_tools/clown_bomb_clownops
name = "Clown Bomb"
desc = "The Clown bomb is a hilarious device capable of massive pranks. It has an adjustable timer, \
with a minimum of 60 seconds, and can be bolted to the floor with a wrench to prevent \
movement. The bomb is bulky and cannot be moved; upon ordering this item, a smaller beacon will be \
transported to you that will teleport the actual bomb to it upon activation. Note that this bomb can \
be defused, and some crew may attempt to do so."
item = /obj/item/device/sbeacondrop/clownbomb
cost = 15
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/syndicate_detonator
name = "Syndicate Detonator"
desc = "The Syndicate detonator is a companion device to the Syndicate bomb. Simply press the included button \
@@ -1012,7 +1095,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
the blast radius before using the detonator."
item = /obj/item/device/syndicatedetonator
cost = 3
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/rad_laser
name = "Radioactive Microlaser"
@@ -1029,7 +1112,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/device/assault_pod
cost = 30
surplus = 0
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/shield
name = "Energy Shield"
@@ -1040,20 +1123,30 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
surplus = 20
include_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/device_tools/shield
name = "Bananium Energy Shield"
desc = "A clown's most powerful defensive weapon, this personal shield provides near immunity to ranged energy attacks \
by bouncing them back at the ones who fired them. It can also be thrown to bounce off of people, slipping them, \
and returning to you even if you miss. WARNING: DO NOT ATTEMPT TO STAND ON SHIELD WHILE DEPLOYED, EVEN IF WEARING ANTI-SLIP SHOES."
item = /obj/item/shield/energy/bananium
cost = 16
surplus = 0
include_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/medgun
name = "Medbeam Gun"
desc = "A wonder of Syndicate engineering, the Medbeam gun, or Medi-Gun enables a medic to keep his fellow \
operatives in the fight, even while under fire."
item = /obj/item/gun/medbeam
cost = 15
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/potion
name = "Syndicate Sentience Potion"
item = /obj/item/slimepotion/slime/sentience/nuclear
desc = "A potion recovered at great risk by undercover syndicate operatives and then subsequently modified with syndicate technology. Using it will make any animal sentient, and bound to serve you, as well as implanting an internal radio for communication and an internal ID card for opening doors."
cost = 4
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/device_tools/telecrystal
name = "Raw Telecrystal"
@@ -1189,7 +1282,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
// Role-specific items
/datum/uplink_item/role_restricted
category = "Role-Restricted"
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
surplus = 0
/datum/uplink_item/role_restricted/reverse_revolver
@@ -1346,7 +1439,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/badass/costumes
surplus = 0
include_modes = list(/datum/game_mode/nuclear)
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
cost = 4
cant_discount = TRUE
@@ -1382,7 +1475,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/structure/closet/crate
cost = 20
player_minimum = 25
exclude_modes = list(/datum/game_mode/nuclear)
exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
cant_discount = TRUE
var/starting_crate_value = 50