Merge branch 'master' into Dispencer-UI-change
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
#define BODYPART_NANITES 4
|
||||
|
||||
#define HYBRID_BODYPART_DAMAGE_THRESHHOLD 25 //How much damage has to be suffered until the damage threshhold counts as passed
|
||||
#define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 15 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage.
|
||||
#define HYBRID_BODYPART_THESHHOLD_MINDAMAGE 10 //Which damage value this limb cannot be healed out of via easy nonsurgical means if the threshhold has been passed, state resets if damage value goes below mindamage.
|
||||
|
||||
#define BODYPART_NOT_DISABLED 0
|
||||
#define BODYPART_DISABLED_DAMAGE 1
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
|
||||
#define STATUS_EFFECT_DETERMINED /datum/status_effect/determined //currently in a combat high from being seriously wounded
|
||||
|
||||
#define STATUS_EFFECT_MANTRA /datum/status_effect/mantra // a toggled self buff that makes you stronger and more resilient, but drains stamina over time
|
||||
#define STATUS_EFFECT_ASURA /datum/status_effect/asura // like a weaker version of mantra, drains HP instead of stamina and has no armor
|
||||
|
||||
/////////////
|
||||
// DEBUFFS //
|
||||
/////////////
|
||||
@@ -102,10 +105,6 @@
|
||||
|
||||
#define STATUS_EFFECT_FAKE_VIRUS /datum/status_effect/fake_virus //gives you fluff messages for cough, sneeze, headache, etc but without an actual virus
|
||||
|
||||
#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk.
|
||||
|
||||
#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.
|
||||
|
||||
#define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect/no_combat_mode //Wont allow combat mode and will disable it
|
||||
#define STATUS_EFFECT_MESMERIZE /datum/status_effect/mesmerize //Just reskinned no_combat_mode
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -271,7 +271,7 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
if(skip_mindless && (!M.mind && !M.ckey))
|
||||
if(!isbot(M) && !iscameramob(M) && !ismegafauna(M))
|
||||
continue
|
||||
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
|
||||
if(M.client?.holder?.fakekey && isobserver(M))
|
||||
continue
|
||||
var/name = avoid_assoc_duplicate_keys(M.name, namecounts)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/effect/spawner/lootdrop/welder_tools = 3,
|
||||
/obj/effect/spawner/lootdrop/low_tools = 5,
|
||||
/obj/item/relic = 3,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 2,
|
||||
/obj/item/weaponcrafting/receiver = 2,
|
||||
/obj/item/clothing/head/cone = 2,
|
||||
/obj/item/grenade/smokebomb = 2,
|
||||
/obj/item/geiger_counter = 3,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
/obj/item/weaponcrafting
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
|
||||
/obj/item/weaponcrafting/receiver
|
||||
name = "modular receiver"
|
||||
desc = "A prototype modular receiver and trigger assembly for a firearm."
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
icon_state = "receiver"
|
||||
|
||||
/obj/item/weaponcrafting/stock
|
||||
name = "rifle stock"
|
||||
desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood."
|
||||
@@ -12,41 +18,3 @@
|
||||
name = "wound thread"
|
||||
desc = "A long piece of thread with some resemblance to cable coil."
|
||||
icon_state = "durastring"
|
||||
|
||||
////////////////////////////////
|
||||
// IMPROVISED WEAPON PARTS//
|
||||
////////////////////////////////
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts
|
||||
name = "Debug Improvised Gun Part"
|
||||
desc = "A badly coded gun part. You should report coders if you see this."
|
||||
icon = 'icons/obj/guns/gun_parts.dmi'
|
||||
icon_state = "palette"
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
name = "rifle receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_rifle"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
name = "shotgun reciever"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_shotgun"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
// MISC
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly
|
||||
name = "firearm trigger assembly"
|
||||
desc = "A modular trigger assembly with a firing pin, this can be used to make a whole bunch of improvised firearss."
|
||||
icon_state = "trigger_assembly"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body
|
||||
name = "wooden firearm body"
|
||||
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
|
||||
icon_state = "wooden_body"
|
||||
|
||||
@@ -172,11 +172,11 @@
|
||||
///////////////////
|
||||
|
||||
/datum/crafting_recipe/upgraded_gauze
|
||||
name = "Improved Gauze"
|
||||
name = "Sterilized Gauze"
|
||||
result = /obj/item/stack/medical/gauze/adv/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/space_cleaner/sterilizine = 10)
|
||||
/datum/reagent/space_cleaner/sterilizine = 5)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
name = "Suture Pack"
|
||||
result = /obj/item/stack/medical/suture/five
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
reqs = list(/obj/item/stack/medical/gauze/adv = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
@@ -193,7 +193,7 @@
|
||||
name = "Regenerative Mesh"
|
||||
result = /obj/item/stack/medical/mesh/five
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
reqs = list(/obj/item/stack/medical/gauze/adv = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bokken_steelwood
|
||||
name = "Training Bokken"
|
||||
name = "Training Steelwood Bokken"
|
||||
result = /obj/item/melee/bokken/steelwood
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/bokken_steelblade = 1,
|
||||
@@ -294,33 +294,18 @@
|
||||
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
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
/obj/item/weaponcrafting/stock = 1,
|
||||
/obj/item/stack/packageWrap = 5)
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/irifle // larger and less versatile gun, but a bit easier to make
|
||||
name = "Improvised Rifle (7.62mm)"
|
||||
result = /obj/item/gun/ballistic/shotgun/boltaction/improvised
|
||||
reqs = list(/obj/item/pipe = 2, // above
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
reqs = list(/obj/item/pipe = 1,
|
||||
/obj/item/weaponcrafting/receiver = 1,
|
||||
/obj/item/weaponcrafting/stock = 1,
|
||||
/obj/item/stack/packageWrap = 5)
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
//the Improvised Rifle will not be missed. Rest in Pieces 2019-2021
|
||||
|
||||
//////////////////
|
||||
///AMMO CRAFTING//
|
||||
@@ -449,38 +434,6 @@
|
||||
// PARTS CRAFTING //
|
||||
////////////////////
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/datum/crafting_recipe/rifle_receiver
|
||||
name = "Improvised Rifle Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_receiver
|
||||
name = "Improvised Shotgun Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10) // shotgun does less damage than the rifle and can't 1shot but is more portable
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// MISC
|
||||
|
||||
/datum/crafting_recipe/trigger_assembly
|
||||
name = "Trigger Assembly"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/trigger_assembly
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// BOKKEN CRAFTING
|
||||
|
||||
/datum/crafting_recipe/bokken_blade
|
||||
@@ -510,7 +463,7 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/wakibokken_blade
|
||||
/datum/crafting_recipe/wakibokken_steelblade
|
||||
name = "Training Wakizashi Ironwood Bokken Blade"
|
||||
result = /obj/item/wakibokken_steelblade
|
||||
tools = list(/obj/item/hatchet, TOOL_WELDER)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -573,13 +573,17 @@
|
||||
duration = 1 MINUTES
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = /obj/screen/alert/status_effect/regenerative_core
|
||||
var/heal_amount = 25
|
||||
|
||||
/datum/status_effect/regenerative_core/on_apply()
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
|
||||
owner.adjustBruteLoss(-25)
|
||||
|
||||
if(HAS_TRAIT(owner, TRAIT_ROBOTIC_ORGANISM)) //Robots can heal from cores, but only get 1/5th of the healing. They can use this to get past the damage threshhold however, and then regularely heal from there.
|
||||
heal_amount *= 0.2
|
||||
owner.adjustBruteLoss(-heal_amount, only_organic = FALSE)
|
||||
if(!AmBloodsucker(owner)) //use your coffin you lazy bastard
|
||||
owner.adjustFireLoss(-25)
|
||||
owner.adjustFireLoss(-heal_amount, only_organic = FALSE)
|
||||
owner.remove_CC()
|
||||
owner.bodytemperature = BODYTEMP_NORMAL
|
||||
return TRUE
|
||||
@@ -647,3 +651,120 @@
|
||||
if(D.severity == DISEASE_SEVERITY_POSITIVE)
|
||||
continue
|
||||
D.cure()
|
||||
|
||||
/datum/status_effect/mantra // available to wizards and admins alone, currently
|
||||
id = "Mantra"
|
||||
examine_text = "<span class='notice'>Their aura is filled with yellow energy!</span>"
|
||||
alert_type = null
|
||||
var/damageboost = 10
|
||||
var/woundboost = 5
|
||||
var/prev_hair_color
|
||||
var/powerup
|
||||
var/powerdown
|
||||
|
||||
/datum/status_effect/mantra/on_apply()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
playsound(H, 'sound/magic/powerup.ogg', 50, 1)
|
||||
H.add_filter("mantra_glow", 2, list("type" = "outline", "color" = "#edfa347a", "size" = 2))
|
||||
prev_hair_color = H.hair_color
|
||||
H.hair_color = "ffe11e"
|
||||
H.update_hair()
|
||||
ADD_TRAIT(H, TRAIT_PUGILIST, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_NOSOFTCRIT, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_STUNIMMUNE, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_PUSHIMMUNE, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_NOGUNS, "Mantra")
|
||||
H.dna.species.punchdamagehigh += damageboost
|
||||
H.dna.species.punchdamagelow += damageboost
|
||||
H.dna.species.punchwoundbonus += woundboost
|
||||
H.physiology.brute_mod *= 0.9 // slightly resilient against lethal damage, but...
|
||||
H.physiology.burn_mod *= 0.9
|
||||
H.physiology.stamina_mod *= 0.5 // very resistant to non-lethal damage, because they're already draining stamina every second
|
||||
to_chat(H, "<span class='notice'>Your inner mantra coalesces around you, granting you incredible strength and durability - but at what cost?</span>")
|
||||
|
||||
/datum/status_effect/mantra/tick()
|
||||
. = ..()
|
||||
if(owner.health < HEALTH_THRESHOLD_FULLCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_MANTRA)
|
||||
return
|
||||
if(owner.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_MANTRA)
|
||||
return
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/C = owner
|
||||
C.adjustBruteLoss(-1) // slightly resilient against lethal damage
|
||||
C.adjustFireLoss(-1)
|
||||
C.adjustStaminaLoss(3) // in testing i personally found that 2/sec was too minimal and 4/sec was too much
|
||||
/*if(SEND_SIGNAL(owner, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) // turning on combat mode flares up your aura
|
||||
|
||||
else*/
|
||||
|
||||
/datum/status_effect/mantra/on_remove()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/M = owner
|
||||
playsound(M, 'sound/magic/powerdown.ogg', 50, 1)
|
||||
M.remove_filter("mantra_glow")
|
||||
M.hair_color = prev_hair_color
|
||||
M.update_hair()
|
||||
REMOVE_TRAIT(M, TRAIT_PUGILIST, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_NOSOFTCRIT, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_STUNIMMUNE, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_PUSHIMMUNE, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_NOGUNS, "Mantra")
|
||||
M.dna.species.punchdamagehigh -= damageboost
|
||||
M.dna.species.punchdamagelow -= damageboost
|
||||
M.dna.species.punchwoundbonus -= woundboost
|
||||
M.physiology.brute_mod /= 0.9
|
||||
M.physiology.burn_mod /= 0.9
|
||||
M.physiology.stamina_mod /= 0.5
|
||||
to_chat(M, "<span class='notice'>Your inner mantra collapses, for now.</span>")
|
||||
|
||||
/datum/status_effect/asura // mfw miner gear
|
||||
id = "Asura"
|
||||
examine_text = "<span class='notice'>Their aura is filled with red-hot rage!</span>"
|
||||
alert_type = null
|
||||
var/damageboost = 10
|
||||
var/woundboost = 5
|
||||
|
||||
/datum/status_effect/asura/on_apply()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
playsound(H, 'sound/magic/powerup.ogg', 50, 1)
|
||||
H.add_filter("asura_glow", 2, list("type" = "outline", "color" = "#fc21217a", "size" = 2))
|
||||
ADD_TRAIT(H, TRAIT_PUGILIST, "Asura")
|
||||
H.dna.species.punchdamagehigh += damageboost
|
||||
H.dna.species.punchdamagelow += damageboost
|
||||
H.dna.species.punchwoundbonus += woundboost
|
||||
to_chat(H, "<span class='notice'>Your anger unleashes in a crimson blaze around you and corrosive power fills your muscles.</span>")
|
||||
|
||||
/datum/status_effect/asura/tick()
|
||||
. = ..()
|
||||
if(owner.health < HEALTH_THRESHOLD_CRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_ASURA)
|
||||
return
|
||||
if(owner.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_ASURA)
|
||||
return
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/C = owner
|
||||
C.adjustBruteLoss(1) // drains 1 hp per second. You're gonna need some Senzu Cores.
|
||||
C.adjustStaminaLoss(-2) // angry man punch a lot
|
||||
/*if(SEND_SIGNAL(owner, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) // turning on combat mode flares up your aura
|
||||
|
||||
else*/
|
||||
|
||||
/datum/status_effect/asura/on_remove()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/M = owner
|
||||
playsound(M, 'sound/magic/powerdown.ogg', 50, 1)
|
||||
M.remove_filter("asura_glow")
|
||||
REMOVE_TRAIT(M, TRAIT_PUGILIST, "Asura")
|
||||
M.dna.species.punchdamagehigh -= damageboost
|
||||
M.dna.species.punchdamagelow -= damageboost
|
||||
M.dna.species.punchwoundbonus -= woundboost
|
||||
to_chat(M, "<span class='notice'>You calm yourself, and your unnatural strength dissipates.</span>")
|
||||
|
||||
@@ -74,13 +74,19 @@
|
||||
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
if(blocks_combatmode)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
if(blocks_sprint)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
|
||||
owner.clear_alert(id)
|
||||
LAZYREMOVE(owner.status_effects, src)
|
||||
if(blocks_combatmode)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
if(blocks_sprint)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
owner = null
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("gr", color_matrix_last[2])
|
||||
dat += MATRIX_FIELD("br", color_matrix_last[3])
|
||||
dat += MATRIX_FIELD("gr", color_matrix_last[4])
|
||||
dat += MATRIX_FIELD("br", color_matrix_last[7])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("rg", color_matrix_last[4])
|
||||
dat += MATRIX_FIELD("rg", color_matrix_last[2])
|
||||
dat += MATRIX_FIELD("gg", color_matrix_last[5])
|
||||
dat += MATRIX_FIELD("bg", color_matrix_last[6])
|
||||
dat += MATRIX_FIELD("bg", color_matrix_last[8])
|
||||
dat += "<br><br>"
|
||||
dat += MATRIX_FIELD("rb", color_matrix_last[7])
|
||||
dat += MATRIX_FIELD("gb", color_matrix_last[8])
|
||||
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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
if(.)
|
||||
return
|
||||
if(can_buckle && has_buckled_mobs())
|
||||
if(ishuman(src)) //prevent people from unbuckling fireman-carried/piggybacked people unless on disarm or harm intents
|
||||
if(act_intent == INTENT_HELP || act_intent == INTENT_GRAB)
|
||||
return
|
||||
if(buckled_mobs.len > 1)
|
||||
var/unbuckled = input(user, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in buckled_mobs
|
||||
if(user_unbuckle_mob(unbuckled,user))
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -664,9 +664,8 @@
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 50,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 13,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 13,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 12,
|
||||
/obj/item/weaponcrafting/receiver = 25,
|
||||
/obj/item/weaponcrafting/stock = 25,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/weapon_parts
|
||||
@@ -674,8 +673,8 @@
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 80,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 5,
|
||||
/obj/item/weaponcrafting/receiver = 5,
|
||||
/obj/item/weaponcrafting/stock = 5,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/ammo
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -803,6 +803,7 @@
|
||||
force = 4
|
||||
throwforce = 0
|
||||
attack_verb = list("whipped", "repented", "lashed", "flagellated")
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
var/praying = FALSE
|
||||
var/deity_name = "Coderbus" //This is the default, hopefully won't actually appear if the religion subsystem is running properly
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -173,11 +173,11 @@
|
||||
"<span class='italics'>You hear cutting.</span>")
|
||||
use(2)
|
||||
else if(I.is_drainable() && I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine))
|
||||
if(!I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine, 10))
|
||||
if(!I.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine, 5))
|
||||
to_chat(user, "<span class='warning'>There's not enough sterilizine in [I] to sterilize [src]!</span>")
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] pours the contents of [I] onto [src], sterilizing it.</span>", "<span class='notice'>You pour the contents of [I] onto [src], sterilizing it.</span>")
|
||||
I.reagents.remove_reagent(/datum/reagent/space_cleaner/sterilizine, 10)
|
||||
user.visible_message("<span class='notice'>[user] sterilizes [src] with the contents of [I].</span>", "<span class='notice'>You pour the contents of [I] onto [src], sterilizing it.</span>")
|
||||
I.reagents.remove_reagent(/datum/reagent/space_cleaner/sterilizine, 5)
|
||||
new /obj/item/stack/medical/gauze/adv/one(user.drop_location())
|
||||
use(1)
|
||||
else
|
||||
@@ -187,6 +187,9 @@
|
||||
user.visible_message("<span class='suicide'>[user] begins tightening \the [src] around [user.p_their()] neck! It looks like [user.p_they()] forgot how to use medical supplies!</span>")
|
||||
return OXYLOSS
|
||||
|
||||
/obj/item/stack/medical/gauze/one
|
||||
amount = 1
|
||||
|
||||
/obj/item/stack/medical/gauze/improvised
|
||||
name = "improvised gauze"
|
||||
singular_name = "improvised gauze"
|
||||
@@ -204,8 +207,9 @@
|
||||
heal_brute = 6
|
||||
self_delay = 45
|
||||
other_delay = 15
|
||||
absorption_rate = 0.4
|
||||
absorption_capacity = 6
|
||||
absorption_rate = 0.5
|
||||
absorption_capacity = 12
|
||||
splint_factor = 0.15
|
||||
|
||||
/obj/item/stack/medical/gauze/adv/one
|
||||
amount = 1
|
||||
|
||||
@@ -246,7 +246,6 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
|
||||
new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
)),
|
||||
null, \
|
||||
new/datum/stack_recipe("wooden firearm body", /obj/item/weaponcrafting/improvised_parts/wooden_body, 10, time = 20), \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 20), \
|
||||
new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \
|
||||
new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 30), \
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
return FALSE
|
||||
stunpwr *= round(stuncharge/hitcost, 0.1)
|
||||
|
||||
if(!user.UseStaminaBuffer(getweight(user, STAM_COST_BATON_MOB_MULT), warn = TRUE))
|
||||
if(user && !user.UseStaminaBuffer(getweight(user, STAM_COST_BATON_MOB_MULT), warn = TRUE))
|
||||
return FALSE
|
||||
|
||||
if(!disarming)
|
||||
@@ -314,12 +314,12 @@
|
||||
/obj/item/melee/baton/boomerang
|
||||
name = "\improper OZtek Boomerang"
|
||||
desc = "A device invented in 2486 for the great Space Emu War by the confederacy of Australicus, these high-tech boomerangs also work exceptionally well at stunning crewmembers. Just be careful to catch it when thrown!"
|
||||
throw_speed = 1
|
||||
throw_speed = 1.5
|
||||
icon_state = "boomerang"
|
||||
item_state = "boomerang"
|
||||
force = 5
|
||||
throwforce = 5
|
||||
throw_range = 5
|
||||
throw_range = 10
|
||||
hitcost = 2000
|
||||
throw_hit_chance = 99 //Have you prayed today?
|
||||
custom_materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000)
|
||||
@@ -328,7 +328,7 @@
|
||||
if(turned_on)
|
||||
if(ishuman(thrower))
|
||||
var/mob/living/carbon/human/H = thrower
|
||||
H.throw_mode_off() //so they can catch it on the return.
|
||||
H.throw_mode_on() //so they can catch it on the return.
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/baton/boomerang/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
|
||||
@@ -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))
|
||||
..()
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
new /obj/item/tank/internals/emergency_oxygen/engi(src)
|
||||
new /obj/item/analyzer(src)
|
||||
new /obj/item/holosign_creator/atmos(src)
|
||||
new /obj/item/holosign_creator/firelock(src)
|
||||
new /obj/item/holosign_creator/firelock(src) //what if atmos techs could test things they are meant to test, wild, innit?
|
||||
new /obj/item/watertank/atmos(src)
|
||||
new /obj/item/clothing/suit/fire/atmos(src)
|
||||
new /obj/item/clothing/head/hardhat/atmos(src)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
if(M.client && (is_servant_of_ratvar(M) || isobserver(M) || M.stat == DEAD))
|
||||
viewing += M.client
|
||||
flick_overlay(I, viewing, 8)
|
||||
L.adjustToxLoss(-3, TRUE, TRUE)
|
||||
L.adjustToxLoss(-3, TRUE, TRUE, toxins_type = TOX_OMNI)
|
||||
|
||||
/turf/open/floor/clockwork/try_replace_tile(obj/item/stack/tile/T, mob/user, params)
|
||||
return
|
||||
@@ -278,4 +278,4 @@
|
||||
heavyfootstep = FOOTSTEP_RUST
|
||||
|
||||
/turf/open/floor/plating/rust/rust_heretic_act()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
|
||||
dat += "<I>Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.</I><BR>"
|
||||
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_MARTIAL]'>Martial Artist</a><BR>"
|
||||
dat += "<I>Your apprentice is training in ancient martial arts. They know the Plasmafist and Nuclear Fist.</I><BR>"
|
||||
dat += "<I>Your apprentice is training in ancient martial arts. They know an Inner Mantra and the Nuclear Fist technique.</I><BR>"
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
|
||||
@@ -69,6 +69,7 @@ GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
|
||||
build_path = /obj/item/abductor_machine_beacon/chem_dispenser
|
||||
category = "Advanced Gear"
|
||||
|
||||
/*
|
||||
/datum/abductor_gear/shrink_ray
|
||||
name = "Shrink Ray Blaster"
|
||||
description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
|
||||
@@ -77,3 +78,4 @@ GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
|
||||
cost = 2
|
||||
build_path = /obj/item/gun/energy/shrink_ray
|
||||
category = "Advanced Gear"
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -348,9 +348,9 @@
|
||||
L.dust()
|
||||
else if(L.health > min_drain_health)
|
||||
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
|
||||
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
|
||||
vitality_drained = L.adjustToxLoss(1, forced = TRUE, toxins_type = TOX_OMNI)
|
||||
else
|
||||
vitality_drained = L.adjustToxLoss(1.5, forced = TRUE)
|
||||
vitality_drained = L.adjustToxLoss(1.5, forced = TRUE, toxins_type = TOX_OMNI)
|
||||
if(vitality_drained)
|
||||
GLOB.clockwork_vitality += vitality_drained
|
||||
else
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
if(totaldamage)
|
||||
L.heal_overall_damage(brutedamage, burndamage, only_organic = FALSE) //Maybe a machine god shouldn't murder augmented followers instead of healing them
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE, toxins_type = TOX_OMNI)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("[has_holy_water ? "Heal tainted" : "Mend wounded"] flesh!"))
|
||||
log_combat(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], [has_holy_water ? "causing [L.p_them()] to briefly glow as it mends" : " mending"] [L.p_their()] bruises and burns!</span>", \
|
||||
|
||||
@@ -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--
|
||||
|
||||
@@ -717,9 +717,9 @@
|
||||
uses = 0
|
||||
ratio *= -1
|
||||
H.adjustOxyLoss((overall_damage*ratio) * (H.getOxyLoss() / overall_damage), 0)
|
||||
H.adjustToxLoss((overall_damage*ratio) * (H.getToxLoss() / overall_damage), 0)
|
||||
H.adjustFireLoss((overall_damage*ratio) * (H.getFireLoss() / overall_damage), 0)
|
||||
H.adjustBruteLoss((overall_damage*ratio) * (H.getBruteLoss() / overall_damage), 0)
|
||||
H.adjustToxLoss((overall_damage*ratio) * (H.getToxLoss() / overall_damage), 0, toxins_type = TOX_OMNI)
|
||||
H.adjustFireLoss((overall_damage*ratio) * (H.getFireLoss() / overall_damage), 0, only_organic = FALSE)
|
||||
H.adjustBruteLoss((overall_damage*ratio) * (H.getBruteLoss() / overall_damage), 0, only_organic = FALSE)
|
||||
H.updatehealth()
|
||||
playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25)
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
|
||||
|
||||
@@ -214,8 +214,8 @@
|
||||
if(L.health != L.maxHealth)
|
||||
new /obj/effect/temp_visual/heal(get_turf(src), "#960000")
|
||||
if(ishuman(L))
|
||||
L.adjustBruteLoss(-1, 0)
|
||||
L.adjustFireLoss(-1, 0)
|
||||
L.adjustBruteLoss(-1, 0, only_organic = FALSE)
|
||||
L.adjustFireLoss(-1, 0, only_organic = FALSE)
|
||||
L.updatehealth()
|
||||
if(isshade(L) || isconstruct(L))
|
||||
var/mob/living/simple_animal/M = L
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -617,9 +617,12 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
var/fake = FALSE
|
||||
var/turf/lastlocation
|
||||
var/last_disk_move
|
||||
var/process_tick = 0
|
||||
|
||||
/obj/item/disk/nuclear/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/bed_tuckable, 6, -6, 0)
|
||||
|
||||
if(!fake)
|
||||
GLOB.poi_list |= src
|
||||
last_disk_move = world.time
|
||||
@@ -630,11 +633,25 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
AddComponent(/datum/component/stationloving, !fake)
|
||||
|
||||
/obj/item/disk/nuclear/process()
|
||||
++process_tick
|
||||
if(fake)
|
||||
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.
|
||||
if(process_tick % 30)
|
||||
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)
|
||||
|
||||
@@ -189,6 +189,10 @@
|
||||
name = "Mutate"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/genetic/mutate
|
||||
|
||||
/datum/spellbook_entry/mantra
|
||||
name = "Inner Mantra"
|
||||
spell_type = /obj/effect/proc_holder/spell/self/mantra
|
||||
|
||||
/datum/spellbook_entry/jaunt
|
||||
name = "Ethereal Jaunt"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt
|
||||
|
||||
@@ -181,8 +181,8 @@
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
|
||||
if(APPRENTICE_MARTIAL)
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/touch/nuclear_fist(null))
|
||||
H.put_in_hands(new /obj/item/book/granter/martial/plasma_fist(H))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned mystical martial abilities. You are also able to use the Nuclear Fist at will.")
|
||||
owner.AddSpell(new /obj/effect/proc_holder/spell/self/mantra(null))
|
||||
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned to control your Inner Mantra. You are also able to use the Nuclear Fist at will.")
|
||||
|
||||
/datum/antagonist/wizard/apprentice/create_objectives()
|
||||
var/datum/objective/protect/new_objective = new /datum/objective/protect
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
to_chat(owner, "<span class='warning'>You feel your breasts shrinking away from your body as your chest flattens out.</span>")
|
||||
QDEL_IN(src, 1)
|
||||
return
|
||||
var/enlargement = FALSE
|
||||
switch(rounded_cached)
|
||||
if(0) //flatchested
|
||||
size = "flat"
|
||||
@@ -96,16 +95,8 @@
|
||||
size = breast_values[rounded_cached]
|
||||
if(9 to 15) //massive
|
||||
size = breast_values[rounded_cached]
|
||||
enlargement = TRUE
|
||||
if(16 to INFINITY) //rediculous
|
||||
size = "huge"
|
||||
enlargement = TRUE
|
||||
if(owner)
|
||||
var/status_effect = owner.has_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
|
||||
if(enlargement && !status_effect)
|
||||
owner.apply_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
|
||||
else if(!enlargement && status_effect)
|
||||
owner.remove_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
|
||||
|
||||
if(rounded_cached < 16 && owner)//Because byond doesn't count from 0, I have to do this.
|
||||
var/mob/living/carbon/human/H = owner
|
||||
|
||||
@@ -39,27 +39,16 @@
|
||||
return
|
||||
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 max_D) //If massive
|
||||
if(12 to 36) //If massive
|
||||
new_size = 3
|
||||
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(max_D+14 to INFINITY) //If comical
|
||||
if(37 to INFINITY) //If comical
|
||||
new_size = 4 //no new sprites for anything larger yet
|
||||
enlargement = TRUE
|
||||
if(owner)
|
||||
var/status_effect = owner.has_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
|
||||
if(enlargement && !status_effect)
|
||||
owner.apply_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
|
||||
else if(!enlargement && status_effect)
|
||||
owner.remove_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
|
||||
|
||||
if(linked_organ)
|
||||
linked_organ.size = clamp(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX)
|
||||
linked_organ.update()
|
||||
|
||||
@@ -123,6 +123,7 @@ obj/item/dildo/flared/huge
|
||||
desc = "THIS THING IS HUGE!"
|
||||
dildo_size = 4
|
||||
force = 10
|
||||
hitsound = 'sound/weapons/klonk.ogg'
|
||||
|
||||
obj/item/dildo/custom
|
||||
name = "customizable dildo"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -510,12 +510,12 @@ Contains:
|
||||
name = "paramedic EVA suit"
|
||||
icon_state = "paramedic-eva"
|
||||
item_state = "paramedic-eva"
|
||||
desc = "A deep blue space suit decorated with red and white crosses to indicate that the wearer is trained emergency medical personnel."
|
||||
desc = "A deep blue space suit decorated with medical insignia to indicate that the wearer is trained emergency medical personnel."
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/roller)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/eva/paramedic
|
||||
name = "paramedic EVA helmet"
|
||||
desc = "A deep blue space helmet with a large red cross on the faceplate to designate the wearer as trained emergency medical personnel."
|
||||
desc = "A deep blue space helmet decorated with medical insignia to designate the wearer as trained emergency medical personnel."
|
||||
icon_state = "paramedic-eva-helmet"
|
||||
item_state = "paramedic-eva-helmet"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
/obj/item/weldingtool = 3,
|
||||
/obj/item/wirecutters = 2,
|
||||
/obj/item/wrench = 4,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
|
||||
/obj/item/weaponcrafting/receiver = 1,
|
||||
/obj/item/geiger_counter = 3,
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/orange = 5,
|
||||
/obj/item/assembly/infra = 1,
|
||||
|
||||
@@ -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]"))
|
||||
|
||||
@@ -1104,7 +1104,7 @@
|
||||
if(1)
|
||||
new /obj/item/mayhem(src)
|
||||
if(2)
|
||||
new /obj/item/gun/ballistic/revolver/doublebarrel/super(src)
|
||||
new /obj/item/book/granter/spell/asura(src)
|
||||
if(3)
|
||||
new /obj/item/guardiancreator(src)
|
||||
|
||||
@@ -1187,6 +1187,13 @@
|
||||
unique_reskin = null
|
||||
sawn_off = TRUE
|
||||
|
||||
/obj/item/book/granter/spell/asura
|
||||
spell = /obj/effect/proc_holder/spell/self/asura
|
||||
spellname = "asuras wrath"
|
||||
icon_state = "bookasura"
|
||||
desc = "This crimson novel emanates rage incarnate."
|
||||
remarks = list("Kaio-What?", "It can only be sustained for a short time...", "It's like a massive upsurge of energy...", "Takes a heavy toll on the user's body...?", "Extra arms not included...", "There's stronger levels? Why aren't they in the book...")
|
||||
|
||||
//Colossus
|
||||
/obj/structure/closet/crate/necropolis/colossus
|
||||
name = "colossus chest"
|
||||
|
||||
@@ -243,6 +243,10 @@
|
||||
icon_state = "none"
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/brown
|
||||
name = "Brown"
|
||||
icon_state = "brown"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/punished
|
||||
name = "Burnt Off"
|
||||
icon_state = "punished"
|
||||
@@ -271,6 +275,10 @@
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/featherymoth
|
||||
name = "Feathery Moth"
|
||||
icon_state = "featherymoth"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/firewatch
|
||||
name = "Firewatch"
|
||||
icon_state = "firewatch"
|
||||
@@ -291,18 +299,22 @@
|
||||
name = "Moon Fly"
|
||||
icon_state = "moonfly"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/plasmafire
|
||||
name = "Plasma Fire"
|
||||
icon_state = "plasmafire"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/ragged
|
||||
name = "Ragged"
|
||||
icon_state = "ragged"
|
||||
@@ -311,6 +323,10 @@
|
||||
name = "Reddish"
|
||||
icon_state = "redish"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/rosy
|
||||
name = "Rosy"
|
||||
icon_state = "rosy"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
@@ -325,4 +341,4 @@
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/witchwing
|
||||
name = "Witch Wing"
|
||||
icon_state = "witchwing"
|
||||
icon_state = "witchwing"
|
||||
@@ -58,9 +58,7 @@
|
||||
dimension_y = 34
|
||||
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
|
||||
|
||||
/datum/sprite_accessory/deco_wings/atlas
|
||||
name = "Atlas"
|
||||
icon_state = "atlas"
|
||||
//nonmoth wings
|
||||
|
||||
/datum/sprite_accessory/deco_wings/bat
|
||||
name = "Bat"
|
||||
@@ -70,18 +68,76 @@
|
||||
name = "Bee"
|
||||
icon_state = "bee"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
/datum/sprite_accessory/deco_wings/bee2
|
||||
name = "Small Bee"
|
||||
icon_state = "beewings"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/dragon
|
||||
name = "Dragon"
|
||||
icon_state = "dragon"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/dragonfly
|
||||
name = "Dragonfly"
|
||||
icon_state = "dragonfly"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/fairy
|
||||
name = "Fairy"
|
||||
icon_state = "fairy"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/feathery
|
||||
/datum/sprite_accessory/deco_wings/featheredwing
|
||||
name = "Feathery"
|
||||
icon_state = "feathery"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/featheredwingmedium
|
||||
name = "Medium Feathered"
|
||||
icon_state = "feathered3"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/featheredwinglarge
|
||||
name = "Large Feathered"
|
||||
icon_state = "feathered2"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/harpywings
|
||||
name = "Harpy"
|
||||
icon_state = "harpywings"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/roboticwing
|
||||
name = "Robotic"
|
||||
icon_state = "drago"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/succubusblack
|
||||
name = "Succubus Black"
|
||||
icon_state = "succubusblack"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/succubuspurple
|
||||
name = "Succubus Purple"
|
||||
icon_state = "succubuspurple"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/succubusred
|
||||
name = "Succubus Red"
|
||||
icon_state = "succubusred"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/xenobackplate
|
||||
name = "Xenomorph Backplate"
|
||||
icon_state = "snagbackplate"
|
||||
|
||||
//moth wings
|
||||
|
||||
/datum/sprite_accessory/deco_wings/atlas
|
||||
name = "Atlas"
|
||||
icon_state = "atlas"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/brown
|
||||
name = "Brown"
|
||||
icon_state = "brown"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/featherymoth
|
||||
name = "Feathery Moth Wings"
|
||||
icon_state = "featherymoth"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/firewatch
|
||||
name = "Firewatch"
|
||||
icon_state = "firewatch"
|
||||
@@ -90,6 +146,10 @@
|
||||
name = "Gothic"
|
||||
icon_state = "gothic"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/lovers
|
||||
name = "Lovers"
|
||||
icon_state = "lovers"
|
||||
@@ -106,10 +166,18 @@
|
||||
name = "Moon Fly"
|
||||
icon_state = "moonfly"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/plasmafire
|
||||
name = "Plasma Fire"
|
||||
icon_state = "plasmafire"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
@@ -126,6 +194,10 @@
|
||||
name = "Reddish"
|
||||
icon_state = "redish"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/rosy
|
||||
name = "Rosy"
|
||||
icon_state = "rosy"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
@@ -138,18 +210,10 @@
|
||||
name = "White Fly"
|
||||
icon_state = "whitefly"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/witchwing
|
||||
name = "Witch Wing"
|
||||
icon_state = "witchwing"
|
||||
|
||||
/datum/sprite_accessory/deco_wings/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
|
||||
//INSECT WINGS
|
||||
|
||||
/datum/sprite_accessory/insect_wings
|
||||
@@ -157,6 +221,69 @@
|
||||
color_src = WINGCOLOR
|
||||
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
|
||||
|
||||
//non insect wings
|
||||
/datum/sprite_accessory/deco_wings/bat
|
||||
name = "Bat"
|
||||
icon_state = "bat"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/bee
|
||||
name = "Bee"
|
||||
icon_state = "bee"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/bee2
|
||||
name = "Small Bee"
|
||||
icon_state = "beewings"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/dragon
|
||||
name = "Dragon"
|
||||
icon_state = "dragon"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/dragonfly
|
||||
name = "Dragonfly"
|
||||
icon_state = "dragonfly"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/fairy
|
||||
name = "Fairy"
|
||||
icon_state = "fairy"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/featheredwing
|
||||
name = "Feathery"
|
||||
icon_state = "feathery"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/featheredwingmedium
|
||||
name = "Medium Feathered"
|
||||
icon_state = "feathered3"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/featheredwinglarge
|
||||
name = "Large Feathered"
|
||||
icon_state = "feathered2"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/harpywings
|
||||
name = "Harpy"
|
||||
icon_state = "harpywings"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/roboticwing
|
||||
name = "Robotic"
|
||||
icon_state = "drago"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/succubusblack
|
||||
name = "Succubus Black"
|
||||
icon_state = "succubusblack"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/succubuspurple
|
||||
name = "Succubus Purple"
|
||||
icon_state = "succubuspurple"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/succubusred
|
||||
name = "Succubus Red"
|
||||
icon_state = "succubusred"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/xenobackplate
|
||||
name = "Xenomorph Backplate"
|
||||
icon_state = "snagbackplate"
|
||||
|
||||
//moth wings
|
||||
|
||||
/datum/sprite_accessory/insect_wings/none
|
||||
name = "None"
|
||||
icon_state = "none"
|
||||
@@ -166,25 +293,17 @@
|
||||
name = "Atlas"
|
||||
icon_state = "atlas"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/bat
|
||||
name = "Bat"
|
||||
icon_state = "bat"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/bee
|
||||
name = "Bee"
|
||||
icon_state = "bee"
|
||||
/datum/sprite_accessory/insect_wings/brown
|
||||
name = "Brown"
|
||||
icon_state = "brown"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/fairy
|
||||
name = "Fairy"
|
||||
icon_state = "fairy"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/feathery
|
||||
name = "Feathery"
|
||||
icon_state = "feathery"
|
||||
/datum/sprite_accessory/insect_wings/featherymoth
|
||||
name = "Feathery Moth Wings"
|
||||
icon_state = "featherymoth"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/firewatch
|
||||
name = "Firewatch"
|
||||
@@ -222,6 +341,10 @@
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/plasmafire
|
||||
name = "Plasma Fire"
|
||||
icon_state = "plasmafire"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
@@ -238,6 +361,10 @@
|
||||
name = "Reddish"
|
||||
icon_state = "redish"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/rosy
|
||||
name = "Rosy"
|
||||
icon_state = "rosy"
|
||||
|
||||
/datum/sprite_accessory/insect_wings/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
@@ -265,45 +392,25 @@
|
||||
icon_state = "none"
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/insect_markings/reddish
|
||||
name = "Reddish"
|
||||
icon_state = "reddish"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/gothic
|
||||
name = "Gothic"
|
||||
icon_state = "gothic"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/whitefly
|
||||
name = "White Fly"
|
||||
icon_state = "whitefly"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/lovers
|
||||
name = "Lovers"
|
||||
icon_state = "lovers"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/punished
|
||||
name = "Punished"
|
||||
icon_state = "punished"
|
||||
/datum/sprite_accessory/insect_markings/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/firewatch
|
||||
name = "Firewatch"
|
||||
icon_state = "firewatch"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
/datum/sprite_accessory/insect_markings/gothic
|
||||
name = "Gothic"
|
||||
icon_state = "gothic"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
/datum/sprite_accessory/insect_markings/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/ragged
|
||||
name = "Ragged"
|
||||
icon_state = "ragged"
|
||||
/datum/sprite_accessory/insect_markings/lovers
|
||||
name = "Lovers"
|
||||
icon_state = "lovers"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/moonfly
|
||||
name = "Moon Fly"
|
||||
@@ -313,10 +420,42 @@
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
/datum/sprite_accessory/insect_markings/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/punished
|
||||
name = "Punished"
|
||||
icon_state = "punished"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/ragged
|
||||
name = "Ragged"
|
||||
icon_state = "ragged"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/reddish
|
||||
name = "Reddish"
|
||||
icon_state = "reddish"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/whitefly
|
||||
name = "White Fly"
|
||||
icon_state = "whitefly"
|
||||
|
||||
/datum/sprite_accessory/insect_markings/witchwing
|
||||
name = "Witch Wing"
|
||||
icon_state = "witchwing"
|
||||
|
||||
//DONATOR WINGS
|
||||
|
||||
/datum/sprite_accessory/deco_wings/eyestalks
|
||||
name = "gazer eyestalks"
|
||||
icon_state = "eyestalks"
|
||||
//ckeys_allowed = list("liquidfirefly","seiga") //At request.
|
||||
|
||||
/datum/sprite_accessory/insect_wings/eyestalks
|
||||
name = "gazer eyestalks"
|
||||
icon_state = "eyestalks"
|
||||
//ckeys_allowed = list("liquidfirefly","seiga") //At request.
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
amount += BP.burn_dam
|
||||
return amount
|
||||
|
||||
|
||||
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
//In both these procs, only_organic / only_robotic are only used for healing, not for damaging. For now at least.
|
||||
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL))
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
@@ -71,10 +71,10 @@
|
||||
if(amount > 0)
|
||||
take_overall_damage(amount, 0, 0, updating_health)
|
||||
else
|
||||
heal_overall_damage(abs(amount), 0, 0, FALSE, TRUE, updating_health)
|
||||
heal_overall_damage(abs(amount), 0, 0, only_robotic, only_organic, updating_health)
|
||||
return amount
|
||||
|
||||
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally.
|
||||
return FALSE
|
||||
if(!forced && (status_flags & GODMODE))
|
||||
@@ -82,7 +82,7 @@
|
||||
if(amount > 0)
|
||||
take_overall_damage(0, amount, 0, updating_health)
|
||||
else
|
||||
heal_overall_damage(0, abs(amount), 0, FALSE, TRUE, updating_health)
|
||||
heal_overall_damage(0, abs(amount), 0, only_robotic, only_organic, updating_health)
|
||||
return amount
|
||||
|
||||
|
||||
|
||||
@@ -80,10 +80,11 @@
|
||||
if("shortlimbdisable")
|
||||
var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG))
|
||||
ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM)
|
||||
update_disabled_bodyparts()
|
||||
addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 5 SECONDS)
|
||||
to_chat(src, "<span class='warning'>Error - Limb control subsystem partially shutdown, rebooting.</span>")
|
||||
if("shortblind")
|
||||
ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
|
||||
become_blind(CORRUPTED_SYSTEM)
|
||||
addtimer(CALLBACK(src, .proc/reenable_vision), 5 SECONDS)
|
||||
to_chat(src, "<span class='warning'>Visual receptor shutdown detected - Initiating reboot.</span>")
|
||||
if("shortstun")
|
||||
@@ -105,10 +106,11 @@
|
||||
if("longlimbdisable")
|
||||
var/disabled_type = pick(list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG))
|
||||
ADD_TRAIT(src, disabled_type, CORRUPTED_SYSTEM)
|
||||
update_disabled_bodyparts()
|
||||
addtimer(CALLBACK(src, .proc/reenable_limb, disabled_type), 25 SECONDS)
|
||||
to_chat(src, "<span class='warning'>Fatal error in limb control subsystem - rebooting.</span>")
|
||||
if("blindmutedeaf")
|
||||
ADD_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
|
||||
become_blind(CORRUPTED_SYSTEM)
|
||||
addtimer(CALLBACK(src, .proc/reenable_vision), (rand(10, 25)) SECONDS)
|
||||
ADD_TRAIT(src, TRAIT_DEAF, CORRUPTED_SYSTEM)
|
||||
addtimer(CALLBACK(src, .proc/reenable_hearing), (rand(15, 35)) SECONDS)
|
||||
@@ -140,6 +142,7 @@
|
||||
|
||||
/mob/living/carbon/proc/reenable_limb(disabled_limb)
|
||||
REMOVE_TRAIT(src, disabled_limb, CORRUPTED_SYSTEM)
|
||||
update_disabled_bodyparts()
|
||||
to_chat(src, "<span class='notice'>Limb control subsystem successfully rebooted.</span>")
|
||||
|
||||
/mob/living/carbon/proc/reenable_hearing()
|
||||
@@ -147,7 +150,7 @@
|
||||
to_chat(src, "<span class='notice'>Hearing restored.</span>")
|
||||
|
||||
/mob/living/carbon/proc/reenable_vision()
|
||||
REMOVE_TRAIT(src, TRAIT_BLIND, CORRUPTED_SYSTEM)
|
||||
cure_blind(CORRUPTED_SYSTEM)
|
||||
to_chat(src, "<span class='notice'>Visual receptors back online.</span>")
|
||||
|
||||
/mob/living/carbon/proc/reenable_speech()
|
||||
|
||||
@@ -411,15 +411,18 @@
|
||||
if(isrobotic(src))
|
||||
apply_status_effect(/datum/status_effect/no_combat_mode/robotic_emp, severity / 20)
|
||||
severity *= 0.5
|
||||
var/do_not_stun = FALSE
|
||||
if(HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM))
|
||||
severity *= 0.5 //Robotpeople take less limb damage, but instead suffer system corruption (see carbon emp_act)
|
||||
do_not_stun = TRUE
|
||||
for(var/obj/item/bodypart/L in src.bodyparts)
|
||||
if(L.is_robotic_limb())
|
||||
if(!informed)
|
||||
to_chat(src, "<span class='userdanger'>You feel a sharp pain as your robotic limbs overload.</span>")
|
||||
informed = TRUE
|
||||
L.receive_damage(0,severity/10)
|
||||
Stun(severity*2)
|
||||
if(!do_not_stun) //Tiny bit better than checking for the trait another six times in succession
|
||||
Stun(severity*2)
|
||||
|
||||
/mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit)
|
||||
var/list/damaged = list()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
block_parry_data = /datum/block_parry_data/unarmed/human
|
||||
default_block_parry_data = /datum/block_parry_data/unarmed/human
|
||||
causes_dirt_buildup_on_floor = TRUE
|
||||
|
||||
//Hair colour and style
|
||||
var/hair_color = "000"
|
||||
|
||||
@@ -100,3 +100,8 @@
|
||||
if(dna.species.space_move(src))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/dirt_buildup(strength)
|
||||
if(!shoes || !(shoes.body_parts_covered & FEET))
|
||||
return // barefoot advantage
|
||||
return ..()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
override_bp_icon = 'icons/mob/arachnid_parts.dmi'
|
||||
say_mod = "chitters"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(LIPS, NOEYES, NO_UNDERWEAR)
|
||||
species_traits = list(LIPS, NOEYES, NO_UNDERWEAR, HAS_FLESH, HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
|
||||
mutant_bodyparts = list("arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain")
|
||||
attack_verb = "slash"
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
name = "Xenobiological Slime Entity"
|
||||
id = SPECIES_SLIME
|
||||
default_color = "00FFFF"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,HAS_FLESH)
|
||||
say_mod = "says"
|
||||
hair_color = "mutcolor"
|
||||
hair_alpha = 150
|
||||
@@ -404,7 +404,7 @@
|
||||
id = SPECIES_SLIME_HYBRID
|
||||
limbs_id = SPECIES_SLIME
|
||||
default_color = "00FFFF"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,HAS_FLESH)
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None", "legs" = "Plantigrade")
|
||||
say_mod = "says"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
id = SPECIES_LIZARD
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
|
||||
mutanttongue = /obj/item/organ/tongue/lizard
|
||||
mutanttail = /obj/item/organ/tail/lizard
|
||||
@@ -48,7 +48,7 @@
|
||||
name = "Ash Walker"
|
||||
id = SPECIES_ASHWALKER
|
||||
limbs_id = SPECIES_LIZARD
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE,CAN_SCAR,HAS_FLESH,HAS_BONE)
|
||||
inherent_traits = list(TRAIT_CHUNKYFINGERS)
|
||||
mutantlungs = /obj/item/organ/lungs/ashwalker
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
/datum/species/pod/pseudo_weak
|
||||
name = "Anthromorphic Plant"
|
||||
id = SPECIES_POD_WEAK
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
|
||||
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS,CAN_SCAR,HAS_FLESH,HAS_BONE)
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
limbs_id = SPECIES_POD
|
||||
light_nutrition_gain_factor = 3
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
id = SPECIES_XENOHYBRID
|
||||
say_mod = "hisses"
|
||||
default_color = "00FF00"
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR)
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,CAN_SCAR,HAS_FLESH,HAS_BONE)
|
||||
mutant_bodyparts = list("xenotail"="Xenomorph Tail","xenohead"="Standard","xenodorsal"="Standard", "mam_body_markings" = "Xeno","mcolor" = "0F0","mcolor2" = "0F0","mcolor3" = "0F0","taur" = "None", "legs" = "Digitigrade","deco_wings"= "None")
|
||||
attack_verb = "slash"
|
||||
attack_sound = 'sound/weapons/slash.ogg'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user