@@ -2372,7 +2372,7 @@
|
||||
},
|
||||
/area/awaymission/BMPship/Midship)
|
||||
"hh" = (
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/turf/open/floor/plating/airless,
|
||||
/area/awaymission/BMPship/Midship)
|
||||
"hi" = (
|
||||
|
||||
@@ -2710,7 +2710,7 @@
|
||||
/obj/structure/cable{
|
||||
icon_state = "4-8"
|
||||
},
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/effect/turf_decal/tile/green,
|
||||
/obj/effect/turf_decal/tile/green{
|
||||
dir = 4
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
/obj/structure/janitorialcart,
|
||||
/obj/item/mop,
|
||||
/obj/item/reagent_containers/glass/bucket,
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/open/floor/plating,
|
||||
/area/awaymission/cabin)
|
||||
|
||||
@@ -11030,18 +11030,12 @@
|
||||
/obj/structure/closet/crate/coffin,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/port/fore)
|
||||
"axo" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
"axp" = (
|
||||
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"axq" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 4
|
||||
@@ -11440,10 +11434,6 @@
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
"ayC" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/turf/closed/wall,
|
||||
/area/maintenance/fore)
|
||||
"ayD" = (
|
||||
/obj/effect/spawner/structure/window/reinforced,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
@@ -14255,10 +14245,6 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
"aGh" = (
|
||||
/obj/effect/landmark/event_spawn,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
"aGi" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/turf/open/floor/plasteel/dark,
|
||||
@@ -45279,7 +45265,7 @@
|
||||
/area/maintenance/aft)
|
||||
"cfq" = (
|
||||
/obj/structure/mopbucket,
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/aft)
|
||||
"cfr" = (
|
||||
@@ -53350,7 +53336,7 @@
|
||||
},
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"ddM" = (
|
||||
/obj/structure/sign/poster/official/the_owl{
|
||||
pixel_x = 32
|
||||
@@ -53734,7 +53720,7 @@
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"edA" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 4
|
||||
@@ -54930,7 +54916,7 @@
|
||||
"gKG" = (
|
||||
/obj/structure/bedsheetbin/towel,
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"gLz" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-2"
|
||||
@@ -56208,7 +56194,7 @@
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt/dust,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"jJF" = (
|
||||
/obj/machinery/door/airlock/maintenance,
|
||||
/obj/structure/cable{
|
||||
@@ -56998,7 +56984,7 @@
|
||||
dir = 8
|
||||
},
|
||||
/turf/closed/wall,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"lzt" = (
|
||||
/obj/machinery/portable_atmospherics/pump,
|
||||
/obj/effect/turf_decal/stripes/line,
|
||||
@@ -57590,7 +57576,7 @@
|
||||
},
|
||||
/obj/structure/reagent_dispensers/watertank,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"nbT" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "0-8"
|
||||
@@ -59057,7 +59043,7 @@
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"qIw" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
|
||||
dir = 4
|
||||
@@ -59648,12 +59634,6 @@
|
||||
},
|
||||
/turf/open/floor/plasteel/dark,
|
||||
/area/medical/paramedic)
|
||||
"rWw" = (
|
||||
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
"rXl" = (
|
||||
/obj/structure/chair/office/light,
|
||||
/obj/machinery/firealarm{
|
||||
@@ -59773,7 +59753,7 @@
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"sqg" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/clothing/under/misc/pj/red,
|
||||
@@ -60210,7 +60190,7 @@
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/wood/wood_diagonal,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"trb" = (
|
||||
/obj/machinery/light{
|
||||
dir = 4
|
||||
@@ -60628,7 +60608,7 @@
|
||||
/obj/structure/girder,
|
||||
/obj/structure/grille,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/fore)
|
||||
/area/maintenance/port/fore)
|
||||
"ugu" = (
|
||||
/obj/structure/cable{
|
||||
icon_state = "1-4"
|
||||
@@ -82433,7 +82413,7 @@ lZN
|
||||
amC
|
||||
jIW
|
||||
ddI
|
||||
arP
|
||||
alU
|
||||
fgG
|
||||
rqW
|
||||
aGD
|
||||
@@ -82684,13 +82664,13 @@ amC
|
||||
htu
|
||||
alU
|
||||
edj
|
||||
rWw
|
||||
ygb
|
||||
gKG
|
||||
arP
|
||||
aqR
|
||||
awb
|
||||
alU
|
||||
amC
|
||||
ntt
|
||||
ugq
|
||||
arP
|
||||
alU
|
||||
rPU
|
||||
fne
|
||||
aGr
|
||||
@@ -82943,11 +82923,11 @@ alU
|
||||
tqG
|
||||
spR
|
||||
qGw
|
||||
arP
|
||||
aGh
|
||||
awb
|
||||
axo
|
||||
arP
|
||||
alU
|
||||
aFJ
|
||||
ntt
|
||||
aAY
|
||||
alU
|
||||
aCh
|
||||
pIf
|
||||
kCo
|
||||
@@ -83197,14 +83177,14 @@ ali
|
||||
ali
|
||||
ali
|
||||
alU
|
||||
arP
|
||||
alU
|
||||
lzk
|
||||
arP
|
||||
arP
|
||||
arP
|
||||
avZ
|
||||
alU
|
||||
alU
|
||||
alU
|
||||
atO
|
||||
axp
|
||||
ayC
|
||||
aue
|
||||
azH
|
||||
eEe
|
||||
aGv
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10679,7 +10679,7 @@
|
||||
light_color = "#e8eaff"
|
||||
},
|
||||
/obj/machinery/vending/wardrobe/jani_wardrobe{
|
||||
products = list(/obj/item/clothing/under/rank/civilian/janitor = 2, /obj/item/cartridge/janitor = 2, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, /obj/item/flashlight = 2, /obj/item/caution = 10, /obj/item/holosign_creator = 2, /obj/item/lightreplacer = 2, /obj/item/soap/nanotrasen = 2, /obj/item/storage/bag/trash = 2, /obj/item/clothing/shoes/galoshes = 2, /obj/item/watertank/janitor = 2, /obj/item/storage/belt/janitor = 2)
|
||||
products = list(/obj/item/clothing/under/rank/civilian/janitor = 2, /obj/item/cartridge/janitor = 2, /obj/item/clothing/gloves/color/black = 2, /obj/item/clothing/head/soft/purple = 2, /obj/item/paint/paint_remover = 2, /obj/item/melee/flyswatter = 2, /obj/item/flashlight = 2, /obj/item/clothing/suit/caution = 10, /obj/item/holosign_creator = 2, /obj/item/lightreplacer = 2, /obj/item/soap/nanotrasen = 2, /obj/item/storage/bag/trash = 2, /obj/item/clothing/shoes/galoshes = 2, /obj/item/watertank/janitor = 2, /obj/item/storage/belt/janitor = 2)
|
||||
},
|
||||
/turf/open/floor/plating,
|
||||
/area/janitor)
|
||||
@@ -13637,7 +13637,7 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/hallway/primary/central)
|
||||
"IX" = (
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24603,7 +24603,7 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/department/cargo)
|
||||
"beS" = (
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/department/cargo)
|
||||
"beU" = (
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
//donator items
|
||||
#define LOADOUT_CATEGORY_DONATOR "Donator"
|
||||
|
||||
//unlockable items
|
||||
#define LOADOUT_CATEGORY_UNLOCKABLE "Unlockable"
|
||||
|
||||
//how many prosthetics can we have
|
||||
#define MAXIMUM_LOADOUT_PROSTHETICS 2
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define SPECIES_ANDROID "android"
|
||||
#define SPECIES_ANGEL "angel"
|
||||
#define SPECIES_MAMMAL "mammal"
|
||||
#define SPECIES_MAMMAL_SYNTHETIC "mammal_synthetic"
|
||||
#define SPECIES_ARACHNID "arachnid"
|
||||
#define SPECIES_INSECT "insect"
|
||||
#define SPECIES_DULLAHAN "dullahan"
|
||||
|
||||
@@ -86,10 +86,6 @@
|
||||
if (CONFIG_GET(flag/log_attack))
|
||||
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
|
||||
|
||||
/proc/log_wounded(text)
|
||||
if (CONFIG_GET(flag/log_attack))
|
||||
WRITE_LOG(GLOB.world_attack_log, "WOUND: [text]")
|
||||
|
||||
/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE)
|
||||
if (CONFIG_GET(flag/log_manifest))
|
||||
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
|
||||
|
||||
@@ -238,8 +238,11 @@
|
||||
CHECK_TICK
|
||||
SSdbcore.SetRoundEnd()
|
||||
//Collects persistence features
|
||||
if(mode.allow_persistence_save)
|
||||
SSpersistence.CollectData()
|
||||
if(mode.station_was_nuked)
|
||||
SSpersistence.station_was_destroyed = TRUE
|
||||
if(!mode.allow_persistence_save)
|
||||
SSpersistence.station_persistence_save_disabled = TRUE
|
||||
SSpersistence.CollectData()
|
||||
|
||||
//stop collecting feedback during grifftime
|
||||
SSblackbox.Seal()
|
||||
|
||||
@@ -275,7 +275,7 @@ GLOBAL_LIST_INIT(wisdoms, world.file2list("strings/wisdoms.txt"))
|
||||
|
||||
//LANGUAGE CHARACTER CUSTOMIZATION
|
||||
GLOBAL_LIST_INIT(speech_verbs, list("default","says","gibbers", "states", "chitters", "chimpers", "declares", "bellows", "buzzes" ,"beeps", "chirps", "clicks", "hisses" ,"poofs" , "puffs", "rattles", "mewls" ,"barks", "blorbles", "squeaks", "squawks", "flutters", "warbles"))
|
||||
GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/organ/tongue, "lizard tongue" = /obj/item/organ/tongue/lizard, "skeleton tongue" = /obj/item/organ/tongue/bone, "fly tongue" = /obj/item/organ/tongue/fly, "ipc tongue" = /obj/item/organ/tongue/robot/ipc))
|
||||
GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/organ/tongue, "lizard tongue" = /obj/item/organ/tongue/lizard, "skeleton tongue" = /obj/item/organ/tongue/bone, "fly tongue" = /obj/item/organ/tongue/fly, "ipc tongue" = /obj/item/organ/tongue/robot/ipc, "xeno tongue" = /obj/item/organ/tongue/alien))
|
||||
|
||||
//SPECIES BODYPART LISTS
|
||||
//locked parts are those that your picked species requires to have
|
||||
|
||||
@@ -9,5 +9,6 @@ GLOBAL_LIST_INIT(loadout_categories, list(
|
||||
LOADOUT_CATEGORY_SHOES = LOADOUT_SUBCATEGORIES_NONE,
|
||||
LOADOUT_CATEGORY_GLOVES = LOADOUT_SUBCATEGORIES_NONE,
|
||||
LOADOUT_CATEGORY_GLASSES = LOADOUT_SUBCATEGORIES_NONE,
|
||||
LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE
|
||||
LOADOUT_CATEGORY_DONATOR = LOADOUT_SUBCATEGORIES_NONE,
|
||||
LOADOUT_CATEGORY_UNLOCKABLE = LOADOUT_SUBCATEGORIES_NONE
|
||||
))
|
||||
|
||||
@@ -566,3 +566,20 @@
|
||||
config_entry_value = 0.333
|
||||
min_val = 0
|
||||
integer = FALSE
|
||||
|
||||
/// Amount of dirtyness tiles need to spawn dirt.
|
||||
/datum/config_entry/number/turf_dirt_threshold
|
||||
config_entry_value = 100
|
||||
min_val = 1
|
||||
integer = TRUE
|
||||
|
||||
/// Alpha dirt starts at
|
||||
/datum/config_entry/number/dirt_alpha_starting
|
||||
config_entry_value = 127
|
||||
max_val = 255
|
||||
min_val = 0
|
||||
integer = TRUE
|
||||
|
||||
/// Dirtyness multiplier for making turfs dirty
|
||||
/datum/config_entry/number/turf_dirty_multiplier
|
||||
config_entry_value = 1
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/// Whether or not to use the persistence system for cleanable objects
|
||||
/datum/config_entry/flag/persistent_debris
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Whether or not to nuke all roundstart debris that isn't due to persistence if the above is true
|
||||
/datum/config_entry/flag/persistent_debris_only
|
||||
config_entry_value = TRUE
|
||||
|
||||
/// Max amount of objects to store, total
|
||||
/datum/config_entry/number/persistent_debris_global_max
|
||||
config_entry_value = 10000
|
||||
integer = TRUE
|
||||
|
||||
/// Max amount of objects to store per type
|
||||
/datum/config_entry/number/persistent_debris_type_max
|
||||
config_entry_value = 2000
|
||||
integer = TRUE
|
||||
|
||||
/// Wipe dirty stuff on nuke
|
||||
/datum/config_entry/flag/persistent_debris_wipe_on_nuke
|
||||
@@ -115,18 +115,22 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
lastlevel = level
|
||||
|
||||
for (var/refID in queue)
|
||||
if (!refID)
|
||||
//We do this rather then for(var/refID in queue) because that sort of for loop copies the whole list.
|
||||
//Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun.
|
||||
for (var/i in 1 to length(queue))
|
||||
var/list/L = queue[i]
|
||||
if (length(L) < 2)
|
||||
count++
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
var/GCd_at_time = queue[refID]
|
||||
var/GCd_at_time = L[1]
|
||||
if(GCd_at_time > cut_off_time)
|
||||
break // Everything else is newer, skip them
|
||||
count++
|
||||
|
||||
var/refID = L[2]
|
||||
var/datum/D
|
||||
D = locate(refID)
|
||||
|
||||
@@ -202,10 +206,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
D.gc_destroyed = gctime
|
||||
var/list/queue = queues[level]
|
||||
if (queue[refid])
|
||||
queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list.
|
||||
|
||||
queue[refid] = gctime
|
||||
queue[++queue.len] = list(gctime, refid) // not += for byond reasons
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
/datum/controller/subsystem/garbage/proc/add_type_to_findref(type)
|
||||
|
||||
@@ -698,6 +698,8 @@ SUBSYSTEM_DEF(job)
|
||||
if(polychromic && istype(polychromic))
|
||||
var/list/polychromic_entry = polychromic.colors_by_atom[I]
|
||||
if(polychromic_entry)
|
||||
if(polychromic.suits_with_helmet_typecache[I.type]) //is this one of those toggleable hood/helmet things?
|
||||
polychromic.connect_helmet(I,i[LOADOUT_COLOR])
|
||||
polychromic.colors_by_atom[I] = i[LOADOUT_COLOR]
|
||||
I.update_icon()
|
||||
else
|
||||
|
||||
@@ -41,6 +41,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/datum/space_level/transit
|
||||
var/datum/space_level/empty_space
|
||||
var/num_of_res_levels = 1
|
||||
/// Lookup for zlevel to station z. text = num.
|
||||
var/list/z_to_station_z_index
|
||||
|
||||
var/stat_map_name = "Loading..."
|
||||
|
||||
@@ -259,6 +261,16 @@ SUBSYSTEM_DEF(mapping)
|
||||
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
|
||||
return parsed_maps
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/setup_station_z_index()
|
||||
z_to_station_z_index = list()
|
||||
var/sz = 1
|
||||
var/cz = station_start
|
||||
if(islist(config.map_file))
|
||||
for(var/map in config.map_file)
|
||||
z_to_station_z_index["[cz++]"] = sz++
|
||||
else
|
||||
z_to_station_z_index["[station_start]"] = 1
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/loadWorld()
|
||||
//if any of these fail, something has gone horribly, HORRIBLY, wrong
|
||||
var/list/FailedZs = list()
|
||||
@@ -271,6 +283,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
INIT_ANNOUNCE("Loading [config.map_name]...")
|
||||
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION, FALSE, config.orientation)
|
||||
|
||||
setup_station_z_index()
|
||||
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
|
||||
query_round_map_name.Execute()
|
||||
|
||||
+70
-272
@@ -5,18 +5,14 @@ SUBSYSTEM_DEF(persistence)
|
||||
name = "Persistence"
|
||||
init_order = INIT_ORDER_PERSISTENCE
|
||||
flags = SS_NO_FIRE
|
||||
var/list/satchel_blacklist = list() //this is a typecache
|
||||
var/list/new_secret_satchels = list() //these are objects
|
||||
var/list/old_secret_satchels = list()
|
||||
|
||||
/// Marks if the station got horribly destroyed
|
||||
var/station_was_destroyed = FALSE
|
||||
/// Marks if persistence save should be disabled
|
||||
var/station_persistence_save_disabled = FALSE
|
||||
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/list/saved_modes = list(1,2,3)
|
||||
var/list/saved_dynamic_rules = list(list(),list(),list())
|
||||
var/list/saved_storytellers = list("foo","bar","baz")
|
||||
var/list/average_dynamic_threat = 50
|
||||
var/list/saved_maps
|
||||
var/list/saved_trophies = list()
|
||||
var/list/spawned_objects = list()
|
||||
var/list/antag_rep = list()
|
||||
var/list/antag_rep_change = list()
|
||||
@@ -28,62 +24,81 @@ SUBSYSTEM_DEF(persistence)
|
||||
var/list/paintings = list()
|
||||
|
||||
/datum/controller/subsystem/persistence/Initialize()
|
||||
LoadSatchels()
|
||||
LoadPoly()
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
LoadRecentModes()
|
||||
LoadRecentStorytellers()
|
||||
LoadRecentRulesets()
|
||||
LoadRecentMaps()
|
||||
LoadPhotoPersistence()
|
||||
LoadServerPersistence()
|
||||
LoadGamePersistence()
|
||||
var/map_persistence_path = get_map_persistence_path()
|
||||
if(map_persistence_path)
|
||||
LoadMapPersistence()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Gets the persistence path of the current map.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/get_map_persistence_path()
|
||||
ASSERT(SSmapping.config)
|
||||
if(!SSmapping.config.persistence_key || (SSmapping.config.persistence_key == "NO_PERSIST"))
|
||||
return null
|
||||
return "data/persistence/[ckey(SSmapping.config.persistence_key)]"
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectData()
|
||||
SaveServerPersistence()
|
||||
if(station_persistence_save_disabled)
|
||||
return
|
||||
SaveGamePersistence()
|
||||
var/map_persistence_path = get_map_persistence_path()
|
||||
if(map_persistence_path)
|
||||
SaveMapPersistence()
|
||||
|
||||
/**
|
||||
* Loads persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/LoadServerPersistence()
|
||||
for(var/client/C in GLOB.clients)
|
||||
LoadSavedVote(C.ckey)
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
LoadAntagReputation()
|
||||
LoadRandomizedRecipes()
|
||||
LoadPanicBunker()
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadSatchels()
|
||||
var/placed_satchel = 0
|
||||
var/path
|
||||
/**
|
||||
* Saves persistent data relevant to the server: Configurations, past gamemodes, votes, antag rep, etc
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/SaveServerPersistence()
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
CollectAntagReputation()
|
||||
SaveRandomizedRecipes()
|
||||
|
||||
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
|
||||
var/list/json = list()
|
||||
if(fexists(json_file))
|
||||
json = json_decode(file2text(json_file))
|
||||
/**
|
||||
* Loads persistent data relevant to the game in general: Photos, etc
|
||||
*
|
||||
* Legacy map persistence systems also use this.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/LoadGamePersistence()
|
||||
LoadChiselMessages()
|
||||
LoadPhotoPersistence()
|
||||
LoadPaintings()
|
||||
|
||||
old_secret_satchels = json["data"]
|
||||
var/obj/item/storage/backpack/satchel/flat/F
|
||||
if(old_secret_satchels && old_secret_satchels.len >= 10) //guards against low drop pools assuring that one player cannot reliably find his own gear.
|
||||
var/pos = rand(1, old_secret_satchels.len)
|
||||
F = new()
|
||||
old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
|
||||
F.x = old_secret_satchels[pos]["x"]
|
||||
F.y = old_secret_satchels[pos]["y"]
|
||||
F.z = SSmapping.station_start
|
||||
path = text2path(old_secret_satchels[pos]["saved_obj"])
|
||||
/**
|
||||
* Saves persistent data relevant to the game in general: Photos, etc
|
||||
*
|
||||
* Legacy map persistence systems also use this.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/SaveGamePersistence()
|
||||
CollectChiselMessages()
|
||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||
SavePaintings()
|
||||
SaveScars()
|
||||
|
||||
if(F)
|
||||
if(isfloorturf(F.loc) && !isplatingturf(F.loc))
|
||||
F.hide(1)
|
||||
if(ispath(path))
|
||||
var/spawned_item = new path(F)
|
||||
spawned_objects[spawned_item] = TRUE
|
||||
placed_satchel++
|
||||
var/free_satchels = 0
|
||||
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,SSmapping.station_start), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,SSmapping.station_start)))) //Nontrivially expensive but it's roundstart only
|
||||
if(isfloorturf(T) && !isplatingturf(T))
|
||||
new /obj/item/storage/backpack/satchel/flat/secret(T)
|
||||
free_satchels++
|
||||
if((free_satchels + placed_satchel) == 10) //ten tiles, more than enough to kill anything that moves
|
||||
break
|
||||
/**
|
||||
* Loads persistent data relevant to the current map: Objects, etc.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/LoadMapPersistence()
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadPoly()
|
||||
for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.alive_mob_list)
|
||||
twitterize(P.speech_buffer, "polytalk")
|
||||
break //Who's been duping the bird?!
|
||||
/**
|
||||
* Saves persistent data relevant to the current map: Objects, etc.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/proc/SaveMapPersistence()
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
|
||||
var/list/saved_messages = list()
|
||||
@@ -130,63 +145,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadTrophies()
|
||||
if(fexists("data/npc_saves/TrophyItems.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/TrophyItems.sav")
|
||||
var/saved_json
|
||||
S >> saved_json
|
||||
if(!saved_json)
|
||||
return
|
||||
saved_trophies = json_decode(saved_json)
|
||||
fdel("data/npc_saves/TrophyItems.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/TrophyItems.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_trophies = json["data"]
|
||||
SetUpTrophies(saved_trophies.Copy())
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentModes()
|
||||
var/json_file = file("data/RecentModes.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_modes = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_dynamic_rules = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers()
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_storytellers = json["data"]
|
||||
if(saved_storytellers.len > 3)
|
||||
average_dynamic_threat = saved_storytellers[4]
|
||||
saved_storytellers.len = 3
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_maps = json["maps"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadAntagReputation()
|
||||
var/json = file2text(FILE_ANTAG_REP)
|
||||
@@ -207,59 +165,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
saved_votes[ckey] = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
if (T.showpiece)
|
||||
continue
|
||||
T.added_roundstart = TRUE
|
||||
|
||||
var/trophy_data = pick_n_take(trophy_items)
|
||||
|
||||
if(!islist(trophy_data))
|
||||
continue
|
||||
|
||||
var/list/chosen_trophy = trophy_data
|
||||
|
||||
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
|
||||
continue
|
||||
|
||||
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
continue
|
||||
|
||||
T.showpiece = new /obj/item/showpiece_dummy(T, path)
|
||||
T.trophy_message = chosen_trophy["message"]
|
||||
T.placer_key = chosen_trophy["placer_key"]
|
||||
T.update_icon()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectData()
|
||||
CollectChiselMessages()
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
CollectRoundtype()
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
CollectStoryteller(mode)
|
||||
CollectRulesets(mode)
|
||||
RecordMaps()
|
||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
CollectAntagReputation()
|
||||
SaveRandomizedRecipes()
|
||||
SavePanicBunker()
|
||||
SavePaintings()
|
||||
SaveScars()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
|
||||
var/bunker_path = file("data/bunker_passthrough.json")
|
||||
if(fexists(bunker_path))
|
||||
var/list/json = json_decode(file2text(bunker_path))
|
||||
GLOB.bunker_passthrough = json["data"]
|
||||
for(var/ckey in GLOB.bunker_passthrough)
|
||||
if(daysSince(GLOB.bunker_passthrough[ckey]) >= CONFIG_GET(number/max_bunker_days))
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/GetPhotoAlbums()
|
||||
var/album_path = file("data/photo_albums.json")
|
||||
if(fexists(album_path))
|
||||
@@ -329,35 +234,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
WRITE_FILE(frame_path, frame_json)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
|
||||
var/list/satchels_to_add = list()
|
||||
for(var/A in new_secret_satchels)
|
||||
var/obj/item/storage/backpack/satchel/flat/F = A
|
||||
if(QDELETED(F) || F.z != SSmapping.station_start || F.invisibility != INVISIBILITY_MAXIMUM)
|
||||
continue
|
||||
var/list/savable_obj = list()
|
||||
for(var/obj/O in F)
|
||||
if(is_type_in_typecache(O, satchel_blacklist) || (O.flags_1 & ADMIN_SPAWNED_1))
|
||||
continue
|
||||
if(O.persistence_replacement)
|
||||
savable_obj += O.persistence_replacement
|
||||
else
|
||||
savable_obj += O.type
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
var/list/data = list()
|
||||
data["x"] = F.x
|
||||
data["y"] = F.y
|
||||
data["saved_obj"] = pick(savable_obj)
|
||||
satchels_to_add += list(data)
|
||||
|
||||
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
|
||||
var/list/file_data = list()
|
||||
fdel(json_file)
|
||||
file_data["data"] = old_secret_satchels + satchels_to_add
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
|
||||
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
|
||||
|
||||
@@ -373,84 +249,6 @@ SUBSYSTEM_DEF(persistence)
|
||||
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
var/json_file = file("data/npc_saves/TrophyItems.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = remove_duplicate_trophies(saved_trophies)
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SavePanicBunker()
|
||||
var/json_file = file("data/bunker_passthrough.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = GLOB.bunker_passthrough
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file,json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies)
|
||||
var/list/ukeys = list()
|
||||
. = list()
|
||||
for(var/trophy in trophies)
|
||||
var/tkey = "[trophy["path"]]-[trophy["message"]]"
|
||||
if(ukeys[tkey])
|
||||
continue
|
||||
else
|
||||
. += list(trophy)
|
||||
ukeys[tkey] = TRUE
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
var/list/data = list()
|
||||
data["path"] = T.showpiece.type
|
||||
data["message"] = T.trophy_message
|
||||
data["placer_key"] = T.placer_key
|
||||
saved_trophies += list(data)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectRoundtype()
|
||||
saved_modes[3] = saved_modes[2]
|
||||
saved_modes[2] = saved_modes[1]
|
||||
saved_modes[1] = SSticker.mode.config_tag
|
||||
var/json_file = file("data/RecentModes.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_modes
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
|
||||
saved_storytellers.len = 3
|
||||
saved_storytellers[3] = saved_storytellers[2]
|
||||
saved_storytellers[2] = saved_storytellers[1]
|
||||
saved_storytellers[1] = mode.storyteller.name
|
||||
average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_storytellers + average_dynamic_threat
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectRulesets(var/datum/game_mode/dynamic/mode)
|
||||
saved_dynamic_rules[3] = saved_dynamic_rules[2]
|
||||
saved_dynamic_rules[2] = saved_dynamic_rules[1]
|
||||
saved_dynamic_rules[1] = list()
|
||||
for(var/r in mode.executed_rules)
|
||||
var/datum/dynamic_ruleset/rule = r
|
||||
saved_dynamic_rules[1] += rule.config_tag
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_dynamic_rules
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/RecordMaps()
|
||||
saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
var/list/file_data = list()
|
||||
file_data["maps"] = saved_maps
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectAntagReputation()
|
||||
var/ANTAG_REP_MAXIMUM = CONFIG_GET(number/antag_rep_maximum)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Persistence for cleanable debris.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence
|
||||
/// tracks if we already loaded debris. Unlike everything else, this can actually be a major problem if some badmin procs it twice.
|
||||
var/loaded_debris = FALSE
|
||||
|
||||
/datum/controller/subsystem/persistence/LoadMapPersistence()
|
||||
. = ..()
|
||||
if(CONFIG_GET(flag/persistent_debris))
|
||||
LoadMapDebris()
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveMapPersistence()
|
||||
. = ..()
|
||||
if(CONFIG_GET(flag/persistent_debris))
|
||||
SaveMapDebris()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadMapDebris()
|
||||
if(CONFIG_GET(flag/persistent_debris_only))
|
||||
wipe_existing_debris()
|
||||
if(!fexists("[get_map_persistence_path()]/debris.json"))
|
||||
return
|
||||
if(loaded_debris)
|
||||
return
|
||||
loaded_debris = TRUE
|
||||
var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space)
|
||||
var/list/allowed_z_cache = list()
|
||||
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
allowed_z_cache[num2text(z)] = TRUE
|
||||
var/list/data = json_decode(file2text("[get_map_persistence_path()]/debris.json"))
|
||||
var/list/z_lookup = list()
|
||||
var/loaded = 0
|
||||
var/list/loaded_by_type = list()
|
||||
var/nopath = 0
|
||||
var/badloc = 0
|
||||
var/noturf = 0
|
||||
/// reverse it
|
||||
for(var/z in SSmapping.z_to_station_z_index)
|
||||
var/sz = SSmapping.z_to_station_z_index[z]
|
||||
z_lookup[num2text(sz)] = text2num(z)
|
||||
for(var/z in data)
|
||||
var/actual_z = z_lookup[z]
|
||||
var/list/L1 = data[z]
|
||||
for(var/x in L1)
|
||||
var/list/L2 = data[z][x]
|
||||
for(var/y in L2)
|
||||
var/turf/tile = locate(text2num(x), text2num(y), actual_z)
|
||||
if(!tile)
|
||||
noturf++
|
||||
continue
|
||||
var/list/objects = data[z][x][y]
|
||||
for(var/_L in objects)
|
||||
var/list/objdata
|
||||
var/path
|
||||
if(islist(_L))
|
||||
objdata = _L
|
||||
path = text2path(objdata["__PATH__"])
|
||||
else
|
||||
path = text2path(_L)
|
||||
objdata = objects[_L]
|
||||
if(!path)
|
||||
nopath++
|
||||
continue
|
||||
if(!IsValidDebrisLocation(tile, allowed_turf_typecache, allowed_z_cache, path, TRUE))
|
||||
badloc++
|
||||
continue
|
||||
var/obj/effect/decal/cleanable/instantiated = new path(tile)
|
||||
loaded_by_type[path] += 1
|
||||
loaded++
|
||||
if(objdata)
|
||||
instantiated.PersistenceLoad(objdata)
|
||||
var/list/bytype = list()
|
||||
for(var/path in loaded_by_type)
|
||||
bytype += "[path] - [loaded_by_type[path]]"
|
||||
subsystem_log(
|
||||
{"Debris loading completed:
|
||||
Errors:
|
||||
No path: [nopath]
|
||||
Invalid location: [badloc]
|
||||
No turf on map: [noturf]
|
||||
Total loaded: [loaded]
|
||||
By type:
|
||||
[bytype.Join("\n")]"}
|
||||
)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveMapDebris()
|
||||
if(fexists("[get_map_persistence_path()]/debris.json"))
|
||||
fdel("[get_map_persistence_path()]/debris.json")
|
||||
if(CONFIG_GET(flag/persistent_debris_wipe_on_nuke) && station_was_destroyed)
|
||||
return // local janitor cheers on nukeop team to save some work
|
||||
var/list/data = list()
|
||||
var/list/z_lookup = SSmapping.z_to_station_z_index
|
||||
var/list/debris = RelevantPersistentDebris()
|
||||
var/obj/effect/decal/cleanable/saving
|
||||
var/global_max = CONFIG_GET(number/persistent_debris_global_max)
|
||||
var/type_max = CONFIG_GET(number/persistent_debris_type_max)
|
||||
var/stored = 0
|
||||
var/list/stored_by_type = list()
|
||||
for(var/i in debris)
|
||||
saving = i
|
||||
var/list/serializing = list()
|
||||
var/path = saving.PersistenceSave(serializing)
|
||||
if(!path)
|
||||
continue
|
||||
if(stored_by_type[path] > type_max)
|
||||
continue
|
||||
var/text_z = num2text(z_lookup[num2text(saving.z)])
|
||||
var/text_y = num2text(saving.y)
|
||||
var/text_x = num2text(saving.x)
|
||||
LAZYINITLIST(data[text_z])
|
||||
LAZYINITLIST(data[text_z][text_x])
|
||||
LAZYINITLIST(data[text_z][text_x][text_y])
|
||||
if(saving.persistence_allow_stacking)
|
||||
serializing["__PATH__"] = path
|
||||
data[text_z][text_x][text_y] += list(serializing)
|
||||
else
|
||||
data[text_z][text_x][text_y][path] = serializing
|
||||
stored++
|
||||
if(stored > global_max)
|
||||
var/w = "Persistent debris saving globally aborted due to global max >= [global_max]. Either janitors never do their jobs or something is wrong."
|
||||
message_admins(w)
|
||||
subsystem_log(w)
|
||||
return
|
||||
stored_by_type[path] = stored_by_type[path]? stored_by_type[path] + 1 : 1
|
||||
if(stored_by_type[path] > type_max)
|
||||
var/w = "Persistent debris saving aborted for type [path] due to type max >= [global_max]. Either janitors never do their jobs or something is wrong."
|
||||
message_admins(w)
|
||||
subsystem_log(w)
|
||||
|
||||
var/list/bytype = list()
|
||||
for(var/path in stored_by_type)
|
||||
bytype += "[path] - [stored_by_type[path]]"
|
||||
subsystem_log(
|
||||
{"Debris saving completed:
|
||||
Total: [stored]
|
||||
By type:
|
||||
[bytype.Join("\n")]"}
|
||||
)
|
||||
WRITE_FILE(file("[get_map_persistence_path()]/debris.json"), json_encode(data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/IsValidDebrisLocation(turf/tile, list/allowed_typecache, list/allowed_zcache, obj/effect/decal/cleanable/type, loading = FALSE)
|
||||
if(!allowed_typecache[tile.type])
|
||||
return FALSE
|
||||
var/area/A = tile.loc
|
||||
if(!A.persistent_debris_allowed)
|
||||
return FALSE
|
||||
if(!allowed_zcache[num2text(tile.z)])
|
||||
return FALSE
|
||||
if(loading)
|
||||
if(!initial(type.persistence_allow_stacking))
|
||||
var/obj/effect/decal/cleanable/C = locate(type) in tile
|
||||
if(!QDELETED(C))
|
||||
return FALSE
|
||||
// Saving verifies allow stacking in the save proc.
|
||||
for(var/obj/structure/window/W in tile)
|
||||
if(W.fulltile)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/wipe_existing_debris()
|
||||
var/list/existing = RelevantPersistentDebris()
|
||||
QDEL_LIST(existing)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/RelevantPersistentDebris()
|
||||
var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space)
|
||||
var/list/allowed_z_cache = list()
|
||||
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
allowed_z_cache[num2text(z)] = TRUE
|
||||
. = list()
|
||||
for(var/obj/effect/decal/cleanable/C in world)
|
||||
if(!C.loc || QDELETED(C))
|
||||
continue
|
||||
if(!C.persistent)
|
||||
continue
|
||||
if(!IsValidDebrisLocation(C.loc, allowed_turf_typecache, allowed_z_cache, C.type, FALSE))
|
||||
continue
|
||||
. += C
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Persists panic bunker whitelisting for a configured period of time
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/LoadServerPersistence()
|
||||
. = ..()
|
||||
LoadPanicBunker()
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveServerPersistence()
|
||||
. = ..()
|
||||
SavePanicBunker()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
|
||||
var/bunker_path = file("data/bunker_passthrough.json")
|
||||
if(fexists(bunker_path))
|
||||
var/list/json = json_decode(file2text(bunker_path))
|
||||
GLOB.bunker_passthrough = json["data"]
|
||||
for(var/ckey in GLOB.bunker_passthrough)
|
||||
if(daysSince(GLOB.bunker_passthrough[ckey]) >= CONFIG_GET(number/max_bunker_days))
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SavePanicBunker()
|
||||
var/json_file = file("data/bunker_passthrough.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = GLOB.bunker_passthrough
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file,json_encode(file_data))
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Persists poly messages across rounds
|
||||
*/
|
||||
/datum/controller/subsystem/persistence/LoadGamePersistence()
|
||||
. = ..()
|
||||
LoadPoly()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadPoly()
|
||||
for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.alive_mob_list)
|
||||
twitterize(P.speech_buffer, "polytalk")
|
||||
break //Who's been duping the bird?!
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Stores recently played gamemodes, maps, etc.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence
|
||||
var/list/saved_modes = list(1,2,3)
|
||||
var/list/saved_dynamic_rules = list(list(),list(),list())
|
||||
var/list/saved_storytellers = list("foo","bar","baz")
|
||||
var/list/average_dynamic_threat = 50
|
||||
var/list/saved_maps
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveServerPersistence()
|
||||
. = ..()
|
||||
CollectRoundtype()
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
CollectStoryteller(mode)
|
||||
CollectRulesets(mode)
|
||||
RecordMaps()
|
||||
|
||||
/datum/controller/subsystem/persistence/LoadServerPersistence()
|
||||
. = ..()
|
||||
LoadRecentModes()
|
||||
LoadRecentStorytellers()
|
||||
LoadRecentRulesets()
|
||||
LoadRecentMaps()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectRoundtype()
|
||||
saved_modes[3] = saved_modes[2]
|
||||
saved_modes[2] = saved_modes[1]
|
||||
saved_modes[1] = SSticker.mode.config_tag
|
||||
var/json_file = file("data/RecentModes.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_modes
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
|
||||
saved_storytellers.len = 3
|
||||
saved_storytellers[3] = saved_storytellers[2]
|
||||
saved_storytellers[2] = saved_storytellers[1]
|
||||
saved_storytellers[1] = mode.storyteller.name
|
||||
average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_storytellers + average_dynamic_threat
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectRulesets(var/datum/game_mode/dynamic/mode)
|
||||
saved_dynamic_rules[3] = saved_dynamic_rules[2]
|
||||
saved_dynamic_rules[2] = saved_dynamic_rules[1]
|
||||
saved_dynamic_rules[1] = list()
|
||||
for(var/r in mode.executed_rules)
|
||||
var/datum/dynamic_ruleset/rule = r
|
||||
saved_dynamic_rules[1] += rule.config_tag
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_dynamic_rules
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/RecordMaps()
|
||||
saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
var/list/file_data = list()
|
||||
file_data["maps"] = saved_maps
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentModes()
|
||||
var/json_file = file("data/RecentModes.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_modes = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_dynamic_rules = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers()
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_storytellers = json["data"]
|
||||
if(saved_storytellers.len > 3)
|
||||
average_dynamic_threat = saved_storytellers[4]
|
||||
saved_storytellers.len = 3
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_maps = json["maps"]
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Secret satchel persistence - allows storing of items in underfloor satchels that's loaded later.
|
||||
*/
|
||||
/datum/controller/subsystem/persistence
|
||||
var/list/satchel_blacklist = list() //this is a typecache
|
||||
var/list/new_secret_satchels = list() //these are objects
|
||||
var/list/old_secret_satchels = list()
|
||||
|
||||
/datum/controller/subsystem/persistence/LoadGamePersistence()
|
||||
. = ..()
|
||||
LoadSatchels()
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveGamePersistence()
|
||||
. = ..()
|
||||
CollectSecretSatchels()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadSatchels()
|
||||
var/placed_satchel = 0
|
||||
var/path
|
||||
|
||||
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
|
||||
var/list/json = list()
|
||||
if(fexists(json_file))
|
||||
json = json_decode(file2text(json_file))
|
||||
|
||||
old_secret_satchels = json["data"]
|
||||
var/obj/item/storage/backpack/satchel/flat/F
|
||||
if(old_secret_satchels && old_secret_satchels.len >= 10) //guards against low drop pools assuring that one player cannot reliably find his own gear.
|
||||
var/pos = rand(1, old_secret_satchels.len)
|
||||
F = new()
|
||||
old_secret_satchels.Cut(pos, pos+1 % old_secret_satchels.len)
|
||||
F.x = old_secret_satchels[pos]["x"]
|
||||
F.y = old_secret_satchels[pos]["y"]
|
||||
F.z = SSmapping.station_start
|
||||
path = text2path(old_secret_satchels[pos]["saved_obj"])
|
||||
|
||||
if(F)
|
||||
if(isfloorturf(F.loc) && !isplatingturf(F.loc))
|
||||
F.hide(1)
|
||||
if(ispath(path))
|
||||
var/spawned_item = new path(F)
|
||||
spawned_objects[spawned_item] = TRUE
|
||||
placed_satchel++
|
||||
var/free_satchels = 0
|
||||
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,SSmapping.station_start), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,SSmapping.station_start)))) //Nontrivially expensive but it's roundstart only
|
||||
if(isfloorturf(T) && !isplatingturf(T))
|
||||
new /obj/item/storage/backpack/satchel/flat/secret(T)
|
||||
free_satchels++
|
||||
if((free_satchels + placed_satchel) == 10) //ten tiles, more than enough to kill anything that moves
|
||||
break
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
|
||||
var/list/satchels_to_add = list()
|
||||
for(var/A in new_secret_satchels)
|
||||
var/obj/item/storage/backpack/satchel/flat/F = A
|
||||
if(QDELETED(F) || F.z != SSmapping.station_start || F.invisibility != INVISIBILITY_MAXIMUM)
|
||||
continue
|
||||
var/list/savable_obj = list()
|
||||
for(var/obj/O in F)
|
||||
if(is_type_in_typecache(O, satchel_blacklist) || (O.flags_1 & ADMIN_SPAWNED_1))
|
||||
continue
|
||||
if(O.persistence_replacement)
|
||||
savable_obj += O.persistence_replacement
|
||||
else
|
||||
savable_obj += O.type
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
var/list/data = list()
|
||||
data["x"] = F.x
|
||||
data["y"] = F.y
|
||||
data["saved_obj"] = pick(savable_obj)
|
||||
satchels_to_add += list(data)
|
||||
|
||||
var/json_file = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
|
||||
var/list/file_data = list()
|
||||
fdel(json_file)
|
||||
file_data["data"] = old_secret_satchels + satchels_to_add
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Stores trophies in curator display cases
|
||||
*/
|
||||
/datum/controller/subsystem/persistence
|
||||
var/list/saved_trophies = list()
|
||||
|
||||
/datum/controller/subsystem/persistence/LoadGamePersistence()
|
||||
. = ..()
|
||||
LoadTrophies()
|
||||
|
||||
/datum/controller/subsystem/persistence/SaveGamePersistence()
|
||||
. = ..()
|
||||
CollectTrophies()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadTrophies()
|
||||
if(fexists("data/npc_saves/TrophyItems.sav")) //legacy compatability to convert old format to new
|
||||
var/savefile/S = new /savefile("data/npc_saves/TrophyItems.sav")
|
||||
var/saved_json
|
||||
S >> saved_json
|
||||
if(!saved_json)
|
||||
return
|
||||
saved_trophies = json_decode(saved_json)
|
||||
fdel("data/npc_saves/TrophyItems.sav")
|
||||
else
|
||||
var/json_file = file("data/npc_saves/TrophyItems.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_trophies = json["data"]
|
||||
SetUpTrophies(saved_trophies.Copy())
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
if (T.showpiece)
|
||||
continue
|
||||
T.added_roundstart = TRUE
|
||||
|
||||
var/trophy_data = pick_n_take(trophy_items)
|
||||
|
||||
if(!islist(trophy_data))
|
||||
continue
|
||||
|
||||
var/list/chosen_trophy = trophy_data
|
||||
|
||||
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
|
||||
continue
|
||||
|
||||
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
continue
|
||||
|
||||
T.showpiece = new /obj/item/showpiece_dummy(T, path)
|
||||
T.trophy_message = chosen_trophy["message"]
|
||||
T.placer_key = chosen_trophy["placer_key"]
|
||||
T.update_icon()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
var/json_file = file("data/npc_saves/TrophyItems.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = remove_duplicate_trophies(saved_trophies)
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/remove_duplicate_trophies(list/trophies)
|
||||
var/list/ukeys = list()
|
||||
. = list()
|
||||
for(var/trophy in trophies)
|
||||
var/tkey = "[trophy["path"]]-[trophy["message"]]"
|
||||
if(ukeys[tkey])
|
||||
continue
|
||||
else
|
||||
. += list(trophy)
|
||||
ukeys[tkey] = TRUE
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
var/list/data = list()
|
||||
data["path"] = T.showpiece.type
|
||||
data["message"] = T.trophy_message
|
||||
data["placer_key"] = T.placer_key
|
||||
saved_trophies += list(data)
|
||||
@@ -2,6 +2,7 @@
|
||||
#define AB_CHECK_STUN 2
|
||||
#define AB_CHECK_LYING 4
|
||||
#define AB_CHECK_CONSCIOUS 8
|
||||
#define AB_CHECK_ALIVE 16
|
||||
|
||||
/datum/action
|
||||
var/name = "Generic Action"
|
||||
@@ -115,6 +116,9 @@
|
||||
if(check_flags & AB_CHECK_CONSCIOUS)
|
||||
if(owner.stat)
|
||||
return FALSE
|
||||
if(check_flags & AB_CHECK_ALIVE)
|
||||
if(owner.stat == DEAD)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE)
|
||||
|
||||
@@ -72,6 +72,52 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bokken
|
||||
name = "Training Bokken"
|
||||
result = /obj/item/melee/bokken
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/bokken_blade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 2,
|
||||
/obj/item/stack/sheet/leather = 1)
|
||||
time = 60
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bokken_steelwood
|
||||
name = "Training Steelwood Bokken"
|
||||
result = /obj/item/melee/bokken/steelwood
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/bokken_steelblade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 2,
|
||||
/obj/item/stack/sheet/leather = 1)
|
||||
time = 60
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/wakibokken
|
||||
name = "Training Wakizashi Bokken"
|
||||
result = /obj/item/melee/bokken/waki
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/wakibokken_blade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/wakibokken_steelwood
|
||||
name = "Training Wakizashi Steelwood Bokken"
|
||||
result = /obj/item/melee/bokken/waki/steelwood
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/wakibokken_steelblade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bola
|
||||
name = "Bola"
|
||||
result = /obj/item/restraints/legcuffs/bola
|
||||
@@ -248,7 +294,7 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun
|
||||
/datum/crafting_recipe/ishotgun
|
||||
name = "Improvised Shotgun"
|
||||
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
|
||||
@@ -434,3 +480,51 @@
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// BOKKEN CRAFTING
|
||||
|
||||
/datum/crafting_recipe/bokken_blade
|
||||
name = "Training Bokken Blade"
|
||||
result = /obj/item/bokken_blade
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 5)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/wakibokken_blade
|
||||
name = "Training Wakizashi Bokken Blade"
|
||||
result = /obj/item/wakibokken_blade
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/bokken_steelblade
|
||||
name = "Training Ironwood Bokken Blade"
|
||||
result = /obj/item/bokken_steelblade
|
||||
tools = list(/obj/item/hatchet, TOOL_WELDER)
|
||||
reqs = list(/obj/item/grown/log/steel = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/wakibokken_steelblade
|
||||
name = "Training Wakizashi Ironwood Bokken Blade"
|
||||
result = /obj/item/wakibokken_steelblade
|
||||
tools = list(/obj/item/hatchet, TOOL_WELDER)
|
||||
reqs = list(/obj/item/grown/log/steel = 1)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/bokken_hilt
|
||||
name = "Training Bokken hilt"
|
||||
result = /obj/item/bokken_hilt
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 5,
|
||||
/obj/item/stack/sheet/cloth = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/// Tucking element, for things that can be tucked into bed.
|
||||
/datum/element/bed_tuckable
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
/// our pixel_x offset - how much the item moves x when in bed (+x is closer to the pillow)
|
||||
var/x_offset = 0
|
||||
/// our pixel_y offset - how much the item move y when in bed (-y is closer to the middle)
|
||||
var/y_offset = 0
|
||||
/// our rotation degree - how much the item turns when in bed (+degrees turns it more parallel)
|
||||
var/rotation_degree = 0
|
||||
|
||||
/datum/element/bed_tuckable/Attach(obj/target, x = 0, y = 0, rotation = 0)
|
||||
. = ..()
|
||||
if(!isitem(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
x_offset = x
|
||||
y_offset = y
|
||||
rotation_degree = rotation
|
||||
RegisterSignal(target, COMSIG_ITEM_ATTACK_OBJ, .proc/tuck_into_bed)
|
||||
|
||||
/datum/element/bed_tuckable/Detach(obj/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, list(COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_PICKUP))
|
||||
|
||||
/**
|
||||
* Tuck our object into bed.
|
||||
*
|
||||
* tucked - the object being tucked
|
||||
* target_bed - the bed we're tucking them into
|
||||
* tucker - the guy doing the tucking
|
||||
*/
|
||||
/datum/element/bed_tuckable/proc/tuck_into_bed(obj/item/tucked, obj/structure/bed/target_bed, mob/living/tucker)
|
||||
|
||||
|
||||
if(!istype(target_bed))
|
||||
return
|
||||
|
||||
if(!tucker.transferItemToLoc(tucked, target_bed.drop_location()))
|
||||
return
|
||||
|
||||
to_chat(tucker, "<span class='notice'>You lay [tucked] out on [target_bed].</span>")
|
||||
tucked.pixel_x = x_offset
|
||||
tucked.pixel_y = y_offset
|
||||
if(rotation_degree)
|
||||
tucked.transform = turn(tucked.transform, rotation_degree)
|
||||
RegisterSignal(tucked, COMSIG_ITEM_PICKUP, .proc/untuck)
|
||||
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/**
|
||||
* If we rotate our object, then we need to un-rotate it when it's picked up
|
||||
*
|
||||
* tucked - the object that is tucked
|
||||
*/
|
||||
/datum/element/bed_tuckable/proc/untuck(obj/item/tucked)
|
||||
|
||||
|
||||
tucked.transform = turn(tucked.transform, -rotation_degree)
|
||||
UnregisterSignal(tucked, COMSIG_ITEM_PICKUP)
|
||||
@@ -165,6 +165,15 @@
|
||||
/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list)
|
||||
examine_list += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/datum/element/polychromic/proc/connect_helmet(atom/I, var/applycolor)
|
||||
if(isitem(I))
|
||||
if(istype(I,/obj/item/clothing/suit/hooded))
|
||||
var/obj/item/clothing/suit/hooded/Isuit = I
|
||||
colors_by_atom[Isuit.hood] = applycolor
|
||||
else if(istype(I,/obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/Isuit = I
|
||||
colors_by_atom[Isuit.helmet] = applycolor
|
||||
|
||||
/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H)
|
||||
if(!isitem(H)) //backup in case if it messes up somehow
|
||||
if(istype(source,/obj/item/clothing/suit/hooded)) //so how come it be like this, where toggleable headslots are named separately (helmet/hood) anyways?
|
||||
|
||||
@@ -85,6 +85,15 @@
|
||||
var/mob/M = teleatom
|
||||
M.cancel_camera()
|
||||
|
||||
var/static/list/bread_cache = typecacheof(/obj/item/reagent_containers/food/snacks/store/bread)
|
||||
var/list/breadlist = typecache_filter_list(teleatom.GetAllContents(), bread_cache)
|
||||
if(breadlist.len && (channel == TELEPORT_CHANNEL_BLUESPACE || channel == TELEPORT_CHANNEL_QUANTUM))
|
||||
for(var/obj/item/reagent_containers/food/snacks/store/bread/bread in breadlist)
|
||||
bread.bread_teleport()
|
||||
else if(istype(teleatom, /obj/item/reagent_containers/food/snacks/store/bread))
|
||||
var/obj/item/reagent_containers/food/snacks/store/bread/bread = teleatom
|
||||
bread.bread_teleport()
|
||||
|
||||
return TRUE
|
||||
|
||||
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
|
||||
|
||||
@@ -41,6 +41,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
power_environ = FALSE
|
||||
valid_territory = FALSE
|
||||
outdoors = TRUE
|
||||
persistent_debris_allowed = FALSE
|
||||
ambientsounds = SPACE
|
||||
blob_allowed = FALSE //Eating up space doesn't count for victory as a blob.
|
||||
considered_hull_exterior = TRUE
|
||||
@@ -1123,6 +1124,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
name = "Research Division Server Room"
|
||||
icon_state = "server"
|
||||
|
||||
/area/science/server/compcore
|
||||
name = "Computer Core"
|
||||
icon_state = "server"
|
||||
|
||||
/area/science/explab
|
||||
name = "Experimentation Lab"
|
||||
icon_state = "toxmisc"
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
var/clockwork_warp_allowed = TRUE
|
||||
/// Message to display when the clockwork warp fails
|
||||
var/clockwork_warp_fail = "The structure there is too dense for warping to pierce. (This is normal in high-security areas.)"
|
||||
/// Persistent debris alowed
|
||||
var/persistent_debris_allowed = TRUE
|
||||
/// Dirty flooring allowed
|
||||
var/dirt_buildup_allowed = TRUE
|
||||
|
||||
/// If mining tunnel generation is allowed in this area
|
||||
var/tunnel_allowed = FALSE
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
break
|
||||
var/datum/mind/cultie = antag_pick(antag_candidates)
|
||||
antag_candidates -= cultie
|
||||
cultie.special_role = ROLE_HERETIC
|
||||
cultie.restricted_roles = restricted_jobs
|
||||
culties += cultie
|
||||
|
||||
|
||||
@@ -106,15 +106,15 @@
|
||||
dat += "<input type='hidden' name='matrix_paint' value='1'"
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("rr", color_matrix_last[1])
|
||||
dat += MATRIX_FIELD("rg", color_matrix_last[2])
|
||||
dat += MATRIX_FIELD("rb", color_matrix_last[3])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("gr", color_matrix_last[4])
|
||||
dat += MATRIX_FIELD("gg", color_matrix_last[5])
|
||||
dat += MATRIX_FIELD("gb", color_matrix_last[6])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("br", color_matrix_last[7])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("rg", color_matrix_last[2])
|
||||
dat += MATRIX_FIELD("gg", color_matrix_last[5])
|
||||
dat += MATRIX_FIELD("bg", color_matrix_last[8])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("rb", color_matrix_last[3])
|
||||
dat += MATRIX_FIELD("gb", color_matrix_last[6])
|
||||
dat += MATRIX_FIELD("bb", color_matrix_last[9])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("cr", color_matrix_last[10])
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
name = "gas sensor"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "gsensor1"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 0)
|
||||
|
||||
var/on = TRUE
|
||||
|
||||
|
||||
@@ -774,6 +774,9 @@
|
||||
stun_projectile_sound = 'sound/weapons/gunshot_smg.ogg'
|
||||
armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 80, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
|
||||
|
||||
/obj/machinery/porta_turret/syndicate/pod/toolbox
|
||||
max_integrity = 100
|
||||
|
||||
/obj/machinery/porta_turret/syndicate/shuttle/target(atom/movable/target)
|
||||
if(target)
|
||||
setDir(get_dir(base, target))//even if you can't shoot, follow the target
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
/obj/effect/decal/cleanable
|
||||
gender = PLURAL
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
/// Is this kind of cleanable decal persistent
|
||||
var/persistent = FALSE
|
||||
/// Can we stack multiple in one tile?
|
||||
var/persistence_allow_stacking = FALSE
|
||||
/// Are we deleted by turf changes?
|
||||
var/wiped_by_floor_change = FALSE
|
||||
|
||||
var/list/random_icon_states = null
|
||||
var/blood_state = "" //I'm sorry but cleanable/blood code is ass, and so is blood_DNA
|
||||
var/bloodiness = 0 //0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
|
||||
@@ -29,9 +36,21 @@
|
||||
|
||||
addtimer(CALLBACK(src, /datum.proc/_AddElement, list(/datum/element/beauty, beauty)), 0)
|
||||
|
||||
/**
|
||||
* A data list is passed into this.
|
||||
* This should return null to skip saving, or the type of data to save. Type must be /cleanable.
|
||||
*/
|
||||
/obj/effect/decal/cleanable/proc/PersistenceSave(list/data)
|
||||
return type
|
||||
|
||||
/**
|
||||
* Loads from a data list.
|
||||
*/
|
||||
/obj/effect/decal/cleanable/proc/PersistenceLoad(list/data)
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
|
||||
if(mergeable_decal)
|
||||
qdel(C)
|
||||
return mergeable_decal
|
||||
|
||||
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food/drinks))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
|
||||
mergeable_decal = FALSE
|
||||
bloodiness = 0 //This isn't supposed to be bloody.
|
||||
persistent = TRUE
|
||||
var/body_colors = "#e3ba84" //a default color just in case.
|
||||
var/gibs_reagent_id = /datum/reagent/liquidgibs
|
||||
var/gibs_bloodtype = "A+"
|
||||
@@ -31,6 +32,10 @@
|
||||
flesh.color = body_colors
|
||||
add_overlay(flesh)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
return /obj/effect/decal/cleanable/blood/gibs/old
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
|
||||
return
|
||||
|
||||
@@ -159,6 +164,10 @@
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/slime/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
return type
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/slime/update_icon()
|
||||
add_atom_colour(body_colors, FIXED_COLOUR_PRIORITY)
|
||||
cut_overlays()
|
||||
@@ -198,6 +207,10 @@
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/synth/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
return type
|
||||
|
||||
//IPCs
|
||||
/obj/effect/decal/cleanable/blood/gibs/ipc
|
||||
desc = "They look sharp yet oozing."
|
||||
@@ -209,6 +222,10 @@
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ipc/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
return type
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ipc/update_icon()
|
||||
add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
|
||||
cut_overlays()
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
color = BLOOD_COLOR_HUMAN //default so we don't have white splotches everywhere.
|
||||
beauty = -100
|
||||
persistent = TRUE
|
||||
var/fixed_color = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
|
||||
if(C.fixed_color)
|
||||
qdel(C)
|
||||
return FALSE
|
||||
if (C.blood_DNA)
|
||||
blood_DNA |= C.blood_DNA
|
||||
qdel(C)
|
||||
update_icon()
|
||||
..()
|
||||
return FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/transfer_blood_dna()
|
||||
..()
|
||||
@@ -24,7 +30,22 @@
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/update_icon()
|
||||
color = blood_DNA_to_color()
|
||||
. = ..()
|
||||
if(!fixed_color)
|
||||
add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
data["color"] = color
|
||||
|
||||
/obj/effect/decal/cleanable/blood/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["color"])
|
||||
fixed_color = TRUE
|
||||
add_atom_colour(data["color"], FIXED_COLOUR_PRIORITY)
|
||||
name = "dried blood"
|
||||
desc = "Looks like it's been here a while. Eew"
|
||||
bloodiness = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/old
|
||||
name = "dried blood"
|
||||
@@ -38,6 +59,7 @@
|
||||
|
||||
/obj/effect/decal/cleanable/blood/splats
|
||||
random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
|
||||
persistence_allow_stacking = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/splatter
|
||||
random_icon_states = list("splatter1", "splatter2", "splatter3", "splatter4", "splatter5")
|
||||
@@ -48,16 +70,43 @@
|
||||
random_icon_states = null
|
||||
beauty = -50
|
||||
|
||||
/obj/effect/decal/cleanable/blood/tracks/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
data["dir"] = dir
|
||||
|
||||
/obj/effect/decal/cleanable/blood/tracks/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["dir"])
|
||||
setDir(text2num(data["dir"]))
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
|
||||
name = "blood"
|
||||
icon_state = "ltrails_1"
|
||||
desc = "Your instincts say you shouldn't be following these."
|
||||
random_icon_states = null
|
||||
beauty = -50
|
||||
persistent = TRUE
|
||||
persistence_allow_stacking = TRUE
|
||||
var/list/existing_dirs = list()
|
||||
var/fixed_color = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
data["dir"] = dir
|
||||
data["color"] = color
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["dir"])
|
||||
setDir(text2num(data["dir"]))
|
||||
if(data["color"])
|
||||
fixed_color = TRUE
|
||||
add_atom_colour(data["color"], FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/update_icon()
|
||||
color = blood_DNA_to_color()
|
||||
. = ..()
|
||||
if(!fixed_color)
|
||||
add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/effect/cleanable/trail_holder/Initialize()
|
||||
. = ..()
|
||||
@@ -84,8 +133,19 @@
|
||||
var/entered_dirs = 0
|
||||
var/exited_dirs = 0
|
||||
blood_state = BLOOD_STATE_BLOOD //the icon state to load images from
|
||||
persistent = TRUE
|
||||
persistence_allow_stacking = TRUE
|
||||
var/list/shoe_types = list()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
data["dir"] = dir
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["dir"])
|
||||
setDir(text2num(data["dir"]))
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/Crossed(atom/movable/O)
|
||||
if(ishuman(O))
|
||||
var/mob/living/carbon/human/H = O
|
||||
@@ -143,7 +203,7 @@
|
||||
return
|
||||
if(color != C.color)
|
||||
return
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/can_bloodcrawl_in()
|
||||
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
icon_state = "ash"
|
||||
mergeable_decal = FALSE
|
||||
beauty = -50
|
||||
persistent = TRUE
|
||||
persistence_allow_stacking = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/ash/Initialize()
|
||||
. = ..()
|
||||
@@ -38,6 +40,8 @@
|
||||
icon = 'icons/obj/shards.dmi'
|
||||
icon_state = "tiny"
|
||||
beauty = -100
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/glass/Initialize()
|
||||
. = ..()
|
||||
@@ -53,10 +57,33 @@
|
||||
name = "dirt"
|
||||
desc = "Someone should clean that up."
|
||||
icon_state = "dirt"
|
||||
alpha = 127
|
||||
canSmoothWith = list(/obj/effect/decal/cleanable/dirt, /turf/closed/wall, /obj/structure/falsewall)
|
||||
smooth = SMOOTH_FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
beauty = -75
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
wiped_by_floor_change = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/Initialize(mapload)
|
||||
. = ..()
|
||||
alpha = CONFIG_GET(number/dirt_alpha_starting)
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/proc/dirty(strength = 1)
|
||||
if(alpha < 255)
|
||||
alpha += strength
|
||||
if(alpha > 255)
|
||||
alpha = 255
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
data["alpha"] = alpha
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["alpha"])
|
||||
alpha = text2num(data["alpha"])
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/Initialize()
|
||||
. = ..()
|
||||
@@ -94,6 +121,8 @@
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
icon_state = "greenglow"
|
||||
beauty = -300
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -122,6 +151,8 @@
|
||||
icon_state = "molten"
|
||||
mergeable_decal = FALSE
|
||||
beauty = -150
|
||||
persistent = TRUE
|
||||
persistence_allow_stacking = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/molten_object/large
|
||||
name = "big gooey grey mass"
|
||||
@@ -136,6 +167,7 @@
|
||||
icon_state = "vomit_1"
|
||||
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
|
||||
beauty = -150
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(ishuman(user))
|
||||
@@ -151,6 +183,10 @@
|
||||
reagents.trans_to(H, reagents.total_volume)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
return /obj/effect/decal/cleanable/vomit/old
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/old
|
||||
name = "crusty dried vomit"
|
||||
desc = "You try not to look at the chunks, and fail."
|
||||
@@ -166,12 +202,16 @@
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
|
||||
beauty = -100
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/plant_smudge
|
||||
name = "plant smudge"
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_plant")
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/egg_smudge
|
||||
name = "smashed egg"
|
||||
@@ -179,6 +219,8 @@
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/pie_smudge //honk
|
||||
name = "smashed pie"
|
||||
@@ -186,6 +228,8 @@
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_pie")
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/chem_pile
|
||||
name = "chemical pile"
|
||||
@@ -193,6 +237,8 @@
|
||||
gender = NEUTER
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "ash"
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/shreds
|
||||
name = "shreds"
|
||||
@@ -200,6 +246,8 @@
|
||||
icon_state = "shreds"
|
||||
gender = PLURAL
|
||||
mergeable_decal = FALSE
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
|
||||
if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion.
|
||||
@@ -222,6 +270,8 @@
|
||||
desc = "The herpes of arts and crafts."
|
||||
icon = 'icons/effects/atmospherics.dmi'
|
||||
gender = NEUTER
|
||||
mergeable_decal = TRUE
|
||||
persistent = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/glitter/pink
|
||||
name = "pink glitter"
|
||||
@@ -247,3 +297,5 @@
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xfloor1"
|
||||
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
|
||||
mergeable_decal = TRUE
|
||||
persistent = TRUE
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
mergeable_decal = FALSE
|
||||
beauty = -50
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
@@ -52,6 +53,7 @@
|
||||
blood_state = BLOOD_STATE_OIL
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
beauty = -100
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/oil/Initialize()
|
||||
. = ..()
|
||||
@@ -61,8 +63,10 @@
|
||||
/obj/effect/decal/cleanable/oil/streak
|
||||
random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
|
||||
beauty = -50
|
||||
persistent = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/oil/slippery
|
||||
persistent = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/oil/slippery/Initialize()
|
||||
AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
icon_state = "rune1"
|
||||
plane = ABOVE_WALL_PLANE //makes the graffiti visible over a wall.
|
||||
gender = NEUTER
|
||||
persistent = TRUE
|
||||
persistence_allow_stacking = TRUE
|
||||
mergeable_decal = FALSE
|
||||
var/do_icon_rotate = TRUE
|
||||
var/rotation = 0
|
||||
@@ -29,3 +31,35 @@
|
||||
if(main)
|
||||
paint_colour = main
|
||||
add_atom_colour(paint_colour, FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/PersistenceSave(list/data)
|
||||
. = ..()
|
||||
if(icon != initial(icon)) // no support for alticons yet, awful system anyways
|
||||
return null
|
||||
data["icon_state"] = icon_state
|
||||
data["paint_color"] = paint_colour
|
||||
if(do_icon_rotate)
|
||||
data["rotation"] = rotation
|
||||
data["name"] = name
|
||||
if(pixel_x != initial(pixel_x))
|
||||
data["pixel_x"] = pixel_x
|
||||
if(pixel_y != initial(pixel_y))
|
||||
data["pixel_y"] = pixel_y
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/PersistenceLoad(list/data)
|
||||
. = ..()
|
||||
if(data["name"])
|
||||
name = data["name"]
|
||||
if(do_icon_rotate && data["rotation"])
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(text2num(data["rotation"]))
|
||||
transform = M
|
||||
if(data["paint_color"])
|
||||
paint_colour = data["paint_color"]
|
||||
add_atom_colour(paint_colour, FIXED_COLOUR_PRIORITY)
|
||||
if(data["icon_state"])
|
||||
icon_state = data["icon_state"]
|
||||
if(data["pixel_x"])
|
||||
pixel_x = data["pixel_x"]
|
||||
if(data["pixel_y"])
|
||||
pixel_y = data["pixel_y"]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
/obj/item/paicard/Initialize()
|
||||
SSpai.pai_card_list += src
|
||||
add_overlay("pai-off")
|
||||
AddElement(/datum/element/bed_tuckable, 6, -5, 90)
|
||||
return ..()
|
||||
|
||||
/obj/item/paicard/Destroy()
|
||||
|
||||
@@ -16,9 +16,9 @@ GLOBAL_LIST_EMPTY(power_sinks)
|
||||
throw_speed = 1
|
||||
throw_range = 2
|
||||
custom_materials = list(/datum/material/iron=750)
|
||||
var/drain_rate = 1600000 // amount of power to drain per tick
|
||||
var/drain_rate = 2000000 // amount of power to drain per tick. Currently 2MJ.
|
||||
var/power_drained = 0 // has drained this much power
|
||||
var/max_power = 1e10 // maximum power that can be drained before exploding
|
||||
var/max_power = 2000000000 // maximum power that can be drained before exploding. Currently 2GJ. About 17 minutes to explode at the max rate.
|
||||
var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
|
||||
var/admins_warned = FALSE // stop spam, only warn the admins once that we are about to boom
|
||||
|
||||
@@ -155,5 +155,5 @@ GLOBAL_LIST_EMPTY(power_sinks)
|
||||
|
||||
if(power_drained >= max_power)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
explosion(src.loc, 4,8,16,32)
|
||||
explosion(src.loc, 3,7,14,28)
|
||||
qdel(src)
|
||||
|
||||
@@ -264,6 +264,30 @@ effective or pretty fucking useless.
|
||||
GLOB.active_jammers -= src
|
||||
update_icon()
|
||||
|
||||
/*portable turret*/
|
||||
/obj/item/storage/toolbox/emergency/turret
|
||||
desc = "You feel a strange urge to hit this with a wrench."
|
||||
|
||||
/obj/item/storage/toolbox/emergency/turret/PopulateContents()
|
||||
new /obj/item/screwdriver(src)
|
||||
new /obj/item/wrench(src)
|
||||
new /obj/item/weldingtool(src)
|
||||
new /obj/item/crowbar(src)
|
||||
new /obj/item/analyzer(src)
|
||||
new /obj/item/wirecutters(src)
|
||||
|
||||
/obj/item/storage/toolbox/emergency/turret/attackby(obj/item/I, mob/living/user, params)
|
||||
if(I.tool_behaviour == TOOL_WRENCH && user.a_intent == INTENT_HARM)
|
||||
user.visible_message("<span class='danger'>[user] bashes [src] with [I]!</span>", \
|
||||
"<span class='danger'>You bash [src] with [I]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
playsound(src, "sound/items/drill_use.ogg", 80, TRUE, -1)
|
||||
var/obj/machinery/porta_turret/syndicate/pod/toolbox/turret = new(get_turf(loc))
|
||||
turret.faction = list("[REF(user)]")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/headsetupgrader
|
||||
name = "headset upgrader"
|
||||
desc = "A tool that can be used to upgrade a normal headset to be able to protect from flashbangs."
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
var/boom_sizes = list(0, 0, 3)
|
||||
var/can_attach_mob = FALSE
|
||||
var/full_damage_on_mobs = FALSE
|
||||
var/can_gib_mobs = FALSE
|
||||
|
||||
/obj/item/grenade/plastic/Initialize()
|
||||
. = ..()
|
||||
@@ -72,7 +73,7 @@
|
||||
explosion(get_step(T, aim_dir), boom_sizes[1], boom_sizes[2], boom_sizes[3])
|
||||
else
|
||||
explosion(location, boom_sizes[1], boom_sizes[2], boom_sizes[3])
|
||||
if(ismob(target))
|
||||
if(ismob(target) && can_gib_mobs)
|
||||
var/mob/M = target
|
||||
M.gib()
|
||||
qdel(src)
|
||||
|
||||
@@ -1,17 +1,3 @@
|
||||
/obj/item/caution
|
||||
desc = "Caution! Wet Floor!"
|
||||
name = "wet floor sign"
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "caution"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
|
||||
force = 1
|
||||
throwforce = 3
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
attack_verb = list("warned", "cautioned", "smashed")
|
||||
|
||||
/obj/item/choice_beacon
|
||||
name = "choice beacon"
|
||||
desc = "Hey, why are you viewing this?!! Please let Centcom know about this odd occurance."
|
||||
|
||||
@@ -24,13 +24,17 @@
|
||||
create_reagents(mopcap, NONE, NO_REAGENTS_VALUE)
|
||||
|
||||
|
||||
/obj/item/mop/proc/clean(turf/A)
|
||||
/obj/item/mop/proc/clean(turf/A, mob/user)
|
||||
if(reagents.has_reagent(/datum/reagent/water, 1) || reagents.has_reagent(/datum/reagent/water/holywater, 1) || reagents.has_reagent(/datum/reagent/consumable/ethanol/vodka, 1) || reagents.has_reagent(/datum/reagent/space_cleaner, 1))
|
||||
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
|
||||
A.clean_blood()
|
||||
var/cleaned_something = FALSE
|
||||
for(var/obj/effect/O in A)
|
||||
if(is_cleanable(O))
|
||||
cleaned_something = TRUE
|
||||
qdel(O)
|
||||
if(cleaned_something && user && user.client)
|
||||
user.client.increment_progress("janitor", 1)
|
||||
reagents.reaction(A, TOUCH, 10) //Needed for proper floor wetting.
|
||||
reagents.remove_any(1) //reaction() doesn't use up the reagents
|
||||
|
||||
@@ -59,7 +63,7 @@
|
||||
if(!L.UseStaminaBuffer(stamusage, warn = TRUE))
|
||||
return
|
||||
user.visible_message("[user] cleans \the [T] with [src].", "<span class='notice'>You clean \the [T] with [src].</span>")
|
||||
clean(T)
|
||||
clean(T, user)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(T, used_item = src)
|
||||
playsound(T, "slosh", 50, 1)
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
/obj/item/toy/plush/Initialize(mapload, set_snowflake_id)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, squeak_override)
|
||||
AddElement(/datum/element/bed_tuckable, 6, -5, 90)
|
||||
|
||||
//have we decided if Pinocchio goes in the blue or pink aisle yet?
|
||||
if(gender == NEUTER)
|
||||
|
||||
@@ -326,6 +326,9 @@
|
||||
else if(istype(W, /obj/item/borg/upgrade/ai))
|
||||
var/obj/item/borg/upgrade/ai/M = W
|
||||
if(check_completion())
|
||||
if(!chest.cell)
|
||||
to_chat(user, "<span class='warning'>The endoskeleton still needs a power cell!</span>")
|
||||
return
|
||||
if(!isturf(loc))
|
||||
to_chat(user, "<span class='warning'>You cannot install[M], the frame has to be standing on the ground to be perfectly precise!</span>")
|
||||
return
|
||||
@@ -346,7 +349,6 @@
|
||||
O.lawupdate = FALSE
|
||||
O.make_laws()
|
||||
|
||||
|
||||
O.cell = chest.cell
|
||||
chest.cell.forceMove(O)
|
||||
chest.cell = null
|
||||
@@ -392,6 +394,7 @@
|
||||
created_name = new_name
|
||||
else
|
||||
created_name = ""
|
||||
log_game("[key_name(usr)] renamed [src] ([REF(src)]) to [created_name].")
|
||||
|
||||
else if(href_list["Master"])
|
||||
forced_ai = select_active_ai(usr)
|
||||
|
||||
@@ -253,7 +253,6 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
|
||||
new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\
|
||||
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
|
||||
new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 15),\
|
||||
new/datum/stack_recipe("training bokken", /obj/item/melee/bokken, 10, time = 15),\
|
||||
null, \
|
||||
new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
|
||||
new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
|
||||
@@ -794,7 +793,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
|
||||
new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 10, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new /datum/stack_recipe("duct", /obj/item/stack/ducts,1), \
|
||||
new /datum/stack_recipe("laser pointer case", /obj/item/glasswork/glass_base/laserpointer_shell, 30), \
|
||||
new /datum/stack_recipe("wet floor sign", /obj/item/caution, 2)))
|
||||
new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2)))
|
||||
|
||||
/obj/item/stack/sheet/plastic
|
||||
name = "plastic"
|
||||
|
||||
@@ -802,7 +802,8 @@
|
||||
. += "<span class='notice'>Alt-click it to quickly draw the blade.</span>"
|
||||
|
||||
/obj/item/storage/belt/sabre/PopulateContents()
|
||||
new starting_sword(src)
|
||||
if(starting_sword)
|
||||
new starting_sword(src)
|
||||
|
||||
/obj/item/storage/belt/sabre/rapier
|
||||
name = "rapier sheath"
|
||||
@@ -864,6 +865,7 @@
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.max_items = 2
|
||||
STR.max_w_class = WEIGHT_CLASS_BULKY + WEIGHT_CLASS_NORMAL //katana and waki.
|
||||
STR.max_combined_w_class = 7
|
||||
|
||||
/obj/item/melee/smith/twohand/katana/on_exit_storage(datum/component/storage/S)
|
||||
var/obj/item/storage/belt/sabre/twin/B = S.parent
|
||||
|
||||
@@ -103,6 +103,39 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents()
|
||||
return
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/clean // the assistant traitor toolbox, damage scales with TC inside
|
||||
name = "toolbox"
|
||||
desc = "An old, blue toolbox. It menaces with a sickening miasma of robust energies. You sure about this, Brain?"
|
||||
icon_state = "toolbox_blue_clean"
|
||||
force = 19
|
||||
throwforce = 22
|
||||
wound_bonus = 0
|
||||
bare_wound_bonus = 10
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/clean/proc/calc_damage()
|
||||
var/power = 0
|
||||
for (var/obj/item/stack/telecrystal/TC in GetAllContents())
|
||||
power += TC.amount
|
||||
force = 19 + power
|
||||
throwforce = 22 + power
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/clean/attack(mob/target, mob/living/user)
|
||||
calc_damage() // one damage for one telecrystal equals about thirty seven(?) damage if you pour ALL your tc
|
||||
..()
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/clean/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
calc_damage()
|
||||
..()
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/clean/PopulateContents()
|
||||
new /obj/item/screwdriver(src)
|
||||
new /obj/item/wrench(src)
|
||||
new /obj/item/weldingtool(src)
|
||||
new /obj/item/crowbar(src)
|
||||
new /obj/item/wirecutters(src)
|
||||
new /obj/item/multitool(src)
|
||||
new /obj/item/clothing/gloves/color/yellow(src)
|
||||
|
||||
/obj/item/storage/toolbox/electrical
|
||||
name = "electrical toolbox"
|
||||
icon_state = "yellow"
|
||||
|
||||
@@ -296,8 +296,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
force = 7 //how much harm mode damage we do
|
||||
var/stamina_damage_increment = 4 //how much extra damage do we do when in non-harm mode
|
||||
force = 10 //how much harm mode damage we do
|
||||
var/stamina_damage_increment = 5 //how much extra damage do we do when in non-harm mode
|
||||
throwforce = 10
|
||||
damtype = STAMINA
|
||||
attack_verb = list("whacked", "smacked", "struck")
|
||||
@@ -310,11 +310,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
var/quick_parry = FALSE // false = default parry, true = really small parry window
|
||||
item_flags = ITEM_CAN_PARRY
|
||||
block_parry_data = /datum/block_parry_data/bokken
|
||||
var/default_parry_data = /datum/block_parry_data/bokken
|
||||
var/quick_parry_data = /datum/block_parry_data/bokken/quick_parry
|
||||
bare_wound_bonus = 0
|
||||
wound_bonus = 0
|
||||
|
||||
/datum/block_parry_data/bokken // fucked up parry data, emphasizing quicker, shorter parries
|
||||
parry_stamina_cost = 8 // be wise about when you parry, though, else you won't be able to fight enough to make it count
|
||||
parry_stamina_cost = 10 // be wise about when you parry, though, else you won't be able to fight enough to make it count
|
||||
parry_time_windup = 0
|
||||
parry_time_active = 10 // small parry window
|
||||
parry_time_spindown = 0
|
||||
@@ -330,11 +332,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
)
|
||||
parry_failed_stagger_duration = 3 SECONDS
|
||||
parry_data = list(
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 10*2.5 = 25, 11*2.5 = 27.5, 12*2.5 = 30, 13*2.5 = 32.5
|
||||
)
|
||||
|
||||
/datum/block_parry_data/bokken/quick_parry // emphasizing REALLY SHORT PARRIES
|
||||
parry_stamina_cost = 6 // still more costly than most parries, but less than a full bokken parry
|
||||
parry_stamina_cost = 8 // still more costly than most parries, but less than a full bokken parry
|
||||
parry_time_active = 5 // REALLY small parry window
|
||||
parry_time_perfect = 2.5 // however...
|
||||
parry_time_perfect_leeway = 2 // the entire time, the parry is perfect
|
||||
@@ -371,9 +373,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
. = ..()
|
||||
quick_parry = !quick_parry
|
||||
if(quick_parry)
|
||||
block_parry_data = /datum/block_parry_data/bokken/quick_parry
|
||||
block_parry_data = quick_parry_data
|
||||
else
|
||||
block_parry_data = /datum/block_parry_data/bokken
|
||||
block_parry_data = default_parry_data
|
||||
to_chat(user, "<span class='notice'>[src] is now [quick_parry ? "emphasizing shorter parries, forcing you to riposte or be staggered" : "emphasizing longer parries, with a shorter window to riposte but more forgiving parries"].</span>")
|
||||
|
||||
/obj/item/melee/bokken/attackby(obj/item/I, mob/living/user, params)
|
||||
@@ -410,23 +412,76 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
if(burnt)
|
||||
. += " Burned into the \"blade\" is [burned_in]."
|
||||
|
||||
/obj/item/melee/bokken/steelwood
|
||||
name = "steelwood bokken"
|
||||
desc = "A misnomer of sorts, this is effectively a blunt katana made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh."
|
||||
icon_state = "bokken_steel"
|
||||
item_state = "bokken_steel"
|
||||
force = 12
|
||||
stamina_damage_increment = 3
|
||||
|
||||
/obj/item/melee/bokken/waki
|
||||
name = "wakizashi bokken"
|
||||
desc = "A space-Japanese training sword made of wood and shaped like a wakizashi."
|
||||
icon_state = "wakibokken"
|
||||
item_state = "wakibokken"
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 6
|
||||
stamina_damage_increment = 4
|
||||
block_parry_data = /datum/block_parry_data/bokken/waki
|
||||
default_parry_data = /datum/block_parry_data/bokken/waki
|
||||
quick_parry_data = /datum/block_parry_data/bokken/waki/quick_parry
|
||||
|
||||
/datum/block_parry_data/bokken/waki // weaker parries than the bigger variant, but cheaper and faster recovery, like quick parry
|
||||
parry_stamina_cost = 4
|
||||
parry_time_windup = 0
|
||||
parry_time_active = 6
|
||||
parry_time_spindown = 0
|
||||
parry_time_perfect = 1.5
|
||||
parry_time_perfect_leeway = 1
|
||||
parry_imperfect_falloff_percent = 7.5
|
||||
parry_efficiency_to_counterattack = 120
|
||||
parry_efficiency_considered_successful = 65
|
||||
parry_efficiency_perfect = 120
|
||||
parry_efficiency_perfect_override = list(
|
||||
TEXT_ATTACK_TYPE_PROJECTILE = 30,
|
||||
)
|
||||
parry_failed_stagger_duration = 2 SECONDS
|
||||
parry_data = list(
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 1.5, // 6*1.5 = 9, 7*1.5 = 10.5, 8*1.5 = 12, 9*1.5 = 13.5
|
||||
)
|
||||
|
||||
/datum/block_parry_data/bokken/waki/quick_parry //For the parry spammer in you
|
||||
parry_stamina_cost = 2 // Slam that parry button
|
||||
parry_time_active = 2.5
|
||||
parry_time_perfect = 1
|
||||
parry_time_perfect_leeway = 1
|
||||
parry_failed_stagger_duration = 1 SECONDS
|
||||
parry_failed_clickcd_duration = 1 SECONDS
|
||||
|
||||
/datum/block_parry_data/bokken/waki/quick_parry/proj
|
||||
parry_efficiency_perfect_override = list()
|
||||
|
||||
/obj/item/melee/bokken/waki/steelwood
|
||||
name = "wakizashi steelwood bokken"
|
||||
desc = "A misnomer of sorts, this is effectively a blunt wakizashi made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh."
|
||||
icon_state = "wakibokken_steel"
|
||||
item_state = "wakibokken_steel"
|
||||
force = 8
|
||||
stamina_damage_increment = 2
|
||||
|
||||
/obj/item/melee/bokken/debug
|
||||
name = "funny debug parrying stick"
|
||||
desc = "if you see this you've fucked up somewhere my good man"
|
||||
block_parry_data = /datum/block_parry_data/bokken/debug
|
||||
|
||||
/obj/item/melee/bokken/debug/AltClick(mob/user)
|
||||
quick_parry = !quick_parry
|
||||
if(quick_parry)
|
||||
block_parry_data = /datum/block_parry_data/bokken/quick_parry/debug
|
||||
else
|
||||
block_parry_data = /datum/block_parry_data/bokken/debug
|
||||
to_chat(user, "<span class='notice'>[src] is now [quick_parry ? "emphasizing shorter parries, forcing you to riposte or be staggered" : "emphasizing longer parries, with a shorter window to riposte but more forgiving parries"].</span>")
|
||||
default_parry_data = /datum/block_parry_data/bokken/debug
|
||||
quick_parry_data = /datum/block_parry_data/bokken/quick_parry/debug
|
||||
|
||||
/datum/block_parry_data/bokken/debug
|
||||
parry_efficiency_perfect_override = list()
|
||||
parry_data = list(
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 10*2.5 = 25, 11*2.5 = 27.5, 12*2.5 = 30, 13*2.5 = 32.5
|
||||
PARRY_DISARM_ATTACKER = TRUE,
|
||||
PARRY_KNOCKDOWN_ATTACKER = 10,
|
||||
PARRY_STAGGER_ATTACKER = 10,
|
||||
@@ -436,13 +491,63 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/datum/block_parry_data/bokken/quick_parry/debug
|
||||
parry_efficiency_perfect_override = list()
|
||||
parry_data = list(
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 7*2.5 = 17.5, 8*2.5 = 20, 9*2.5 = 22.5, 10*2.5 = 25
|
||||
PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN = 2.5, // 10*2.5 = 25, 11*2.5 = 27.5, 12*2.5 = 30, 13*2.5 = 32.5
|
||||
PARRY_DISARM_ATTACKER = TRUE,
|
||||
PARRY_KNOCKDOWN_ATTACKER = 10,
|
||||
PARRY_STAGGER_ATTACKER = 10,
|
||||
PARRY_DAZE_ATTACKER = 10,
|
||||
)
|
||||
|
||||
/// BOKKEN CRAFTNG PIECES
|
||||
|
||||
/obj/item/bokken_blade
|
||||
name = "training bokken wooden blade"
|
||||
desc = "The blade piece of a bokken katana."
|
||||
icon = 'icons/obj/smith.dmi'
|
||||
icon_state = "bokken"
|
||||
item_state = "bone_dagger"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/bokken_steelblade
|
||||
name = "training bokken steelwood blade"
|
||||
desc = "The blade piece of a steelwood bokken katana."
|
||||
icon = 'icons/obj/smith.dmi'
|
||||
icon_state = "bokken_steel"
|
||||
item_state = "switchblade_ext"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/wakibokken_blade
|
||||
name = "training bokken wooden wakizashi blade"
|
||||
desc = "The blade piece of a bokken wakizashi."
|
||||
icon = 'icons/obj/smith.dmi'
|
||||
icon_state = "wakibokken"
|
||||
item_state = "bone_dagger"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/wakibokken_steelblade
|
||||
name = "training bokken steelwood wakizashi blade"
|
||||
desc = "The blade piece of a steelwood bokken katana."
|
||||
icon = 'icons/obj/smith.dmi'
|
||||
icon_state = "wakibokken_steel"
|
||||
item_state = "switchblade_ext"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/bokken_hilt
|
||||
name = "training bokken hilt"
|
||||
desc = "The hilt piece of a bokken. This hilt is appropriate for any potential blade length or material."
|
||||
icon = 'icons/obj/smith.dmi'
|
||||
icon_state = "bokken_hilt"
|
||||
item_state = "bone_dagger"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
|
||||
/obj/item/wirerod
|
||||
name = "wired rod"
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
return
|
||||
user.do_attack_animation(src)
|
||||
. = take_damage(damage_amount, damage_type, damage_flag, sound_effect, get_dir(src, user), armor_penetration)
|
||||
user.DelayNextAction()
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
|
||||
/obj/attack_alien(mob/living/carbon/alien/humanoid/user)
|
||||
if(attack_generic(user, 60, BRUTE, "melee", 0))
|
||||
|
||||
@@ -40,6 +40,16 @@
|
||||
if(istype(W, /obj/item/wrench) && !(flags_1&NODECONSTRUCT_1))
|
||||
W.play_tool_sound(src)
|
||||
deconstruct(TRUE)
|
||||
else if(istype(W, /obj/item/bedsheet))
|
||||
if(user.transferItemToLoc(W, drop_location()))
|
||||
to_chat(user, "<span class='notice'>You make \the [src] with [W].</span>")
|
||||
W.pixel_x = 0
|
||||
W.pixel_y = 0
|
||||
else if(istype(W, /obj/item/disk/nuclear))
|
||||
if(user.transferItemToLoc(W, drop_location()))
|
||||
to_chat(user, "<span class='notice'>You tuck little disky into bed. Good night disky.</span>")
|
||||
W.pixel_x = 6 //make sure they reach the pillow
|
||||
W.pixel_y = -6
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ LINEN BINS
|
||||
dog_fashion = /datum/dog_fashion/head/ghost
|
||||
var/list/dream_messages = list("white")
|
||||
|
||||
/obj/item/bedsheet/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/bed_tuckable, 0, 0, 0)
|
||||
|
||||
/obj/item/bedsheet/attack(mob/living/M, mob/user)
|
||||
if(!attempt_initiate_surgery(src, M, user))
|
||||
..()
|
||||
@@ -243,7 +247,7 @@ LINEN BINS
|
||||
|
||||
/obj/item/bedsheet/random/Initialize()
|
||||
..()
|
||||
var/type = pick(typesof(/obj/item/bedsheet) - list(/obj/item/bedsheet/random, /obj/item/bedsheet/chameleon))
|
||||
var/type = pick(typesof(/obj/item/bedsheet) - (list(/obj/item/bedsheet/random, /obj/item/bedsheet/chameleon) + typesof(/obj/item/bedsheet/unlockable)))
|
||||
new type(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
@@ -257,9 +261,32 @@ LINEN BINS
|
||||
chameleon_action = new(src)
|
||||
chameleon_action.chameleon_type = /obj/item/bedsheet
|
||||
chameleon_action.chameleon_name = "Bedsheet"
|
||||
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random), only_root_path = TRUE)
|
||||
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random, /obj/item/bedsheet/unlockable), only_root_path = FALSE)
|
||||
chameleon_action.initialize_disguises()
|
||||
|
||||
//unlockable bedsheets
|
||||
/obj/item/bedsheet/unlockable
|
||||
name = "unlockable bedsheet"
|
||||
desc = "this shouldn't be here!"
|
||||
|
||||
//janitor: clean 100 messes with mop as janitor
|
||||
/obj/item/bedsheet/unlockable/janitor
|
||||
name = "janitor bedsheet"
|
||||
desc = "A white bedsheet, with a warning sign on the front."
|
||||
icon_state = "sheetjanitor"
|
||||
|
||||
//cook: use microwave 100 times properly (contents must make one good item) as cook
|
||||
/obj/item/bedsheet/unlockable/cook
|
||||
name = "cook bedsheet"
|
||||
desc = "A grey bedsheet, with a microwave on the front."
|
||||
icon_state = "sheetcook"
|
||||
|
||||
//miner: redeem 100,000 mining points
|
||||
/obj/item/bedsheet/unlockable/miner
|
||||
name = "miner bedsheet"
|
||||
desc = "A red and black bedsheet. It seems to be made with goliath hide."
|
||||
icon_state = "sheetminer"
|
||||
|
||||
//bedsheet bin
|
||||
/obj/structure/bedsheetbin
|
||||
name = "linen bin"
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
new /obj/item/melee/flyswatter(src)
|
||||
new /obj/item/flashlight(src)
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/caution(src)
|
||||
new /obj/item/clothing/suit/caution(src)
|
||||
new /obj/item/holosign_creator(src)
|
||||
new /obj/item/lightreplacer(src)
|
||||
new /obj/item/soap(src)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
l.janicart_insert(user,src)
|
||||
else
|
||||
to_chat(user, fail_msg)
|
||||
else if(istype(I, /obj/item/caution))
|
||||
else if(istype(I, /obj/item/clothing/suit/caution))
|
||||
if(signs < max_signs)
|
||||
put_in_cart(I, user)
|
||||
signs++
|
||||
@@ -104,7 +104,7 @@
|
||||
items += list("Spray bottle" = image(icon = myspray.icon, icon_state = myspray.icon_state))
|
||||
if(myreplacer)
|
||||
items += list("Light replacer" = image(icon = myreplacer.icon, icon_state = myreplacer.icon_state))
|
||||
var/obj/item/caution/sign = locate() in src
|
||||
var/obj/item/clothing/suit/caution/sign = locate() in src
|
||||
if(sign)
|
||||
items += list("Sign" = image(icon = sign.icon, icon_state = sign.icon_state))
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
/turf/open
|
||||
plane = FLOOR_PLANE
|
||||
/// Does dirt buildup happen on us?
|
||||
var/dirt_buildup_allowed = FALSE
|
||||
/// Dirt level.
|
||||
var/dirtyness = 0
|
||||
/// Dirt level to spawn dirt. Null to use config.
|
||||
var/dirt_spawn_threshold
|
||||
/// Slowdown applied to mobs on us.
|
||||
var/slowdown = 0 //negative for faster, positive for slower
|
||||
|
||||
var/postdig_icon_change = FALSE
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
canSmoothWith = list(/turf/open/floor/fakepit, /turf/open/chasm)
|
||||
density = TRUE //This will prevent hostile mobs from pathing into chasms, while the canpass override will still let it function like an open turf
|
||||
bullet_bounce_sound = null //abandon all hope ye who enter
|
||||
dirt_buildup_allowed = FALSE
|
||||
|
||||
/turf/open/chasm/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
//Making the station dirty, one tile at a time. Called by master controller's setup_objects
|
||||
|
||||
/turf/open/floor/proc/MakeDirty()
|
||||
if(CONFIG_GET(flag/persistent_debris_only))
|
||||
return
|
||||
|
||||
if(prob(66)) //fastest possible exit 2/3 of the time
|
||||
return
|
||||
|
||||
@@ -38,7 +41,7 @@
|
||||
return
|
||||
|
||||
//Construction zones. Blood, sweat, and oil. Oh, and dirt.
|
||||
var/static/list/engine_dirt_areas = typecacheof(list(/area/engine,
|
||||
var/static/list/engine_dirt_areas = typecacheof(list(/area/engine,
|
||||
/area/crew_quarters/heads/chief,
|
||||
/area/ruin/space/derelict/assembly_line,
|
||||
/area/science/robotics,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
name = "floor"
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
baseturfs = /turf/open/floor/plating
|
||||
dirt_buildup_allowed = TRUE
|
||||
|
||||
footstep = FOOTSTEP_FLOOR
|
||||
barefootstep = FOOTSTEP_HARD_BAREFOOT
|
||||
@@ -137,6 +138,9 @@
|
||||
burnt = 1
|
||||
|
||||
/turf/open/floor/proc/make_plating()
|
||||
for(var/obj/effect/decal/cleanable/C in src)
|
||||
if(C.wiped_by_floor_change)
|
||||
qdel(C)
|
||||
return ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
|
||||
|
||||
/turf/open/floor/ChangeTurf(path, new_baseturf, flags)
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
to_chat(user, "<span class='notice'>You begin reinforcing the floor...</span>")
|
||||
if(do_after(user, 30, target = src))
|
||||
if (R.get_amount() >= 2 && !istype(src, /turf/open/floor/engine))
|
||||
for(var/obj/effect/decal/cleanable/decal in src)
|
||||
if(decal.wiped_by_floor_change)
|
||||
qdel(decal)
|
||||
PlaceOnTop(/turf/open/floor/engine, flags = CHANGETURF_INHERIT_AIR)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 80, 1)
|
||||
R.use(2)
|
||||
@@ -78,6 +81,9 @@
|
||||
to_chat(user, "<span class='notice'>You begin adding glass to the floor...</span>")
|
||||
if(do_after(user, 5, target = src))
|
||||
if (G.get_amount() >= 2 && !istype(src, /turf/open/transparent/glass))
|
||||
for(var/obj/effect/decal/cleanable/decal in src)
|
||||
if(decal.wiped_by_floor_change)
|
||||
qdel(decal)
|
||||
PlaceOnTop(/turf/open/transparent/glass, flags = CHANGETURF_INHERIT_AIR)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 80, 1)
|
||||
G.use(2)
|
||||
@@ -95,6 +101,9 @@
|
||||
to_chat(user, "<span class='notice'>You begin adding reinforced glass to the floor...</span>")
|
||||
if(do_after(user, 10, target = src))
|
||||
if (RG.get_amount() >= 2 && !istype(src, /turf/open/transparent/glass/reinforced))
|
||||
for(var/obj/effect/decal/cleanable/decal in src)
|
||||
if(decal.wiped_by_floor_change)
|
||||
qdel(decal)
|
||||
PlaceOnTop(/turf/open/transparent/glass/reinforced, flags = CHANGETURF_INHERIT_AIR)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 80, 1)
|
||||
RG.use(2)
|
||||
@@ -110,6 +119,9 @@
|
||||
var/obj/item/stack/tile/W = C
|
||||
if(!W.use(1))
|
||||
return
|
||||
for(var/obj/effect/decal/cleanable/decal in src)
|
||||
if(decal.wiped_by_floor_change)
|
||||
qdel(decal)
|
||||
if(istype(W, /obj/item/stack/tile/material))
|
||||
var/turf/newturf = PlaceOnTop(/turf/open/floor/material, flags = CHANGETURF_INHERIT_AIR)
|
||||
newturf.set_custom_materials(W.custom_materials)
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
return TRUE
|
||||
if(floor_tile)
|
||||
new floor_tile(src, 2)
|
||||
for(var/obj/effect/decal/cleanable/C in src)
|
||||
if(C.wiped_by_floor_change)
|
||||
qdel(C)
|
||||
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
gender = PLURAL //"That's some lava."
|
||||
baseturfs = /turf/open/lava //lava all the way down
|
||||
slowdown = 2
|
||||
dirt_buildup_allowed = FALSE
|
||||
|
||||
light_range = 2
|
||||
light_power = 0.75
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
planetary_atmos = TRUE
|
||||
bullet_bounce_sound = null //forever falling
|
||||
tiled_dirt = FALSE
|
||||
dirt_buildup_allowed = FALSE
|
||||
|
||||
/turf/open/indestructible/reebe_void/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
icon_state = "0"
|
||||
name = "\proper space"
|
||||
intact = 0
|
||||
dirt_buildup_allowed = FALSE
|
||||
|
||||
temperature = TCMB
|
||||
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
if(C.prefs.toggles & SOUND_PRAYERS)
|
||||
if(usr.job == "Chaplain")
|
||||
SEND_SOUND(C, sound('sound/effects/pray.ogg'))
|
||||
else
|
||||
SEND_SOUND(C, sound('sound/effects/ding.ogg'))
|
||||
to_chat(usr, "<span class='info'>You pray to the gods: \"[msg_tmp]\"</span>")
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Prayer") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
return
|
||||
flick("blob_resource_glow", src)
|
||||
if(overmind)
|
||||
overmind.add_points(1)
|
||||
overmind.add_points(2)
|
||||
resource_delay = world.time + 40 + overmind.resource_blobs.len * 2.5 //4 seconds plus a quarter second for each resource blob the overmind has
|
||||
else
|
||||
resource_delay = world.time + 40
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
set category = "Blob"
|
||||
set name = "Create Factory Blob (60)"
|
||||
set desc = "Create a spore tower that will spawn spores to harass your enemies."
|
||||
createSpecial(60, /obj/structure/blob/factory, 7, 1)
|
||||
createSpecial(60, /obj/structure/blob/factory, 5, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_blobbernaut()
|
||||
set category = "Blob"
|
||||
@@ -195,6 +195,7 @@
|
||||
to_chat(blobber, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.</span>")
|
||||
B.naut = FALSE
|
||||
add_points(40)
|
||||
|
||||
/mob/camera/blob/verb/relocate_core()
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [get_area_name(src)] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 10, null, FALSE, 0)
|
||||
SSpersistence.station_was_destroyed = TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
|
||||
GLOB.ratvar_awakens--
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
/datum/antagonist/heretic/on_gain()
|
||||
var/mob/living/current = owner.current
|
||||
owner.teach_crafting_recipe(/datum/crafting_recipe/heretic/codex)
|
||||
owner.special_role = ROLE_HERETIC
|
||||
if(ishuman(current))
|
||||
forge_primary_objectives()
|
||||
gain_knowledge(/datum/eldritch_knowledge/spell/basic)
|
||||
@@ -49,7 +50,7 @@
|
||||
for(var/X in researched_knowledge)
|
||||
var/datum/eldritch_knowledge/EK = researched_knowledge[X]
|
||||
EK.on_lose(owner.current)
|
||||
|
||||
owner.special_role = null
|
||||
if(!silent)
|
||||
to_chat(owner.current, "<span class='userdanger'>Your mind begins to flare as the otherwordly knowledge escapes your grasp!</span>")
|
||||
owner.current.log_message("has renounced the cult of the old ones!", LOG_ATTACK, color="#960000")
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
/obj/screen,
|
||||
/obj/singularity,
|
||||
/mob/living/simple_animal/hostile/morph,
|
||||
/obj/effect))
|
||||
/obj/effect,
|
||||
/mob/camera
|
||||
))
|
||||
|
||||
var/playstyle_string = "<span class='big bold'>You are a morph,</span></b> an abomination of science created primarily with changeling cells. \
|
||||
You may take the form of anything nearby by shift-clicking it. This process will alert any nearby \
|
||||
|
||||
@@ -620,6 +620,8 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
|
||||
/obj/item/disk/nuclear/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/bed_tuckable, 6, -6, 0)
|
||||
|
||||
if(!fake)
|
||||
GLOB.poi_list |= src
|
||||
last_disk_move = world.time
|
||||
@@ -634,7 +636,19 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck")
|
||||
var/turf/newturf = get_turf(src)
|
||||
|
||||
if(newturf && lastlocation == newturf)
|
||||
|
||||
// How comfy is disky?
|
||||
var/disk_comfort_level = 0
|
||||
|
||||
// Checking for items that make disky comfy
|
||||
for(var/obj/comfort_item in loc)
|
||||
if(istype(comfort_item, /obj/item/bedsheet) || istype(comfort_item, /obj/structure/bed))
|
||||
disk_comfort_level++
|
||||
|
||||
if(disk_comfort_level >= 2) //Sleep tight, disky.
|
||||
visible_message("<span class='notice'>[src] sleeps soundly. Sleep tight, disky.</span>")
|
||||
if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001))
|
||||
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
|
||||
if(istype(loneop) && loneop.occurrences < loneop.max_occurrences)
|
||||
|
||||
@@ -40,17 +40,18 @@
|
||||
var/rounded_length = round(length)
|
||||
var/new_size
|
||||
var/enlargement = FALSE
|
||||
var/max_D = CONFIG_GET(number/penis_max_inches_prefs)
|
||||
switch(rounded_length)
|
||||
if(0 to 6) //If modest size
|
||||
new_size = 1
|
||||
if(7 to 11) //If large
|
||||
new_size = 2
|
||||
if(12 to 20) //If massive
|
||||
if(12 to max_D) //If massive
|
||||
new_size = 3
|
||||
if(21 to 34) //If massive and due for large effects
|
||||
if(max_D + 1 to max_D+13) //If massive and due for large effects, modified in case some server owner running recent citcode decides to be insane with dick sizes in the config
|
||||
new_size = 3
|
||||
enlargement = TRUE
|
||||
if(35 to INFINITY) //If comical
|
||||
if(max_D+14 to INFINITY) //If comical
|
||||
new_size = 4 //no new sprites for anything larger yet
|
||||
enlargement = TRUE
|
||||
if(owner)
|
||||
|
||||
@@ -179,6 +179,10 @@
|
||||
if((pack.hidden && !(obj_flags & EMAGGED)) || (pack.contraband && !contraband) || pack.DropPodOnly)
|
||||
return
|
||||
|
||||
if(self_paid && !pack.can_private_buy)
|
||||
say("This cannot be bought privately.")
|
||||
return
|
||||
|
||||
var/name = "*None Provided*"
|
||||
var/rank = "*None Provided*"
|
||||
var/ckey = usr.ckey
|
||||
|
||||
@@ -90,6 +90,18 @@
|
||||
crate_name = "medical hardsuit"
|
||||
crate_type = /obj/structure/closet/crate/secure/medical
|
||||
|
||||
/datum/supply_pack/medical/paramedicevasuit
|
||||
name = "Paramedic EVA Suit"
|
||||
desc = "Greytide pushing up daisies with the carp outside the station? Chemistry vented in a meth experiment gone wrong? Be the blue saviour this station desperately needs and get your Paramedical EVA suit today! Requires medical access to open."
|
||||
cost = 1975
|
||||
access = ACCESS_MEDICAL
|
||||
contains = list(/obj/item/tank/internals/emergency_oxygen,
|
||||
/obj/item/clothing/head/helmet/space/eva/paramedic,
|
||||
/obj/item/clothing/suit/space/eva/paramedic,
|
||||
/obj/item/clothing/mask/breath)
|
||||
crate_name = "paramedic EVA suit"
|
||||
crate_type = /obj/structure/closet/crate/secure/medical
|
||||
|
||||
/datum/supply_pack/medical/supplies
|
||||
name = "Medical Supplies Crate"
|
||||
desc = "Contains seven beakers, syringes, and bodybags. Three morphine bottles, four insulin pills. Two charcoal bottles, epinephrine bottles, antitoxin bottles, and large beakers. Finally, a single roll of medical gauze, as well as a bottle of stimulant pills for long, hard work days. German doctor not included."
|
||||
|
||||
@@ -261,9 +261,9 @@
|
||||
/obj/item/reagent_containers/glass/bucket,
|
||||
/obj/item/reagent_containers/glass/bucket,
|
||||
/obj/item/mop,
|
||||
/obj/item/caution,
|
||||
/obj/item/caution,
|
||||
/obj/item/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/item/clothing/suit/caution,
|
||||
/obj/item/storage/bag/trash,
|
||||
/obj/item/reagent_containers/spray/cleaner,
|
||||
/obj/item/reagent_containers/rag,
|
||||
|
||||
@@ -1024,3 +1024,25 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
verb_tabs |= verb_to_init.category
|
||||
verblist[++verblist.len] = list(verb_to_init.category, verb_to_init.name)
|
||||
src << output("[url_encode(json_encode(verb_tabs))];[url_encode(json_encode(verblist))]", "statbrowser:init_verbs")
|
||||
|
||||
//increment progress for an unlockable loadout item
|
||||
/client/proc/increment_progress(key, amount)
|
||||
if(prefs)
|
||||
var/savefile/S = new /savefile(prefs.path)
|
||||
var/list/unlockable_loadout_data = prefs.unlockable_loadout_data
|
||||
if(!length(unlockable_loadout_data))
|
||||
unlockable_loadout_data = list()
|
||||
unlockable_loadout_data[key] = amount
|
||||
WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data))
|
||||
prefs.unlockable_loadout_data = unlockable_loadout_data
|
||||
return TRUE
|
||||
else
|
||||
if(unlockable_loadout_data[key])
|
||||
unlockable_loadout_data[key] += amount
|
||||
else
|
||||
unlockable_loadout_data[key] = amount
|
||||
WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data))
|
||||
prefs.unlockable_loadout_data = unlockable_loadout_data
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -198,6 +198,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/gear_points = 10
|
||||
var/list/gear_categories
|
||||
var/list/loadout_data = list()
|
||||
var/list/unlockable_loadout_data = list()
|
||||
var/loadout_slot = 1 //goes from 1 to MAXIMUM_LOADOUT_SAVES
|
||||
var/gear_category
|
||||
var/gear_subcategory
|
||||
@@ -907,12 +908,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
loadout_color_non_poly = loadout_item[LOADOUT_COLOR][1]
|
||||
extra_color_data += "<BR><a href='?_src_=prefs;preference=gear;loadout_color=1;loadout_gear_name=[html_encode(gear.name)];'>Color</a>"
|
||||
extra_color_data += "<span style='border: 1px solid #161616; background-color: [loadout_color_non_poly];'> </span>"
|
||||
else if(gear_points <= 0)
|
||||
else if((gear_points - gear.cost) < 0)
|
||||
class_link = "style='white-space:normal;' class='linkOff'"
|
||||
else if(donoritem)
|
||||
class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'"
|
||||
else
|
||||
else if(!istype(gear, /datum/gear/unlockable) || can_use_unlockable(gear))
|
||||
class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'"
|
||||
else
|
||||
class_link = "style='white-space:normal;background:#eb2e2e;' class='linkOff'"
|
||||
dat += "<tr style='vertical-align:top;'><td width=15%><a [class_link]>[name]</a>[extra_color_data]</td>"
|
||||
dat += "<td width = 5% style='vertical-align:top'>[gear.cost]</td><td>"
|
||||
if(islist(gear.restricted_roles))
|
||||
@@ -925,7 +928,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<font size=2>"
|
||||
dat += gear.restricted_roles.Join(";")
|
||||
dat += "</font>"
|
||||
dat += "</td><td><font size=2><i>[gear.description]</i></font></td></tr>"
|
||||
if(!istype(gear, /datum/gear/unlockable))
|
||||
dat += "</td><td><font size=2><i>[gear.description]</i></font></td></tr>"
|
||||
else
|
||||
//we add the user's progress to the description assuming they have progress
|
||||
var/datum/gear/unlockable/unlockable = gear
|
||||
var/progress_made = unlockable_loadout_data[unlockable.progress_key]
|
||||
if(!progress_made)
|
||||
progress_made = 0
|
||||
dat += "</td><td><font size=2><i>[gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]</i></font></td></tr>"
|
||||
|
||||
dat += "</table>"
|
||||
if(4) // Content preferences
|
||||
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
|
||||
@@ -2675,6 +2687,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(G.donoritem && !G.donator_ckey_check(user.ckey))
|
||||
to_chat(user, "<span class='danger'>This is an item intended for donator use only. You are not authorized to use this item.</span>")
|
||||
return
|
||||
if(istype(G, /datum/gear/unlockable) && !can_use_unlockable(G))
|
||||
to_chat(user, "<span class='danger'>To use this item, you need to meet the defined requirements!</span>")
|
||||
return
|
||||
if(gear_points >= initial(G.cost))
|
||||
var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]")
|
||||
if(length(G.loadout_initial_colors))
|
||||
@@ -2960,6 +2975,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(find_gear)
|
||||
loadout_data["SAVE_[save_slot]"] -= list(find_gear)
|
||||
|
||||
/datum/preferences/proc/can_use_unlockable(datum/gear/unlockable/unlockable_gear)
|
||||
if(unlockable_loadout_data[unlockable_gear.progress_key] >= unlockable_gear.progress_required)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
#undef DEFAULT_SLOT_AMT
|
||||
#undef HANDS_SLOT_AMT
|
||||
#undef BACKPACK_SLOT_AMT
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// You do not need to raise this if you are adding new values that have sane defaults.
|
||||
// Only raise this value when changing the meaning/format/name/layout of an existing value
|
||||
// where you would want the updater procs below to run
|
||||
#define SAVEFILE_VERSION_MAX 47
|
||||
#define SAVEFILE_VERSION_MAX 48
|
||||
|
||||
/*
|
||||
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
|
||||
@@ -285,6 +285,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
S["loadout"] = safe_json_encode(loadout_data)
|
||||
|
||||
if(current_version < 48) //unlockable loadout items but we need to clear bad data from a mistake
|
||||
S["unlockable_loadout"] = list()
|
||||
|
||||
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
|
||||
if(!ckey)
|
||||
return
|
||||
@@ -427,6 +430,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
if(S["unlockable_loadout"])
|
||||
unlockable_loadout_data = safe_json_decode(S["unlockable_loadout"])
|
||||
else
|
||||
unlockable_loadout_data = list()
|
||||
|
||||
if(needs_update >= 0) //save the updated version
|
||||
var/old_default_slot = default_slot
|
||||
var/old_max_save_slots = max_save_slots
|
||||
@@ -532,6 +540,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["auto_ooc"], auto_ooc)
|
||||
WRITE_FILE(S["no_tetris_storage"], no_tetris_storage)
|
||||
|
||||
if(length(unlockable_loadout_data))
|
||||
WRITE_FILE(S["unlockable_loadout"], safe_json_encode(unlockable_loadout_data))
|
||||
else
|
||||
WRITE_FILE(S["unlockable_loadout"], safe_json_encode(list()))
|
||||
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE)
|
||||
@@ -736,7 +749,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
belly_prefs = json_from_file["belly_prefs"]
|
||||
|
||||
//gear loadout
|
||||
loadout_data = safe_json_decode(S["loadout"])
|
||||
if(S["loadout"])
|
||||
loadout_data = safe_json_decode(S["loadout"])
|
||||
else
|
||||
loadout_data = list()
|
||||
|
||||
//try to fix any outdated data if necessary
|
||||
//preference updating will handle saving the updated data for us.
|
||||
|
||||
@@ -17,7 +17,7 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC")
|
||||
if(!msg)
|
||||
return
|
||||
|
||||
if(!(prefs.toggles & CHAT_OOC))
|
||||
if(!(prefs.chat_toggles & CHAT_OOC))
|
||||
to_chat(src, "<span class='danger'> You have OOC muted.</span>")
|
||||
return
|
||||
if(jobban_isbanned(mob, "OOC"))
|
||||
@@ -63,14 +63,14 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC")
|
||||
if (isobserver(M))
|
||||
continue //Also handled later.
|
||||
|
||||
if(C.prefs.toggles & CHAT_OOC)
|
||||
if(C.prefs.chat_toggles & CHAT_OOC)
|
||||
if(GLOB.LOOC_COLOR)
|
||||
to_chat(C, "<font color='[GLOB.LOOC_COLOR]'><b><span class='prefix'>LOOC:</span> <EM>[src.mob.name]:</EM> <span class='message'>[msg]</span></b></font>")
|
||||
else
|
||||
to_chat(C, "<span class='looc'><span class='prefix'>LOOC:</span> <EM>[src.mob.name]:</EM> <span class='message'>[msg]</span></span>")
|
||||
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(C.prefs.toggles & CHAT_OOC)
|
||||
if(C.prefs.chat_toggles & CHAT_OOC)
|
||||
var/prefix = "(R)LOOC"
|
||||
if (C.mob in heard)
|
||||
prefix = "LOOC"
|
||||
|
||||
@@ -541,6 +541,21 @@
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/clothing/mask/facehugger/toy)
|
||||
|
||||
/obj/item/clothing/suit/caution
|
||||
name = "wet floor sign"
|
||||
desc = "Caution! Wet Floor!"
|
||||
icon_state = "caution"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
|
||||
force = 1
|
||||
throwforce = 3
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
body_parts_covered = CHEST|GROIN
|
||||
attack_verb = list("warned", "cautioned", "smashed")
|
||||
armor = list("melee" = 5, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
|
||||
// WINTER COATS
|
||||
|
||||
/obj/item/clothing/suit/hooded/wintercoat
|
||||
|
||||
@@ -244,35 +244,33 @@
|
||||
/obj/item/clothing/under/proc/rolldown()
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!can_adjust)
|
||||
to_chat(usr, "<span class='warning'>You cannot wear this suit any differently!</span>")
|
||||
return
|
||||
if(toggle_jumpsuit_adjust())
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit to wear it more casually.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit back to normal.</span>")
|
||||
if(ishuman(usr))
|
||||
if(toggle_jumpsuit_adjust() && ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.update_inv_w_uniform()
|
||||
H.update_body()
|
||||
|
||||
/obj/item/clothing/under/proc/toggle_jumpsuit_adjust()
|
||||
if(!can_adjust)
|
||||
to_chat(usr, "<span class='warning'>You cannot wear this suit any differently!</span>")
|
||||
return FALSE
|
||||
adjusted = !adjusted
|
||||
|
||||
if(adjusted)
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit to wear it more casually.</span>")
|
||||
if(fitted != FEMALE_UNIFORM_TOP)
|
||||
fitted = NO_FEMALE_UNIFORM
|
||||
if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted
|
||||
body_parts_covered &= ~CHEST
|
||||
mutantrace_variation &= ~USE_TAUR_CLIP_MASK //How are we supposed to see the uniform otherwise?
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit back to normal.</span>")
|
||||
fitted = initial(fitted)
|
||||
if(!alt_covers_chest)
|
||||
body_parts_covered |= CHEST
|
||||
if(initial(mutantrace_variation) & USE_TAUR_CLIP_MASK)
|
||||
mutantrace_variation |= USE_TAUR_CLIP_MASK
|
||||
|
||||
return adjusted
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/under/rank
|
||||
dying_key = DYE_REGISTRY_UNDER
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
|
||||
|
||||
/obj/item/clothing/under/rank/civilian/util
|
||||
name = "generic utility uniform"
|
||||
name = "utility uniform"
|
||||
desc = "A utility uniform worn by various crew."
|
||||
icon_state = "utilgen"
|
||||
item_state = "utilgen"
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
name = "captain's jumpsuit"
|
||||
icon_state = "captain"
|
||||
item_state = "b_suit"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15)
|
||||
sensor_mode = SENSOR_COORDS
|
||||
random_sensor = FALSE
|
||||
|
||||
/obj/item/clothing/under/rank/captain/util
|
||||
name = "Command Utiltiy Uniform"
|
||||
name = "command utility uniform"
|
||||
desc = "A utility uniform for command personnel."
|
||||
icon_state = "utilcom"
|
||||
item_state = "utilcom"
|
||||
@@ -26,7 +27,6 @@
|
||||
/obj/item/clothing/under/rank/captain/suit
|
||||
name = "captain's suit"
|
||||
desc = "A green suit and yellow necktie. Exemplifies authority."
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15)
|
||||
icon_state = "green_suit"
|
||||
item_state = "dg_suit"
|
||||
can_adjust = FALSE
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5)
|
||||
|
||||
/obj/item/clothing/under/rank/medical/doctor/util
|
||||
name = "Medical Utility Uniform"
|
||||
name = "medical utility uniform"
|
||||
desc = "Utility jumpsuit for medical personnel"
|
||||
icon_state = "utilmed"
|
||||
item_state = "utilmed"
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5)
|
||||
|
||||
/obj/item/clothing/under/rank/rnd/scientist/util
|
||||
name = "Science Utility Uniform"
|
||||
name = "science utility uniform"
|
||||
desc = "A utility uniform for science personnel"
|
||||
icon_state = "utilsci"
|
||||
item_state = "utilsci"
|
||||
|
||||
@@ -172,11 +172,13 @@
|
||||
body_parts_covered = CHEST|GROIN
|
||||
|
||||
/obj/item/clothing/under/misc/gear_harness/toggle_jumpsuit_adjust()
|
||||
adjusted = !adjusted
|
||||
if(adjusted)
|
||||
body_parts_covered = NONE
|
||||
else
|
||||
if(!body_parts_covered)
|
||||
to_chat(usr, "<span class='notice'>Your gear harness is now covering your chest and groin.</span>")
|
||||
body_parts_covered = CHEST|GROIN
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Your gear harness is no longer covering anything.</span>")
|
||||
body_parts_covered = NONE
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/under/misc/durathread
|
||||
name = "durathread jumpsuit"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
var/fraction = min(gulp_size/reagents.total_volume, 1)
|
||||
checkLiked(fraction, M)
|
||||
reagents.reaction(M, INGEST, fraction)
|
||||
reagents.trans_to(M, gulp_size)
|
||||
reagents.trans_to(M, gulp_size, log = TRUE)
|
||||
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
|
||||
return 1
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
return
|
||||
|
||||
var/refill = reagents.get_master_reagent_id()
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE)
|
||||
to_chat(user, "<span class='notice'>You transfer [trans] units of the solution to [target].</span>")
|
||||
|
||||
if(iscyborg(user)) //Cyborg modules that include drinks automatically refill themselves, but drain the borg's cell
|
||||
@@ -92,7 +92,7 @@
|
||||
to_chat(user, "<span class='warning'>[src] is full.</span>")
|
||||
return
|
||||
|
||||
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
|
||||
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = TRUE)
|
||||
to_chat(user, "<span class='notice'>You fill [src] with [trans] units of the contents of [target].</span>")
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/attackby(obj/item/I, mob/user, params)
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
var/fraction = min(10/reagents.total_volume, 1)
|
||||
reagents.reaction(M, INGEST, fraction)
|
||||
reagents.trans_to(M, 10)
|
||||
reagents.trans_to(M, 10, log = TRUE)
|
||||
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
|
||||
return 1
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
to_chat(user, "<span class='warning'>[src] is full!</span>")
|
||||
return
|
||||
|
||||
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
|
||||
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this, log = TRUE)
|
||||
to_chat(user, "<span class='notice'>You fill [src] with [trans] units of the contents of [target].</span>")
|
||||
|
||||
//Something like a glass or a food item. Player probably wants to transfer TO it.
|
||||
@@ -84,7 +84,7 @@
|
||||
if(target.reagents.total_volume >= target.reagents.maximum_volume)
|
||||
to_chat(user, "<span class='warning'>you can't add anymore to [target]!</span>")
|
||||
return
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
|
||||
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE)
|
||||
to_chat(user, "<span class='notice'>You transfer [trans] units of the condiment to [target].</span>")
|
||||
|
||||
/obj/item/reagent_containers/food/condiment/on_reagent_change(changetype)
|
||||
@@ -270,7 +270,7 @@
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You tear open [src] above [target] and the condiments drip onto it.</span>")
|
||||
src.reagents.trans_to(target, amount_per_transfer_from_this)
|
||||
src.reagents.trans_to(target, amount_per_transfer_from_this, log = TRUE)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/condiment/pack/on_reagent_change(changetype)
|
||||
|
||||
@@ -160,7 +160,7 @@ All foods are distributed among various categories. Use common sense.
|
||||
SEND_SIGNAL(src, COMSIG_FOOD_EATEN, M, user)
|
||||
var/fraction = min(bitesize / reagents.total_volume, 1)
|
||||
reagents.reaction(M, INGEST, fraction)
|
||||
reagents.trans_to(M, bitesize)
|
||||
reagents.trans_to(M, bitesize, log = TRUE)
|
||||
bitecount++
|
||||
On_Consume(M)
|
||||
checkLiked(fraction, M)
|
||||
@@ -359,7 +359,7 @@ All foods are distributed among various categories. Use common sense.
|
||||
if(!M.is_drainable())
|
||||
to_chat(user, "<span class='warning'>[M] is unable to be dunked in!</span>")
|
||||
return
|
||||
if(M.reagents.trans_to(src, dunk_amount)) //if reagents were transfered, show the message
|
||||
if(M.reagents.trans_to(src, dunk_amount, log = TRUE)) //if reagents were transfered, show the message
|
||||
to_chat(user, "<span class='notice'>You dunk the [M].</span>")
|
||||
return
|
||||
if(!M.reagents.total_volume)
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
foodtype = GRAIN
|
||||
dunkable = TRUE
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/store/bread/proc/bread_teleport()
|
||||
// you did WHAT?
|
||||
new /mob/living/simple_animal/hostile/bread(get_turf(src))
|
||||
visible_message("<span class='warning'>[src] begins to deform and grow grotesque tumors!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/breadslice
|
||||
icon = 'icons/obj/food/burgerbread.dmi'
|
||||
bitesize = 2
|
||||
@@ -228,3 +234,25 @@
|
||||
/obj/item/reagent_containers/food/snacks/butterdog/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/slippery, 80)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/store/bread/tumor_bread
|
||||
name = "dead tumor bread"
|
||||
desc = "It's still within its expiration date, right?"
|
||||
icon_state = "tumorbread"
|
||||
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/tumor_bread
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/toxin = 10)
|
||||
foodtype = GROSS | GRAIN
|
||||
tastes = list("wheat and tumors" = 10)
|
||||
|
||||
//teleporting tumor bread kills it
|
||||
/obj/item/reagent_containers/food/snacks/store/bread/tumor_bread/bread_teleport()
|
||||
visible_message(src, "<span class='warning'>[src] explodes in a horrible mess of tumor and flour!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/breadslice/tumor_bread
|
||||
name = "tumor bread slice"
|
||||
desc = "A slice of bread filled with tumors!"
|
||||
icon_state = "tumorbreadslice"
|
||||
filling_color = "#B2D72C"
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin = 2)
|
||||
foodtype = GROSS | GRAIN
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
H.visible_message("<span class='warning'>[H] is creamed by [src]!</span>", "<span class='userdanger'>You've been creamed by [src]!</span>")
|
||||
playsound(H, "desceration", 50, TRUE)
|
||||
if(!H.is_mouth_covered())
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
reagents.trans_to(H, 15, log = TRUE) //Cream pie combat
|
||||
if(!H.creamed) // one layer at a time
|
||||
H.add_overlay(creamoverlay)
|
||||
H.creamed = TRUE
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
/obj/machinery/microwave/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
cook()
|
||||
cook(user)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/microwave/ui_interact(mob/user)
|
||||
@@ -226,7 +226,7 @@
|
||||
if("eject")
|
||||
eject()
|
||||
if("use")
|
||||
cook()
|
||||
cook(user)
|
||||
if("examine")
|
||||
examine(user)
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
AM.forceMove(drop_location())
|
||||
ingredients.Cut()
|
||||
|
||||
/obj/machinery/microwave/proc/cook()
|
||||
/obj/machinery/microwave/proc/cook(mob/user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(operating || broken > 0 || panel_open || !anchored || dirty == 100)
|
||||
@@ -257,7 +257,7 @@
|
||||
start_can_fail()
|
||||
return
|
||||
break
|
||||
start()
|
||||
start(user)
|
||||
|
||||
/obj/machinery/microwave/proc/turn_on()
|
||||
visible_message("\The [src] turns on.", "<span class='italics'>You hear a microwave humming.</span>")
|
||||
@@ -277,9 +277,9 @@
|
||||
#define MICROWAVE_MUCK 1
|
||||
#define MICROWAVE_PRE 2
|
||||
|
||||
/obj/machinery/microwave/proc/start()
|
||||
/obj/machinery/microwave/proc/start(mob/user)
|
||||
turn_on()
|
||||
loop(MICROWAVE_NORMAL, 10)
|
||||
loop(MICROWAVE_NORMAL, 10, user = user)
|
||||
|
||||
/obj/machinery/microwave/proc/start_can_fail()
|
||||
turn_on()
|
||||
@@ -292,7 +292,7 @@
|
||||
update_icon()
|
||||
loop(MICROWAVE_MUCK, 4)
|
||||
|
||||
/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2)) // standard wait is 10
|
||||
/obj/machinery/microwave/proc/loop(type, time, wait = max(12 - 2 * productivity, 2), mob/user) // standard wait is 10
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
if(type == MICROWAVE_PRE)
|
||||
pre_fail()
|
||||
@@ -300,7 +300,7 @@
|
||||
if(!time)
|
||||
switch(type)
|
||||
if(MICROWAVE_NORMAL)
|
||||
loop_finish()
|
||||
loop_finish(user)
|
||||
if(MICROWAVE_MUCK)
|
||||
muck_finish()
|
||||
if(MICROWAVE_PRE)
|
||||
@@ -308,16 +308,21 @@
|
||||
return
|
||||
time--
|
||||
use_power(500)
|
||||
addtimer(CALLBACK(src, .proc/loop, type, time, wait), wait)
|
||||
addtimer(CALLBACK(src, .proc/loop, type, time, wait, user), wait)
|
||||
|
||||
/obj/machinery/microwave/proc/loop_finish()
|
||||
/obj/machinery/microwave/proc/loop_finish(mob/user)
|
||||
operating = FALSE
|
||||
|
||||
var/metal = 0
|
||||
var/cooked_food = 0
|
||||
for(var/obj/item/O in ingredients)
|
||||
O.microwave_act(src)
|
||||
var/cooked_result = O.microwave_act(src)
|
||||
if(!istype(cooked_result, /obj/item/reagent_containers/food/snacks/badrecipe))
|
||||
cooked_food += 1
|
||||
if(O.custom_materials?.len)
|
||||
metal += O.custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]
|
||||
if(cooked_food && user.client)
|
||||
user.client.increment_progress("cook", cooked_food)
|
||||
|
||||
if(metal)
|
||||
spark()
|
||||
@@ -336,8 +341,8 @@
|
||||
spark()
|
||||
after_finish_loop()
|
||||
|
||||
/obj/machinery/microwave/proc/pre_success()
|
||||
loop(MICROWAVE_NORMAL, 10)
|
||||
/obj/machinery/microwave/proc/pre_success(mob/user)
|
||||
loop(MICROWAVE_NORMAL, 10, user)
|
||||
|
||||
/obj/machinery/microwave/proc/muck_finish()
|
||||
visible_message("<span class='warning'>\The [src] gets covered in muck!</span>")
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
reagents.remove_any(min(0.5, nutridrain))
|
||||
else
|
||||
reagents.remove_any(nutridrain)
|
||||
|
||||
|
||||
// Lack of nutrients hurts non-weeds
|
||||
if(reagents.total_volume <= 0 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
|
||||
adjustHealth(-rand(1,3))
|
||||
@@ -501,7 +501,7 @@
|
||||
if(visi_msg)
|
||||
visible_message("<span class='notice'>[visi_msg].</span>")
|
||||
|
||||
|
||||
|
||||
for(var/obj/machinery/hydroponics/H in trays)
|
||||
//cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener
|
||||
//This was originally in apply_chemicals, but due to apply_chemicals only holding nutrients, we handle it here now.
|
||||
@@ -675,7 +675,7 @@
|
||||
idle_power_usage = 0
|
||||
self_sustaining = FALSE
|
||||
update_icon()
|
||||
|
||||
|
||||
/// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds.///
|
||||
/obj/machinery/hydroponics/proc/adjustWater(adjustamt)
|
||||
waterlevel = clamp(waterlevel + adjustamt, 0, maxwater)
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
var/map_name = "Box Station"
|
||||
var/map_path = "map_files/BoxStation"
|
||||
var/map_file = "BoxStation.dmm"
|
||||
/// Persistence key: Defaults to ckey(map_name). If set to "NO_PERSIST", this map will have NO persistence.
|
||||
var/persistence_key
|
||||
|
||||
var/traits = null
|
||||
var/space_ruin_levels = 4
|
||||
@@ -99,6 +101,16 @@
|
||||
map_path = json["map_path"]
|
||||
|
||||
map_file = json["map_file"]
|
||||
|
||||
persistence_key = ckey(map_name)
|
||||
|
||||
var/json_persistence_key = json["persistence_key"]
|
||||
if(json_persistence_key)
|
||||
if(json_persistence_key == "NO_PERSIST")
|
||||
persistence_key = null
|
||||
else
|
||||
persistence_key = json_persistence_key
|
||||
|
||||
// "map_file": "BoxStation.dmm"
|
||||
if (istext(map_file))
|
||||
if (!fexists("_maps/[map_path]/[map_file]"))
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
if(points)
|
||||
if(I)
|
||||
I.mining_points += points
|
||||
if(usr.client)
|
||||
usr.client.increment_progress("miner", points)
|
||||
points = 0
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>No ID detected.</span>")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user