This commit is contained in:
Putnam3145
2022-08-07 17:59:28 -07:00
382 changed files with 5255 additions and 2567 deletions
+1
View File
@@ -69,6 +69,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/cmd_admin_man_up, //CIT CHANGE - adds man up verb
/client/proc/cmd_admin_man_up_global, //CIT CHANGE - ditto
/client/proc/cmd_admin_create_centcom_report,
/client/proc/cmd_admin_make_priority_announcement, //CIT CHANGE
/client/proc/cmd_change_command_name,
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
+5 -5
View File
@@ -150,7 +150,7 @@ GLOBAL_LIST(round_end_notifiees)
/datum/tgs_chat_command/wheelofsalt/Run(datum/tgs_chat_user/sender, params)
var/saltresult = "The wheel of salt [pick("clatters","screams","vibrates","clanks","resonates","groans","moans","squeaks","emits a[pick(" god-forsaken"," lewd"," creepy"," generic","n orgasmic"," demonic")] [pick("airhorn","bike horn","trumpet","clown","latex","vore","dog","laughing")] noise")] as it spins violently... And it seems the salt of the day is the "
var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin removal","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin removal","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Polly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP","bikeshedding","crossdressing","sprites","semen keg","argument","theft","nerf","screeching","salt","creampie","lewding","murder","kissing","marriage","replacement","fucking","ship","netflix adaptation","dance","remaster","system","voyeur","decoration","pre-order","bukkake","seduction","worship","gangbang","handholding")]"
if(prob(10))
saltresult += "@here for your salt, all day every day"
@@ -174,12 +174,12 @@ GLOBAL_LIST(round_end_notifiees)
/datum/tgs_chat_command/despacito/Run()
return "https://www.youtube.com/watch?v=kJQP7kiw5Fk"
/datum/tgs_chat_command/poly
name = "poly"
help_text = "The Lewder, more applicable Poly speak for Citadel Station 13."
/datum/tgs_chat_command/polly
name = "polly"
help_text = "The Lewder, more applicable Polly speak for Citadel Station 13."
var/list/speech_buffer
/datum/tgs_chat_command/poly/Run()
/datum/tgs_chat_command/polly/Run()
LAZYINITLIST(speech_buffer) //I figure this is just safe to do for everything at this point
if(length(speech_buffer)) //Let's not look up the whole json EVERY TIME, just the first time.
return "[pick(speech_buffer)]"
+4
View File
@@ -50,6 +50,10 @@
H.dna.features["flavor_text"] = "" //Oh no.
H.dna.features["body_model"] = H.gender
H.set_bark(pick(GLOB.bark_random_list))
H.vocal_pitch = BARK_PITCH_RAND(H.gender)
H.vocal_pitch_range = BARK_VARIANCE_RAND
SEND_SIGNAL(H, COMSIG_HUMAN_ON_RANDOMIZE)
H.update_body(TRUE)
+2 -2
View File
@@ -489,8 +489,8 @@
M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob )
if("parrot")
M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob )
if("polyparrot")
M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob )
if("pollyparrot")
M.change_mob_type( /mob/living/simple_animal/parrot/Polly , null, null, delmob )
if("constructarmored")
M.change_mob_type( /mob/living/simple_animal/hostile/construct/armored , null, null, delmob )
if("constructbuilder")
@@ -102,7 +102,7 @@
factory.spores += src
. = ..()
/mob/living/simple_animal/hostile/blob/blobspore/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/hostile/blob/blobspore/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
if(!is_zombie && isturf(src.loc))
@@ -233,7 +233,7 @@
return FALSE
return ..()
/mob/living/simple_animal/hostile/blob/blobbernaut/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/hostile/blob/blobbernaut/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
var/list/blobs_in_area = range(2, src)
@@ -2,7 +2,7 @@
// * MEZMERIZE
// LOVE: Target falls in love with you. Being harmed directly causes them harm if they see it?
// STAY: Target will do everything they can to stand in the same place.
// FOLLOW: Target follows you, spouting random phrases from their history (or maybe Poly's or NPC's vocab?)
// FOLLOW: Target follows you, spouting random phrases from their history (or maybe Polly's or NPC's vocab?)
// ATTACK: Target finds a nearby non-Bloodsucker victim to attack.
/datum/action/bloodsucker/targeted/mesmerize
@@ -16,7 +16,7 @@
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
var/loudness = 0 //Determines how much having this ability will affect changeling blood tests. At 4, the blood will react violently and turn to ash, creating a unique message in the process. At 10, the blood will explode when heated.
var/loudness = 0.5 //Determines how much having this ability will affect changeling blood tests. This is averaged with other purchased abilities. Above 1, the blood will react violently and turn to ash, creating a unique message in the process. Above 2, the blood will explode when heated.
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
@@ -43,7 +43,7 @@
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
var/t_He = p_they(TRUE)
var/t_s = p_s()
var/msg = "<span class='brass'>*---------*\nThis is [icon2html(src, user)] \a <b>[src]</b>!\n"
var/msg = "<span class='brass'>This is [icon2html(src, user)] \a <b>[src]</b>!\n"
msg += "[desc]\n"
if(health < maxHealth)
msg += "<span class='warning'>"
@@ -55,7 +55,7 @@
var/addendum = examine_info()
if(addendum)
msg += "[addendum]\n"
msg += "*---------*</span>"
msg += "</span>"
return list(msg)
@@ -38,7 +38,7 @@
. = ..()
true_name = pick(possible_true_names)
/mob/living/simple_animal/hostile/clockwork/guardian/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/hostile/clockwork/guardian/BiologicalLife(delta_time, times_fired)
..()
if(is_in_host())
if(!is_servant_of_ratvar(host))
@@ -39,7 +39,7 @@
if(!shield_health)
return "<span class='warning'>Its shield has been destroyed!</span>"
/mob/living/simple_animal/hostile/clockwork/marauder/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/hostile/clockwork/marauder/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
var/turf/T = get_turf(src)
+1 -1
View File
@@ -48,7 +48,7 @@
..()
boost = world.time + 30
/mob/living/simple_animal/imp/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/imp/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
if(boost<world.time)
@@ -63,7 +63,7 @@
/mob/living/carbon/true_devil/examine(mob/user)
. = list("<span class='info'>*---------*\nThis is [icon2html(src, user)] <b>[src]</b>!")
. = list("<span class='info'>This is [icon2html(src, user)] <b>[src]</b>!")
//Left hand items
for(var/obj/item/I in held_items)
@@ -81,7 +81,7 @@
. += "<span class='warning'>You can see hellfire inside its gaping wounds.</span>"
else if(health < (maxHealth/2))
. += "<span class='warning'>You can see hellfire inside its wounds.</span>"
. += "*---------*</span>"
. += "</span>"
/mob/living/carbon/true_devil/IsAdvancedToolUser()
return 1
+5
View File
@@ -67,6 +67,11 @@
if(handler) // if we have a handler, the handler should track this gang
handler.gangs += my_gang
my_gang.current_theme = handler.current_theme
else if(GLOB.families_override_theme)
my_gang.current_theme = new GLOB.families_override_theme
else
var/theme_to_use = pick(subtypesof(/datum/gang_theme))
my_gang.current_theme = new theme_to_use
my_gang.name = gang_name
my_gang.gang_id = gang_id
my_gang.acceptable_clothes = acceptable_clothes.Copy()
@@ -66,9 +66,21 @@
icon_state = "nuclearbomb_base"
anchored = TRUE //stops it being moved
/obj/machinery/nuclearbomb/selfdestruct/Initialize(mapload)
. = ..()
if(SSevents.holidays && SSevents.holidays[PRIDE_MONTH] && prob(10))
name = "station-wide gender-reveal terminal"
desc = "For when the whole sector deserves to know a gender. But of whom? Don't ask."
/obj/machinery/nuclearbomb/syndicate
//ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb
/obj/machinery/nuclearbomb/syndicate/Initialize(mapload)
. = ..()
if(SSevents.holidays && SSevents.holidays[PRIDE_MONTH] && prob(50))
name = "tactical gender-reveal device"
desc = "\"But whose gender is it revealing?\" you ponder. Don't worry. That comes later."
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
var/datum/game_mode/nuclear/NM = SSticker.mode
switch(off_station)
@@ -20,6 +20,7 @@
if(!SSpersistence.IsValidDebrisLocation(C.loc, allowed_turf_typecache, allowed_z_cache, C.type, FALSE))
continue
weight += 0.03
CHECK_TICK
return ..()
/datum/round_event/ghost_role/slaughter
+3
View File
@@ -33,6 +33,9 @@
linked_organ = null
. = ..()
/obj/item/organ/genital/on_life()
return
/obj/item/organ/genital/proc/set_aroused_state(new_state,cause = "manual toggle")
if(!(genital_flags & GENITAL_CAN_AROUSE))
return FALSE
-6
View File
@@ -15,12 +15,6 @@
var/prev_size //former size value, to allow update_size() to early return should be there no significant changes.
layer_index = BUTT_LAYER_INDEX
/obj/item/organ/genital/butt/on_life()
if(QDELETED(src))
return
if(!owner)
return
/obj/item/organ/genital/butt/modify_size(modifier, min = -INFINITY, max = BUTT_SIZE_MAX)
var/new_value = clamp(size_cached + modifier, min, max)
if(new_value == size_cached)
+4 -1
View File
@@ -17,7 +17,6 @@
/obj/item/assembly_holder/IsAssemblyHolder()
return TRUE
/obj/item/assembly_holder/proc/assemble(obj/item/assembly/A, obj/item/assembly/A2, mob/user)
attach(A,user)
attach(A2,user)
@@ -32,6 +31,8 @@
else
A.forceMove(src)
A.holder = src
// bandaid: please don't try to be picked up while we're still in the assembly
A.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
A.toggle_secure()
if(!a_left)
a_left = A
@@ -103,9 +104,11 @@
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
if(a_left)
a_left.on_detach()
a_left.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
a_left = null
if(a_right)
a_right.on_detach()
a_right.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
a_right = null
qdel(src)
return TRUE
@@ -46,7 +46,7 @@
gases = list(
GAS_METHANE = 1,
GAS_METHYL_BROMIDE = -0.7,
GAS_OXYGEN = -0.1,
GAS_O2 = -0.1,
GAS_PLUOXIUM = -0.8
)
products = list(
+42 -29
View File
@@ -69,6 +69,19 @@
fire_products = FIRE_PRODUCT_PLASMA
enthalpy = FIRE_PLASMA_ENERGY_RELEASED // 3000000, 3 megajoules, 3000 kj
/datum/gas/nitrous_oxide
id = GAS_NITROUS
specific_heat = 40
name = "Nitrous Oxide"
gas_overlay = "nitrous_oxide"
moles_visible = MOLES_GAS_VISIBLE * 2
flags = GAS_FLAG_DANGEROUS
fire_products = list(GAS_N2 = 1)
oxidation_rate = 0.5
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + 100
enthalpy = 81600
heat_resistance = 6
/datum/gas/water_vapor
id = GAS_H2O
specific_heat = 40
@@ -82,18 +95,23 @@
powermix = 1
breath_reagent = /datum/reagent/water
/datum/gas/nitrous_oxide
id = GAS_NITROUS
specific_heat = 40
name = "Nitrous Oxide"
gas_overlay = "nitrous_oxide"
moles_visible = MOLES_GAS_VISIBLE * 2
flags = GAS_FLAG_DANGEROUS
fire_products = list(GAS_N2 = 1)
oxidation_rate = 0.5
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + 100
enthalpy = 81600
heat_resistance = 6
/datum/gas/pluoxium
id = GAS_PLUOXIUM
specific_heat = 80
name = "Pluoxium"
fusion_power = 10
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 25 // it is VERY stable
oxidation_rate = 8 // when it can oxidize, it can oxidize a LOT
enthalpy = -2000000 // but it reduces the heat output a great deal (plasma fires add 3000000 per mole)
powermix = -1
heat_penalty = -1
transmit_modifier = -5
heat_resistance = 3
price = 6
/datum/gas/pluoxium/generate_TLV()
return new/datum/tlv(-1, -1, 5, 6)
/datum/gas/tritium
id = GAS_TRITIUM
@@ -111,17 +129,19 @@
fire_burn_rate = 2
fire_radiation_released = 50 // arbitrary number, basically 60 moles of trit burning will just barely start to harm you
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
price = 7
/datum/gas/nitric_oxide
id = GAS_NITRIC
specific_heat = 20
name = "Nitric oxide"
flags = GAS_FLAG_DANGEROUS
odor = "sharp sweetness"
odor_strength = 1
fusion_power = 15
enthalpy = 91290
heat_resistance = 2
powermix = -1
heat_penalty = -1
/datum/gas/nitryl
id = GAS_NITRYL
@@ -134,6 +154,7 @@
fire_products = list(GAS_N2 = 0.5)
enthalpy = 33200
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
price = 3
/datum/gas/hypernoblium
id = GAS_HYPERNOB
@@ -141,6 +162,7 @@
name = "Hyper-noblium"
gas_overlay = "freon"
moles_visible = MOLES_GAS_VISIBLE
price = 50
/datum/gas/hydrogen
id = GAS_HYDROGEN
@@ -168,6 +190,7 @@
enthalpy = FIRE_CARBON_ENERGY_RELEASED // it is a mystery
transmit_modifier = -2
radioactivity_modifier = 5
price = 3
/datum/gas/stimulum
id = GAS_STIMULUM
@@ -176,22 +199,7 @@
odor_strength = 10
name = "Stimulum"
fusion_power = 7
/datum/gas/pluoxium
id = GAS_PLUOXIUM
specific_heat = 80
name = "Pluoxium"
fusion_power = 10
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 25 // it is VERY stable
oxidation_rate = 8 // when it can oxidize, it can oxidize a LOT
enthalpy = -2000000 // but it reduces the heat output a great deal (plasma fires add 3000000 per mole)
powermix = -1
heat_penalty = -1
transmit_modifier = -5
heat_resistance = 3
/datum/gas/pluoxium/generate_TLV()
return new/datum/tlv(-1, -1, 5, 6)
price = 25
/datum/gas/miasma
id = GAS_MIASMA
@@ -201,7 +209,9 @@
// snowflaked odor
name = "Miasma"
gas_overlay = "miasma"
color = "#963"
moles_visible = MOLES_GAS_VISIBLE * 60
price = 2
/datum/gas/methane
id = GAS_METHANE
@@ -227,6 +237,7 @@
)
enthalpy = -74600
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
price = 1
/datum/gas/methyl_bromide
id = GAS_METHYL_BROMIDE
@@ -249,6 +260,7 @@
enthalpy = -35400
fire_burn_rate = 4 / 7 // oh no
fire_temperature = 808 // its autoignition; it apparently doesn't spark readily, so i don't put it lower
price = 2
/datum/gas/bromine
id = GAS_BROMINE
@@ -285,3 +297,4 @@
powermix = -1
transmit_modifier = -10
heat_penalty = -10
price = 5 // IT'S NOT ACTUALLY THAT HARD TO GET INTO A CANISTER LOL
@@ -43,6 +43,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/list/TLVs = list()
var/list/odors = list()
var/list/odor_strengths = list()
var/list/prices = list()
/datum/gas
var/id = ""
@@ -60,6 +61,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/datum/reagent/breath_reagent = null // what breathing this adds to your reagents
var/datum/reagent/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
var/list/breath_alert_info = null // list for alerts that pop up when you have too much/not enough of something
var/price = 0 // How much this gas is worth when sold, per mole.
var/oxidation_temperature = null // temperature above which this gas is an oxidizer; null for none
var/oxidation_rate = 1 // how many moles of this can oxidize how many moles of material
var/fire_temperature = null // temperature above which gas may catch fire; null for none
@@ -135,6 +137,8 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
if(gas.odor)
odor_strengths[g] = gas.odor_strength
odors[g] = gas.odor
if(gas.price)
prices[g] = gas.price
add_supermatter_properties(gas)
_auxtools_register_gas(gas)
if(done_initializing)
@@ -729,11 +729,11 @@
/datum/gas_reaction/nitric_oxide/react(datum/gas_mixture/air, datum/holder)
var/nitric = air.get_moles(GAS_NITRIC)
var/oxygen = air.get_moles(GAS_O2)
var/max_amount = max(nitric / 10, MINIMUM_MOLE_COUNT)
var/enthalpy = air.return_temperature() * (air.heat_capacity() + R_IDEAL_GAS_EQUATION * air.total_moles());
var/max_amount = max(nitric / 8, MINIMUM_MOLE_COUNT)
var/enthalpy = air.return_temperature() * (air.heat_capacity() + R_IDEAL_GAS_EQUATION * air.total_moles())
var/list/enthalpies = GLOB.gas_data.enthalpies
if(oxygen > MINIMUM_MOLE_COUNT)
var/reaction_amount = min(max_amount, oxygen)
var/reaction_amount = min(max_amount, oxygen)/4
air.adjust_moles(GAS_NITRIC, -reaction_amount*2)
air.adjust_moles(GAS_O2, -reaction_amount)
air.adjust_moles(GAS_NITRYL, reaction_amount*2)
@@ -759,7 +759,18 @@
var/initial_energy = air.thermal_energy()
for(var/g in air.get_gases())
air.set_moles(g, 0)
air.set_moles(GAS_QCD, initial_energy / (air.return_temperature() * GLOB.gas_data.specific_heats[GAS_QCD]))
var/amount = initial_energy / (air.return_temperature() * GLOB.gas_data.specific_heats[GAS_QCD])
air.set_moles(GAS_QCD, amount)
var/list/largest_values = SSresearch.science_tech.largest_values
if(!(GAS_QCD in largest_values))
largest_values[GAS_QCD] = 0
var/previous_largest = largest_values[GAS_QCD]
var/research_amount = amount * QCD_RESEARCH_AMOUNT
if(previous_largest < research_amount)
SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, research_amount)
largest_values[GAS_QCD] = research_amount
else
SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, research_amount / 100)
/datum/gas_reaction/dehagedorn
priority = 50
@@ -781,11 +792,10 @@
var/list/gases = GLOB.gas_data.specific_heats.Copy()
gases -= GAS_QCD
gases -= GAS_TRITIUM // no refusing sorry
for(var/g in gases)
gases[g] = 10000 / gases[g]
gases -= GAS_HYPERNOB // makes it waaay too easy to stabilize it
while(energy_remaining > 0)
var/G = pick(gases)
air.adjust_moles(G, max(0.1, energy_remaining / (gases[G] * new_temp * 20)))
energy_remaining = initial_energy - air.thermal_energy()
air.adjust_heat(-energy_remaining)
air.set_temperature(initial_energy / air.heat_capacity())
return REACTING
@@ -45,9 +45,9 @@
if(9)
SpeakPeace(list("Alright maybe that's <b>too</b> boring.", "I can't keep manually typing these lines out though.", "It's hard to explain but the code structure I'm using is kind of terrible."))
if(10)
SpeakPeace(list("Oh I have an idea!", "Lets outsource this endless banter to Poly!", "Then you'll be able to keep listening to this without getting bored!"))
SpeakPeace(list("Oh I have an idea!", "Lets outsource this endless banter to Polly!", "Then you'll be able to keep listening to this without getting bored!"))
if(isnull(shenanigans) || !shenanigans.len)
shenanigans = list("Except the poly file is missing...")
shenanigans = list("Except the polly file is missing...")
if(11 to 14, 16 to 50, 52 to 99, 103 to 107, 109 to 203, 205 to 249, 252 to 665, 667 to 999, 1001 to 5642)
SpeakPeace(list(pick(shenanigans),pick(shenanigans),pick(shenanigans)))
if(times_spoken_to % 10 == 0)
@@ -55,7 +55,7 @@
if(15)
SpeakPeace(list("See? Isn't this fun?","Now you can mash this for hours without getting bored.","Anyway I'll leave you it."))
if(51)
SpeakPeace(list("The fun never ends around here.", "The Poly text files stores up to 500 statements.", "But you've probably heard a few repeats by now."))
SpeakPeace(list("The fun never ends around here.", "The Polly text files stores up to 500 statements.", "But you've probably heard a few repeats by now."))
if(100)
SpeakPeace(list("And that's a solid hundred.", "Good hustle I guess.", "You've probably heard a lot of repeats by now."))
if(101)
+3 -7
View File
@@ -169,13 +169,9 @@
/datum/export/large/gas_canister/get_cost(obj/O)
var/obj/machinery/portable_atmospherics/canister/C = O
var/worth = 10
worth += C.air_contents.get_moles(GAS_BZ)*3
worth += C.air_contents.get_moles(GAS_STIMULUM)*25
worth += C.air_contents.get_moles(GAS_HYPERNOB)*20
worth += C.air_contents.get_moles(GAS_MIASMA)*2
worth += C.air_contents.get_moles(GAS_TRITIUM)*7
worth += C.air_contents.get_moles(GAS_PLUOXIUM)*6
worth += C.air_contents.get_moles(GAS_NITRYL)*10
var/list/gas_prices = GLOB.gas_data.prices
for(var/gas in C.air_contents.get_gases())
worth += C.air_contents.get_moles(gas)*gas_prices[gas]
return worth
+1 -1
View File
@@ -332,7 +332,7 @@
/datum/export/weapon/l6sawammo
cost = 60
unit_name = "L6 SAW ammo box"
export_types = list(/obj/item/ammo_box/magazine/mm195x129)
export_types = list(/obj/item/ammo_box/magazine/mm712x82)
include_subtypes = TRUE
/datum/export/weapon/rocket
+1 -1
View File
@@ -49,7 +49,7 @@
/datum/supply_pack/engineering/engihardsuit
name = "Engineering Hardsuit"
desc = "Poly 'Who stole all the hardsuits!' Well now you can get more hardsuits if needed! NOTE ONE HARDSUIT IS IN THIS CRATE, as well as one air tank and mask!"
desc = "Polly 'Who stole all the hardsuits!' Well now you can get more hardsuits if needed! NOTE ONE HARDSUIT IS IN THIS CRATE, as well as one air tank and mask!"
cost = 2250
access = ACCESS_ENGINE
contains = list(/obj/item/tank/internals/air,
-4
View File
@@ -135,10 +135,6 @@
///Used in MouseDrag to preserve the last mouse-entered object.
var/mouseObject = null
var/mouseControlObject = null
//Middle-mouse-button click dragtime control for aimbot exploit detection.
var/middragtime = 0
//Middle-mouse-button clicked object control for aimbot exploit detection.
var/atom/middragatom
/// Messages currently seen by this client
var/list/seen_messages
+14 -19
View File
@@ -422,10 +422,12 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if( (world.address == address || !address) && !GLOB.host )
GLOB.host = key
world.update_status()
if(holder)
add_admin_verbs()
to_chat(src, get_message_output("memo"))
var/admin_memo_note = get_message_output("memo")
if(admin_memo_note)
to_chat(src, admin_memo_note)
adminGreet()
add_verbs_from_config()
@@ -468,7 +470,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(CONFIG_GET(flag/autoconvert_notes))
convert_notes_sql(ckey)
to_chat(src, get_message_output("message", ckey))
var/admin_message_note = get_message_output("message", ckey)
if(admin_message_note)
to_chat(src, admin_message_note)
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
to_chat(src, "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>")
@@ -867,10 +871,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
return
last_activity = world.time
last_click = world.time
var/ab = FALSE
var/list/L = params2list(params)
if (object && object == middragatom && L["left"])
ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1)
if(L["drag"])
return
var/mcl = CONFIG_GET(number/minute_click_limit)
if (!holder && !ignore_spam && mcl)
var/minute = round(world.time, 600)
@@ -879,20 +884,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if (minute != clicklimiter[CURRENT_MINUTE])
clicklimiter[CURRENT_MINUTE] = minute
clicklimiter[MINUTE_COUNT] = 0
clicklimiter[MINUTE_COUNT] += 1+(ab)
clicklimiter[MINUTE_COUNT] += 1
if (clicklimiter[MINUTE_COUNT] > mcl)
var/msg = "Your previous click was ignored because you've done too many in a minute."
if (minute != clicklimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
clicklimiter[ADMINSWARNED_AT] = minute
msg += " Administrators have been informed."
if (ab)
log_game("[key_name(src)] is using the middle click aimbot exploit")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit</span>")
add_system_note("aimbot", "Is using the middle click aimbot exploit")
log_click(object, location, control, params, src, "lockout (spam - minute ab c [ab] s [middragtime])", TRUE)
else
log_click(object, location, control, params, src, "lockout (spam - minute)", TRUE)
log_click(object, location, control, params, src, "lockout (spam - minute)", TRUE)
log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
to_chat(src, "<span class='danger'>[msg]</span>")
@@ -906,15 +905,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if (second != clicklimiter[CURRENT_SECOND])
clicklimiter[CURRENT_SECOND] = second
clicklimiter[SECOND_COUNT] = 0
clicklimiter[SECOND_COUNT] += 1+(!!ab)
clicklimiter[SECOND_COUNT] += 1
if (clicklimiter[SECOND_COUNT] > scl)
to_chat(src, "<span class='danger'>Your previous click was ignored because you've done too many in a second</span>")
return
if(ab) //Citadel edit, things with stuff.
log_click(object, location, control, params, src, "dropped (ab c [ab] s [middragtime])", TRUE)
return
if(prefs.log_clicks)
log_click(object, location, control, params, src, extra_info? "clicked ([extra_info])" : null)
+109 -10
View File
@@ -140,6 +140,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/modified_limbs = list() //prosthetic/amputated limbs
var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded
// Vocal bark prefs
var/bark_id = "mutedc3"
var/bark_speed = 4
var/bark_pitch = 1
var/bark_variance = 0.2
COOLDOWN_DECLARE(bark_previewing)
/// Security record note section
var/security_records
/// Medical record note section
@@ -153,6 +160,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//Quirk list
var/list/all_quirks = list()
//Quirk category currently selected
var/quirk_category = QUIRK_POSITIVE // defaults to positive, the first tab!
//Job preferences 2.0 - indexed by job title , no key or value implies never
var/list/job_preferences = list()
@@ -223,6 +233,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/screenshake = 100
var/damagescreenshake = 2
var/recoil_screenshake = 100
var/arousable = TRUE
var/autostand = TRUE
var/auto_ooc = FALSE
@@ -401,7 +412,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>Flavor Text</h2>"
dat += "<a href='?_src_=prefs;preference=flavor_text;task=input'><b>Set Examine Text</b></a><br>"
if(length(features["flavor_text"]) <= 40)
if(length(features["flavor_text"]) <= MAX_FLAVOR_PREVIEW_LEN)
if(!length(features["flavor_text"]))
dat += "\[...\]"
else
@@ -410,7 +421,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "[TextPreview(features["flavor_text"])]...<BR>"
dat += "<h2>Silicon Flavor Text</h2>"
dat += "<a href='?_src_=prefs;preference=silicon_flavor_text;task=input'><b>Set Silicon Examine Text</b></a><br>"
if(length(features["silicon_flavor_text"]) <= 40)
if(length(features["silicon_flavor_text"]) <= MAX_FLAVOR_PREVIEW_LEN)
if(!length(features["silicon_flavor_text"]))
dat += "\[...\]"
else
@@ -420,7 +431,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h2>OOC notes</h2>"
dat += "<a href='?_src_=prefs;preference=ooc_notes;task=input'><b>Set OOC notes</b></a><br>"
var/ooc_notes_len = length(features["ooc_notes"])
if(ooc_notes_len <= 40)
if(ooc_notes_len <= MAX_FLAVOR_PREVIEW_LEN)
if(!ooc_notes_len)
dat += "\[...\]"
else
@@ -792,11 +803,21 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>Speech preferences</h2>"
dat += "<b>Custom Speech Verb:</b><BR>"
dat += "</b><a style='display:block;width:100px' href='?_src_=prefs;preference=speech_verb;task=input'>[custom_speech_verb]</a><BR>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=speech_verb;task=input'>[custom_speech_verb]</a><BR>"
dat += "<b>Custom Tongue:</b><BR>"
dat += "</b><a style='display:block;width:100px' href='?_src_=prefs;preference=tongue;task=input'>[custom_tongue]</a><BR>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=tongue;task=input'>[custom_tongue]</a><BR>"
dat += "<b>Additional Language</b><BR>"
dat += "</b><a style='display:block;width:100px' href='?_src_=prefs;preference=language;task=input'>[additional_language]</a><BR>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=language;task=input'>[additional_language]</a><BR>"
dat += "</td>"
dat += "<td width='340px' height='300px' valign='top'>"
dat += "<h2>Vocal Bark preferences</h2>"
var/datum/bark/B = GLOB.bark_list[bark_id]
dat += "<b>Vocal Bark Sound:</b><BR>"
dat += "<a style='display:block;width:200px' href='?_src_=prefs;preference=barksound;task=input'>[B ? initial(B.name) : "INVALID"]</a><BR>"
dat += "<b>Vocal Bark Speed:</b> <a href='?_src_=prefs;preference=barkspeed;task=input'>[bark_speed]</a><BR>"
dat += "<b>Vocal Bark Pitch:</b> <a href='?_src_=prefs;preference=barkpitch;task=input'>[bark_pitch]</a><BR>"
dat += "<b>Vocal Bark Variance:</b> <a href='?_src_=prefs;preference=barkvary;task=input'>[bark_variance]</a><BR>"
dat += "<BR><a href='?_src_=prefs;preference=barkpreview'>Preview Bark</a><BR>"
dat += "</td>"
dat += "</tr></table>"
@@ -887,6 +908,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Screen Shake:</b> <a href='?_src_=prefs;preference=screenshake'>[(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]</a><br>"
if (user && user.client && !user.client.prefs.screenshake==0)
dat += "<b>Damage Screen Shake:</b> <a href='?_src_=prefs;preference=damagescreenshake'>[(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]</a><br>"
dat += "<b>Recoil Screen Push:</b> <a href='?_src_=prefs;preference=recoil_screenshake'>[(recoil_screenshake==100) ? "Full" : ((recoil_screenshake==0) ? "None" : "[screenshake]")]</a><br>"
var/p_chaos
if (!preferred_chaos)
p_chaos = "No preference"
@@ -1464,9 +1486,17 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<hr>"
dat += "<center><b>Current quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<center>[GetPositiveQuirkCount()] / [MAX_QUIRKS] max positive quirks<br>\
<b>Quirk balance remaining:</b> [GetQuirkBalance()]</center><br>"
<b>Quirk balance remaining:</b> [GetQuirkBalance()]<br>"
dat += " <a href='?_src_=prefs;quirk_category=[QUIRK_POSITIVE]' [quirk_category == QUIRK_POSITIVE ? "class='linkOn'" : ""]>[QUIRK_POSITIVE]</a> "
dat += " <a href='?_src_=prefs;quirk_category=[QUIRK_NEUTRAL]' [quirk_category == QUIRK_NEUTRAL ? "class='linkOn'" : ""]>[QUIRK_NEUTRAL]</a> "
dat += " <a href='?_src_=prefs;quirk_category=[QUIRK_NEGATIVE]' [quirk_category == QUIRK_NEGATIVE ? "class='linkOn'" : ""]>[QUIRK_NEGATIVE]</a> "
dat += "</center><br>"
for(var/V in SSquirks.quirks)
var/datum/quirk/T = SSquirks.quirks[V]
var/value = initial(T.value)
if((value > 0 && quirk_category != QUIRK_POSITIVE) || (value < 0 && quirk_category != QUIRK_NEGATIVE) || (value == 0 && quirk_category != QUIRK_NEUTRAL))
continue
var/quirk_name = initial(T.name)
var/has_quirk
var/quirk_cost = initial(T.value) * -1
@@ -1488,7 +1518,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
quirk_cost = "+[quirk_cost]"
var/font_color = "#AAAAFF"
if(initial(T.value) != 0)
font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
font_color = value > 0 ? "#AAFFAA" : "#FFAAAA"
if(quirk_conflict)
dat += "<font color='[font_color]'>[quirk_name]</font> - [initial(T.desc)] \
<font color='red'><b>LOCKED: [lock_reason]</b></font><br>"
@@ -1618,6 +1648,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
SetQuirks(user)
return TRUE
else if(href_list["quirk_category"])
var/temp_quirk_category = href_list["quirk_category"]
if(temp_quirk_category == QUIRK_POSITIVE || temp_quirk_category == QUIRK_NEUTRAL || temp_quirk_category == QUIRK_NEGATIVE)
quirk_category = temp_quirk_category
SetQuirks(user)
switch(href_list["task"])
if("random")
switch(href_list["preference"])
@@ -1697,7 +1733,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("name")
var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null
if(new_name)
new_name = reject_bad_name(new_name)
new_name = reject_bad_name(new_name, allow_numbers = TRUE)
if(new_name)
real_name = new_name
else
@@ -2538,6 +2574,43 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(selected_language)
additional_language = selected_language
if("barksound")
var/list/woof_woof = list()
for(var/path in GLOB.bark_list)
var/datum/bark/B = GLOB.bark_list[path]
if(initial(B.ignore))
continue
if(initial(B.ckeys_allowed))
var/list/allowed = initial(B.ckeys_allowed)
if(!allowed.Find(user.client.ckey))
continue
woof_woof[initial(B.name)] = initial(B.id)
var/new_bork = input(user, "Choose your desired vocal bark", "Character Preference") as null|anything in woof_woof
if(new_bork)
bark_id = woof_woof[new_bork]
var/datum/bark/B = GLOB.bark_list[bark_id] //Now we need sanitization to take into account bark-specific min/max values
bark_speed = round(clamp(bark_speed, initial(B.minspeed), initial(B.maxspeed)), 1)
bark_pitch = clamp(bark_pitch, initial(B.minpitch), initial(B.maxpitch))
bark_variance = clamp(bark_variance, initial(B.minvariance), initial(B.maxvariance))
if("barkspeed")
var/datum/bark/B = GLOB.bark_list[bark_id]
var/borkset = input(user, "Choose your desired bark speed (Higher is slower, lower is faster). Min: [initial(B.minspeed)]. Max: [initial(B.maxspeed)]", "Character Preference") as null|num
if(borkset)
bark_speed = round(clamp(borkset, initial(B.minspeed), initial(B.maxspeed)), 1)
if("barkpitch")
var/datum/bark/B = GLOB.bark_list[bark_id]
var/borkset = input(user, "Choose your desired baseline bark pitch. Min: [initial(B.minpitch)]. Max: [initial(B.maxpitch)]", "Character Preference") as null|num
if(borkset)
bark_pitch = clamp(borkset, initial(B.minpitch), initial(B.maxpitch))
if("barkvary")
var/datum/bark/B = GLOB.bark_list[bark_id]
var/borkset = input(user, "Choose your desired baseline bark pitch. Min: [initial(B.minvariance)]. Max: [initial(B.maxvariance)]", "Character Preference") as null|num
if(borkset)
bark_variance = clamp(borkset, initial(B.minvariance), initial(B.maxvariance))
if("bodysprite")
var/selected_body_sprite = input(user, "Choose your desired body sprite", "Character Preference") as null|anything in pref_species.allowed_limb_ids
if(selected_body_sprite)
@@ -2711,7 +2784,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("no_tetris_storage")
no_tetris_storage = !no_tetris_storage
if ("screenshake")
var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, no maximum (at your own risk).)", "Character Preference", screenshake) as null|num
if (!isnull(desiredshake))
screenshake = desiredshake
if("damagescreenshake")
@@ -2724,6 +2797,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
damagescreenshake = 0
else
damagescreenshake = 1
if ("recoil_screenshake")
var/desiredshake = input(user, "Set the amount of recoil screenshake/push you want. \n(0 = disabled, 100 = full, no maximum (at your own risk).)", "Character Preference", screenshake) as null|num
if (!isnull(desiredshake))
recoil_screenshake = desiredshake
if("nameless")
nameless = !nameless
//END CITADEL EDIT
@@ -2998,6 +3075,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("hud_toggle_flash")
hud_toggle_flash = !hud_toggle_flash
if("barkpreview")
if(SSticker.current_state == GAME_STATE_STARTUP) //Timers don't tick at all during game startup, so let's just give an error message
to_chat(user, "<span class='warning'>Bark previews can't play during initialization!</span>")
return
if(!COOLDOWN_FINISHED(src, bark_previewing))
return
if(!parent || !parent.mob)
return
COOLDOWN_START(src, bark_previewing, (5 SECONDS))
var/atom/movable/barkbox = new(get_turf(parent.mob))
barkbox.set_bark(bark_id)
var/total_delay
for(var/i in 1 to (round((32 / bark_speed)) + 1))
addtimer(CALLBACK(barkbox, /atom/movable/proc/bark, list(parent.mob), 7, 70, BARK_DO_VARY(bark_pitch, bark_variance)), total_delay)
total_delay += rand(DS2TICKS(bark_speed/4), DS2TICKS(bark_speed/4) + DS2TICKS(bark_speed/4)) TICKS
QDEL_IN(barkbox, total_delay)
if("save")
save_preferences()
save_character()
@@ -3219,6 +3313,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.additional_language = language_entry
character.grant_language(language_entry, TRUE, TRUE)
character.set_bark(bark_id)
character.vocal_speed = bark_speed
character.vocal_pitch = bark_pitch
character.vocal_pitch_range = bark_variance
//limb stuff, only done when initially spawning in
if(initial_spawn)
//delete any existing prosthetic limbs to make sure no remnant prosthetics are left over - But DO NOT delete those that are species-related
+324 -308
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 53
#define SAVEFILE_VERSION_MAX 55
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -42,6 +42,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//if your savefile is 3 months out of date, then 'tough shit'.
/datum/preferences/proc/update_preferences(current_version, savefile/S)
if(current_version < 55) //Bitflag toggles don't set their defaults when they're added, always defaulting to off instead.
toggles |= SOUND_BARK
if(current_version < 46) //If you remove this, remove force_reset_keybindings() too.
force_reset_keybindings_direct(TRUE)
addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice.
@@ -72,15 +74,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
var/job_engsec_med = 0
var/job_engsec_low = 0
S["job_civilian_high"] >> job_civilian_high
S["job_civilian_med"] >> job_civilian_med
S["job_civilian_low"] >> job_civilian_low
S["job_medsci_high"] >> job_medsci_high
S["job_medsci_med"] >> job_medsci_med
S["job_medsci_low"] >> job_medsci_low
S["job_engsec_high"] >> job_engsec_high
S["job_engsec_med"] >> job_engsec_med
S["job_engsec_low"] >> job_engsec_low
S["job_civilian_high"] >> job_civilian_high
S["job_civilian_med"] >> job_civilian_med
S["job_civilian_low"] >> job_civilian_low
S["job_medsci_high"] >> job_medsci_high
S["job_medsci_med"] >> job_medsci_med
S["job_medsci_low"] >> job_medsci_low
S["job_engsec_high"] >> job_engsec_high
S["job_engsec_med"] >> job_engsec_med
S["job_engsec_low"] >> job_engsec_low
//Can't use SSjob here since this happens right away on login
for(var/job in subtypesof(/datum/job))
@@ -173,10 +175,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
var/devourable
var/feeding
var/lickable
S["digestable"] >> digestable
S["devourable"] >> devourable
S["feeding"] >> feeding
S["lickable"] >> lickable
S["digestable"] >> digestable
S["devourable"] >> devourable
S["feeding"] >> feeding
S["lickable"] >> lickable
if(digestable)
vore_flags |= DIGESTABLE
if(devourable)
@@ -196,8 +198,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["taur"] = "Cow (Spotted)"
if(current_version < 31)
S["wing_color"] >> features["wings_color"]
S["horn_color"] >> features["horns_color"]
S["wing_color"] >> features["wings_color"]
S["horn_color"] >> features["horns_color"]
if(current_version < 33)
features["flavor_text"] = html_encode(features["flavor_text"])
@@ -346,6 +348,16 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(current_version < 53)
parallax = PARALLAX_INSANE
// Some genius decided to make features update on the loading part, go figure.
if(current_version < 54)
var/old_silicon_flavor = S["silicon_feature_flavor_text"]
if(length(old_silicon_flavor))
features["feature_silicon_flavor_text"] = old_silicon_flavor
var/old_flavor_text = S["flavor_text"]
// If they have the old flavor text but also have the new one, i suppose the new one is more important.
if(length(old_flavor_text) && !length(features["feature_flavor_text"]))
features["feature_flavor_text"] = old_flavor_text
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -380,70 +392,70 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
. = TRUE
//general preferences
S["ooccolor"] >> ooccolor
S["lastchangelog"] >> lastchangelog
S["UI_style"] >> UI_style
S["outline_color"] >> outline_color
S["outline_enabled"] >> outline_enabled
S["screentip_pref"] >> screentip_pref
S["screentip_color"] >> screentip_color
S["hotkeys"] >> hotkeys
S["chat_on_map"] >> chat_on_map
S["max_chat_length"] >> max_chat_length
S["ooccolor"] >> ooccolor
S["lastchangelog"] >> lastchangelog
S["UI_style"] >> UI_style
S["outline_color"] >> outline_color
S["outline_enabled"] >> outline_enabled
S["screentip_pref"] >> screentip_pref
S["screentip_color"] >> screentip_color
S["hotkeys"] >> hotkeys
S["chat_on_map"] >> chat_on_map
S["max_chat_length"] >> max_chat_length
S["see_chat_non_mob"] >> see_chat_non_mob
S["tgui_fancy"] >> tgui_fancy
S["tgui_lock"] >> tgui_lock
S["buttons_locked"] >> buttons_locked
S["windowflash"] >> windowflashing
S["tgui_fancy"] >> tgui_fancy
S["tgui_lock"] >> tgui_lock
S["buttons_locked"] >> buttons_locked
S["windowflash"] >> windowflashing
S["be_special"] >> be_special
S["default_slot"] >> default_slot
S["chat_toggles"] >> chat_toggles
S["toggles"] >> toggles
S["deadmin"] >> deadmin
S["ghost_form"] >> ghost_form
S["ghost_orbit"] >> ghost_orbit
S["ghost_accs"] >> ghost_accs
S["ghost_others"] >> ghost_others
S["preferred_map"] >> preferred_map
S["ignoring"] >> ignoring
S["ghost_hud"] >> ghost_hud
S["inquisitive_ghost"] >> inquisitive_ghost
S["default_slot"] >> default_slot
S["chat_toggles"] >> chat_toggles
S["toggles"] >> toggles
S["deadmin"] >> deadmin
S["ghost_form"] >> ghost_form
S["ghost_orbit"] >> ghost_orbit
S["ghost_accs"] >> ghost_accs
S["ghost_others"] >> ghost_others
S["preferred_map"] >> preferred_map
S["ignoring"] >> ignoring
S["ghost_hud"] >> ghost_hud
S["inquisitive_ghost"] >> inquisitive_ghost
S["uses_glasses_colour"]>> uses_glasses_colour
S["clientfps"] >> clientfps
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
S["widescreenpref"] >> widescreenpref
S["long_strip_menu"] >> long_strip_menu
S["clientfps"] >> clientfps
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
S["widescreenpref"] >> widescreenpref
S["long_strip_menu"] >> long_strip_menu
S["pixel_size"] >> pixel_size
S["scaling_method"] >> scaling_method
S["hud_toggle_flash"] >> hud_toggle_flash
S["hud_toggle_color"] >> hud_toggle_color
S["menuoptions"] >> menuoptions
S["enable_tips"] >> enable_tips
S["tip_delay"] >> tip_delay
S["pda_style"] >> pda_style
S["pda_color"] >> pda_color
S["pda_skin"] >> pda_skin
S["hud_toggle_flash"] >> hud_toggle_flash
S["hud_toggle_color"] >> hud_toggle_color
S["menuoptions"] >> menuoptions
S["enable_tips"] >> enable_tips
S["tip_delay"] >> tip_delay
S["pda_style"] >> pda_style
S["pda_color"] >> pda_color
S["pda_skin"] >> pda_skin
// Custom hotkeys
S["key_bindings"] >> key_bindings
S["modless_key_bindings"] >> modless_key_bindings
S["key_bindings"] >> key_bindings
S["modless_key_bindings"] >> modless_key_bindings
//citadel code
S["arousable"] >> arousable
S["screenshake"] >> screenshake
S["damagescreenshake"] >> damagescreenshake
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
S["preferred_chaos"] >> preferred_chaos
S["auto_ooc"] >> auto_ooc
S["no_tetris_storage"] >> no_tetris_storage
S["arousable"] >> arousable
S["screenshake"] >> screenshake
S["damagescreenshake"] >> damagescreenshake
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
S["preferred_chaos"] >> preferred_chaos
S["auto_ooc"] >> auto_ooc
S["no_tetris_storage"] >> no_tetris_storage
//favorite outfits
S["favorite_outfits"] >> favorite_outfits
S["favorite_outfits"] >> favorite_outfits
var/list/parsed_favs = list()
for(var/typetext in favorite_outfits)
@@ -461,47 +473,47 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
update_preferences(needs_update, S) //needs_update = savefile_version if we need an update (positive integer)
//Sanitize
ooccolor = sanitize_ooccolor(sanitize_hexcolor(ooccolor, 6, 1, initial(ooccolor)))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
UI_style = sanitize_inlist(UI_style, GLOB.available_ui_styles, GLOB.available_ui_styles[1])
hotkeys = sanitize_integer(hotkeys, 0, 1, initial(hotkeys))
chat_on_map = sanitize_integer(chat_on_map, 0, 1, initial(chat_on_map))
ooccolor = sanitize_ooccolor(sanitize_hexcolor(ooccolor, 6, 1, initial(ooccolor)))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
UI_style = sanitize_inlist(UI_style, GLOB.available_ui_styles, GLOB.available_ui_styles[1])
hotkeys = sanitize_integer(hotkeys, 0, 1, initial(hotkeys))
chat_on_map = sanitize_integer(chat_on_map, 0, 1, initial(chat_on_map))
max_chat_length = sanitize_integer(max_chat_length, 1, CHAT_MESSAGE_MAX_LENGTH, initial(max_chat_length))
see_chat_non_mob = sanitize_integer(see_chat_non_mob, 0, 1, initial(see_chat_non_mob))
tgui_fancy = sanitize_integer(tgui_fancy, 0, 1, initial(tgui_fancy))
tgui_lock = sanitize_integer(tgui_lock, 0, 1, initial(tgui_lock))
buttons_locked = sanitize_integer(buttons_locked, 0, 1, initial(buttons_locked))
windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing))
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 16777215, initial(toggles))
deadmin = sanitize_integer(deadmin, 0, 16777215, initial(deadmin))
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
parallax = sanitize_integer(parallax, PARALLAX_DISABLE, PARALLAX_INSANE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
long_strip_menu = sanitize_integer(long_strip_menu, 0, 1, initial(long_strip_menu))
pixel_size = sanitize_integer(pixel_size, PIXEL_SCALING_AUTO, PIXEL_SCALING_3X, initial(pixel_size))
scaling_method = sanitize_text(scaling_method, initial(scaling_method))
see_chat_non_mob = sanitize_integer(see_chat_non_mob, 0, 1, initial(see_chat_non_mob))
tgui_fancy = sanitize_integer(tgui_fancy, 0, 1, initial(tgui_fancy))
tgui_lock = sanitize_integer(tgui_lock, 0, 1, initial(tgui_lock))
buttons_locked = sanitize_integer(buttons_locked, 0, 1, initial(buttons_locked))
windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing))
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 16777215, initial(toggles))
deadmin = sanitize_integer(deadmin, 0, 16777215, initial(deadmin))
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
parallax = sanitize_integer(parallax, PARALLAX_DISABLE, PARALLAX_INSANE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
long_strip_menu = sanitize_integer(long_strip_menu, 0, 1, initial(long_strip_menu))
pixel_size = sanitize_integer(pixel_size, PIXEL_SCALING_AUTO, PIXEL_SCALING_3X, initial(pixel_size))
scaling_method = sanitize_text(scaling_method, initial(scaling_method))
hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash))
hud_toggle_color = sanitize_hexcolor(hud_toggle_color, 6, 1, initial(hud_toggle_color))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit))
ghost_accs = sanitize_inlist(ghost_accs, GLOB.ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION)
ghost_others = sanitize_inlist(ghost_others, GLOB.ghost_others_options, GHOST_OTHERS_DEFAULT_OPTION)
menuoptions = SANITIZE_LIST(menuoptions)
be_special = SANITIZE_LIST(be_special)
pda_style = sanitize_inlist(pda_style, GLOB.pda_styles, initial(pda_style))
pda_color = sanitize_hexcolor(pda_color, 6, 1, initial(pda_color))
pda_skin = sanitize_inlist(pda_skin, GLOB.pda_reskins, PDA_SKIN_ALT)
screenshake = sanitize_integer(screenshake, 0, 800, initial(screenshake))
damagescreenshake = sanitize_integer(damagescreenshake, 0, 2, initial(damagescreenshake))
autostand = sanitize_integer(autostand, 0, 1, initial(autostand))
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
key_bindings = sanitize_islist(key_bindings, list())
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit))
ghost_accs = sanitize_inlist(ghost_accs, GLOB.ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION)
ghost_others = sanitize_inlist(ghost_others, GLOB.ghost_others_options, GHOST_OTHERS_DEFAULT_OPTION)
menuoptions = SANITIZE_LIST(menuoptions)
be_special = SANITIZE_LIST(be_special)
pda_style = sanitize_inlist(pda_style, GLOB.pda_styles, initial(pda_style))
pda_color = sanitize_hexcolor(pda_color, 6, 1, initial(pda_color))
pda_skin = sanitize_inlist(pda_skin, GLOB.pda_reskins, PDA_SKIN_ALT)
screenshake = sanitize_integer(screenshake, 0, 800, initial(screenshake))
damagescreenshake = sanitize_integer(damagescreenshake, 0, 2, initial(damagescreenshake))
autostand = sanitize_integer(autostand, 0, 1, initial(autostand))
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
key_bindings = sanitize_islist(key_bindings, list())
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
favorite_outfits = SANITIZE_LIST(favorite_outfits)
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
@@ -663,7 +675,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Species
var/species_id
S["species"] >> species_id
S["species"] >> species_id
if(species_id)
if(species_id == "avian" || species_id == "aquatic")
species_id = "mammal"
@@ -678,63 +690,63 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
scars_index = rand(1,5) // WHY
//Character
S["real_name"] >> real_name
S["nameless"] >> nameless
S["custom_species"] >> custom_species
S["name_is_always_random"] >> be_random_name
S["body_is_always_random"] >> be_random_body
S["gender"] >> gender
S["body_model"] >> features["body_model"]
S["body_size"] >> features["body_size"]
S["age"] >> age
S["hair_color"] >> hair_color
S["facial_hair_color"] >> facial_hair_color
S["eye_type"] >> eye_type
S["left_eye_color"] >> left_eye_color
S["right_eye_color"] >> right_eye_color
S["use_custom_skin_tone"] >> use_custom_skin_tone
S["skin_tone"] >> skin_tone
S["hair_style_name"] >> hair_style
S["facial_style_name"] >> facial_hair_style
S["grad_style"] >> grad_style
S["grad_color"] >> grad_color
S["underwear"] >> underwear
S["undie_color"] >> undie_color
S["undershirt"] >> undershirt
S["shirt_color"] >> shirt_color
S["socks"] >> socks
S["socks_color"] >> socks_color
S["backbag"] >> backbag
S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
S["custom_speech_verb"] >> custom_speech_verb
S["custom_tongue"] >> custom_tongue
S["additional_language"] >> additional_language
S["feature_mcolor"] >> features["mcolor"]
S["feature_lizard_tail"] >> features["tail_lizard"]
S["feature_lizard_snout"] >> features["snout"]
S["feature_lizard_horns"] >> features["horns"]
S["feature_lizard_frills"] >> features["frills"]
S["feature_lizard_spines"] >> features["spines"]
S["feature_lizard_legs"] >> features["legs"]
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
S["feature_deco_wings"] >> features["deco_wings"]
S["feature_insect_wings"] >> features["insect_wings"]
S["feature_insect_fluff"] >> features["insect_fluff"]
S["feature_insect_markings"] >> features["insect_markings"]
S["feature_arachnid_legs"] >> features["arachnid_legs"]
S["feature_arachnid_spinneret"] >> features["arachnid_spinneret"]
S["feature_arachnid_mandibles"] >> features["arachnid_mandibles"]
S["feature_horns_color"] >> features["horns_color"]
S["feature_wings_color"] >> features["wings_color"]
S["feature_color_scheme"] >> features["color_scheme"]
S["real_name"] >> real_name
S["nameless"] >> nameless
S["custom_species"] >> custom_species
S["name_is_always_random"] >> be_random_name
S["body_is_always_random"] >> be_random_body
S["gender"] >> gender
S["body_model"] >> features["body_model"]
S["body_size"] >> features["body_size"]
S["age"] >> age
S["hair_color"] >> hair_color
S["facial_hair_color"] >> facial_hair_color
S["eye_type"] >> eye_type
S["left_eye_color"] >> left_eye_color
S["right_eye_color"] >> right_eye_color
S["use_custom_skin_tone"] >> use_custom_skin_tone
S["skin_tone"] >> skin_tone
S["hair_style_name"] >> hair_style
S["facial_style_name"] >> facial_hair_style
S["grad_style"] >> grad_style
S["grad_color"] >> grad_color
S["underwear"] >> underwear
S["undie_color"] >> undie_color
S["undershirt"] >> undershirt
S["shirt_color"] >> shirt_color
S["socks"] >> socks
S["socks_color"] >> socks_color
S["backbag"] >> backbag
S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
S["custom_speech_verb"] >> custom_speech_verb
S["custom_tongue"] >> custom_tongue
S["additional_language"] >> additional_language
S["feature_mcolor"] >> features["mcolor"]
S["feature_lizard_tail"] >> features["tail_lizard"]
S["feature_lizard_snout"] >> features["snout"]
S["feature_lizard_horns"] >> features["horns"]
S["feature_lizard_frills"] >> features["frills"]
S["feature_lizard_spines"] >> features["spines"]
S["feature_lizard_legs"] >> features["legs"]
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
S["feature_deco_wings"] >> features["deco_wings"]
S["feature_insect_wings"] >> features["insect_wings"]
S["feature_insect_fluff"] >> features["insect_fluff"]
S["feature_insect_markings"] >> features["insect_markings"]
S["feature_arachnid_legs"] >> features["arachnid_legs"]
S["feature_arachnid_spinneret"] >> features["arachnid_spinneret"]
S["feature_arachnid_mandibles"] >> features["arachnid_mandibles"]
S["feature_horns_color"] >> features["horns_color"]
S["feature_wings_color"] >> features["wings_color"]
S["feature_color_scheme"] >> features["color_scheme"]
S["persistent_scars"] >> persistent_scars
S["scars1"] >> scars_list["1"]
S["scars2"] >> scars_list["2"]
S["scars3"] >> scars_list["3"]
S["scars4"] >> scars_list["4"]
S["scars5"] >> scars_list["5"]
S["scars1"] >> scars_list["1"]
S["scars2"] >> scars_list["2"]
S["scars3"] >> scars_list["3"]
S["scars4"] >> scars_list["4"]
S["scars5"] >> scars_list["5"]
var/limbmodstr
S["modified_limbs"] >> limbmodstr
if(length(limbmodstr))
@@ -756,100 +768,94 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
else
tcg_decks = list()
S["chosen_limb_id"] >> chosen_limb_id
S["hide_ckey"] >> hide_ckey //saved per-character
S["chosen_limb_id"] >> chosen_limb_id
S["hide_ckey"] >> hide_ckey //saved per-character
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
var/savefile_slot_name = custom_name_id + "_name" //TODO remove this
S[savefile_slot_name] >> custom_names[custom_name_id]
S["preferred_ai_core_display"] >> preferred_ai_core_display
S["prefered_security_department"] >> prefered_security_department
S["preferred_ai_core_display"] >> preferred_ai_core_display
S["prefered_security_department"] >> prefered_security_department
//Jobs
S["joblessrole"] >> joblessrole
S["joblessrole"] >> joblessrole
//Load prefs
S["job_preferences"] >> job_preferences
S["job_preferences"] >> job_preferences
//Quirks
S["all_quirks"] >> all_quirks
S["all_quirks"] >> all_quirks
//Records
S["security_records"] >> security_records
S["medical_records"] >> medical_records
S["security_records"] >> security_records
S["medical_records"] >> medical_records
//Citadel code
S["feature_genitals_use_skintone"] >> features["genitals_use_skintone"]
S["feature_mcolor2"] >> features["mcolor2"]
S["feature_mcolor3"] >> features["mcolor3"]
S["feature_genitals_use_skintone"] >> features["genitals_use_skintone"]
S["feature_mcolor2"] >> features["mcolor2"]
S["feature_mcolor3"] >> features["mcolor3"]
// note safe json decode will runtime the first time it migrates but this is fine and it solves itself don't worry about it if you see it error
features["mam_body_markings"] = safe_json_decode(S["feature_mam_body_markings"])
S["feature_mam_tail"] >> features["mam_tail"]
S["feature_mam_ears"] >> features["mam_ears"]
S["feature_mam_tail_animated"] >> features["mam_tail_animated"]
S["feature_taur"] >> features["taur"]
S["feature_mam_snouts"] >> features["mam_snouts"]
S["feature_meat"] >> features["meat_type"]
S["feature_mam_tail"] >> features["mam_tail"]
S["feature_mam_ears"] >> features["mam_ears"]
S["feature_mam_tail_animated"] >> features["mam_tail_animated"]
S["feature_taur"] >> features["taur"]
S["feature_mam_snouts"] >> features["mam_snouts"]
S["feature_meat"] >> features["meat_type"]
//Xeno features
S["feature_xeno_tail"] >> features["xenotail"]
S["feature_xeno_dors"] >> features["xenodorsal"]
S["feature_xeno_head"] >> features["xenohead"]
S["feature_xeno_tail"] >> features["xenotail"]
S["feature_xeno_dors"] >> features["xenodorsal"]
S["feature_xeno_head"] >> features["xenohead"]
//cock features
S["feature_has_cock"] >> features["has_cock"]
S["feature_cock_shape"] >> features["cock_shape"]
S["feature_cock_color"] >> features["cock_color"]
S["feature_cock_length"] >> features["cock_length"]
S["feature_cock_diameter"] >> features["cock_diameter"]
S["feature_cock_taur"] >> features["cock_taur"]
S["feature_cock_visibility"] >> features["cock_visibility"]
S["feature_has_cock"] >> features["has_cock"]
S["feature_cock_shape"] >> features["cock_shape"]
S["feature_cock_color"] >> features["cock_color"]
S["feature_cock_length"] >> features["cock_length"]
S["feature_cock_diameter"] >> features["cock_diameter"]
S["feature_cock_taur"] >> features["cock_taur"]
S["feature_cock_visibility"] >> features["cock_visibility"]
//balls features
S["feature_has_balls"] >> features["has_balls"]
S["feature_balls_color"] >> features["balls_color"]
S["feature_balls_shape"] >> features["balls_shape"]
S["feature_balls_size"] >> features["balls_size"]
S["feature_balls_visibility"] >> features["balls_visibility"]
S["feature_has_balls"] >> features["has_balls"]
S["feature_balls_color"] >> features["balls_color"]
S["feature_balls_shape"] >> features["balls_shape"]
S["feature_balls_size"] >> features["balls_size"]
S["feature_balls_visibility"] >> features["balls_visibility"]
//breasts features
S["feature_has_breasts"] >> features["has_breasts"]
S["feature_breasts_size"] >> features["breasts_size"]
S["feature_breasts_shape"] >> features["breasts_shape"]
S["feature_breasts_color"] >> features["breasts_color"]
S["feature_breasts_producing"] >> features["breasts_producing"]
S["feature_breasts_visibility"] >> features["breasts_visibility"]
S["feature_has_breasts"] >> features["has_breasts"]
S["feature_breasts_size"] >> features["breasts_size"]
S["feature_breasts_shape"] >> features["breasts_shape"]
S["feature_breasts_color"] >> features["breasts_color"]
S["feature_breasts_producing"] >> features["breasts_producing"]
S["feature_breasts_visibility"] >> features["breasts_visibility"]
//vagina features
S["feature_has_vag"] >> features["has_vag"]
S["feature_vag_shape"] >> features["vag_shape"]
S["feature_vag_color"] >> features["vag_color"]
S["feature_vag_visibility"] >> features["vag_visibility"]
S["feature_has_vag"] >> features["has_vag"]
S["feature_vag_shape"] >> features["vag_shape"]
S["feature_vag_color"] >> features["vag_color"]
S["feature_vag_visibility"] >> features["vag_visibility"]
//womb features
S["feature_has_womb"] >> features["has_womb"]
S["feature_has_womb"] >> features["has_womb"]
//butt features
S["feature_has_butt"] >> features["has_butt"]
S["feature_butt_color"] >> features["butt_color"]
S["feature_butt_size"] >> features["butt_size"]
S["feature_butt_visibility"] >> features["butt_visibility"]
S["feature_has_butt"] >> features["has_butt"]
S["feature_butt_color"] >> features["butt_color"]
S["feature_butt_size"] >> features["butt_size"]
S["feature_butt_visibility"] >> features["butt_visibility"]
//flavor text
//Let's make our players NOT cry desperately as we wipe their savefiles of their special snowflake texts:
if((S["flavor_text"] != "") && (S["flavor_text"] != null) && S["flavor_text"]) //If old text isn't null and isn't "" but still exists.
S["flavor_text"] >> features["flavor_text"] //Load old flavortext as current dna-based flavortext
// Flavor texts, Made into a standard.
S["feature_flavor_text"] >> features["flavor_text"]
S["feature_silicon_flavor_text"] >> features["silicon_flavor_text"]
S["feature_ooc_notes"] >> features["ooc_notes"]
WRITE_FILE(S["feature_flavor_text"], features["flavor_text"]) //Save it in our new type of flavor-text
WRITE_FILE(S["flavor_text"] , "") //Remove old flavortext, completing the cut-and-paste into the new format.
// Barks
S["bark_id"] >> bark_id
S["bark_speed"] >> bark_speed
S["bark_pitch"] >> bark_pitch
S["bark_variance"] >> bark_variance
else //We have no old flavortext, default to new
S["feature_flavor_text"] >> features["flavor_text"]
S["silicon_feature_flavor_text"] >> features["silicon_flavor_text"]
S["feature_ooc_notes"] >> features["ooc_notes"]
S["silicon_flavor_text"] >> features["silicon_flavor_text"]
S["vore_flags"] >> vore_flags
S["vore_taste"] >> vore_taste
S["vore_smell"] >> vore_smell
S["vore_flags"] >> vore_flags
S["vore_taste"] >> vore_taste
S["vore_smell"] >> vore_smell
var/char_vr_path = "[vr_path]/character_[default_slot]_v2.json"
if(fexists(char_vr_path))
var/list/json_from_file = json_decode(file2text(char_vr_path))
@@ -869,69 +875,69 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Sanitize
real_name = reject_bad_name(real_name)
gender = sanitize_gender(gender, TRUE, TRUE)
real_name = reject_bad_name(real_name)
gender = sanitize_gender(gender, TRUE, TRUE)
features["body_model"] = sanitize_gender(features["body_model"], FALSE, FALSE, gender == FEMALE ? FEMALE : MALE)
if(!real_name)
real_name = random_unique_name(gender)
custom_species = reject_bad_name(custom_species)
real_name = random_unique_name(gender)
custom_species = reject_bad_name(custom_species)
for(var/custom_name_id in GLOB.preferences_custom_names)
var/namedata = GLOB.preferences_custom_names[custom_name_id]
custom_names[custom_name_id] = reject_bad_name(custom_names[custom_name_id],namedata["allow_numbers"])
if(!custom_names[custom_name_id])
custom_names[custom_name_id] = get_default_name(custom_name_id)
nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_list)
facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_list)
underwear = sanitize_inlist(underwear, GLOB.underwear_list)
undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list)
undie_color = sanitize_hexcolor(undie_color, 6, FALSE, initial(undie_color))
shirt_color = sanitize_hexcolor(shirt_color, 6, FALSE, initial(shirt_color))
socks = sanitize_inlist(socks, GLOB.socks_list)
socks_color = sanitize_hexcolor(socks_color, 6, FALSE, initial(socks_color))
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
hair_color = sanitize_hexcolor(hair_color, 6, FALSE)
facial_hair_color = sanitize_hexcolor(facial_hair_color, 6, FALSE)
grad_style = sanitize_inlist(grad_style, GLOB.hair_gradients_list, "None")
grad_color = sanitize_hexcolor(grad_color, 6, FALSE)
eye_type = sanitize_inlist(eye_type, GLOB.eye_types, DEFAULT_EYES_TYPE)
left_eye_color = sanitize_hexcolor(left_eye_color, 6, FALSE)
right_eye_color = sanitize_hexcolor(right_eye_color, 6, FALSE)
hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_list)
facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_list)
underwear = sanitize_inlist(underwear, GLOB.underwear_list)
undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list)
undie_color = sanitize_hexcolor(undie_color, 6, FALSE, initial(undie_color))
shirt_color = sanitize_hexcolor(shirt_color, 6, FALSE, initial(shirt_color))
socks = sanitize_inlist(socks, GLOB.socks_list)
socks_color = sanitize_hexcolor(socks_color, 6, FALSE, initial(socks_color))
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
hair_color = sanitize_hexcolor(hair_color, 6, FALSE)
facial_hair_color = sanitize_hexcolor(facial_hair_color, 6, FALSE)
grad_style = sanitize_inlist(grad_style, GLOB.hair_gradients_list, "None")
grad_color = sanitize_hexcolor(grad_color, 6, FALSE)
eye_type = sanitize_inlist(eye_type, GLOB.eye_types, DEFAULT_EYES_TYPE)
left_eye_color = sanitize_hexcolor(left_eye_color, 6, FALSE)
right_eye_color = sanitize_hexcolor(right_eye_color, 6, FALSE)
var/static/allow_custom_skintones
if(isnull(allow_custom_skintones))
allow_custom_skintones = CONFIG_GET(flag/allow_custom_skintones)
use_custom_skin_tone = allow_custom_skintones ? sanitize_integer(use_custom_skin_tone, FALSE, TRUE, initial(use_custom_skin_tone)) : FALSE
use_custom_skin_tone = allow_custom_skintones ? sanitize_integer(use_custom_skin_tone, FALSE, TRUE, initial(use_custom_skin_tone)) : FALSE
if(use_custom_skin_tone)
skin_tone = sanitize_hexcolor(skin_tone, 6, TRUE, "#FFFFFF")
skin_tone = sanitize_hexcolor(skin_tone, 6, TRUE, "#FFFFFF")
else
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones - GLOB.nonstandard_skin_tones, initial(skin_tone))
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones - GLOB.nonstandard_skin_tones, initial(skin_tone))
features["horns_color"] = sanitize_hexcolor(features["horns_color"], 6, FALSE, "85615a")
features["wings_color"] = sanitize_hexcolor(features["wings_color"], 6, FALSE, "FFFFFF")
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
features["mcolor"] = sanitize_hexcolor(features["mcolor"], 6, FALSE)
features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human)
features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list)
features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list)
features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list)
features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list)
features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list)
features["legs"] = sanitize_inlist(features["legs"], GLOB.legs_list, "Plantigrade")
features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list, "None")
features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None")
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
features["arachnid_legs"] = sanitize_inlist(features["arachnid_legs"], GLOB.arachnid_legs_list, "Plain")
features["arachnid_spinneret"] = sanitize_inlist(features["arachnid_spinneret"], GLOB.arachnid_spinneret_list, "Plain")
features["arachnid_mandibles"] = sanitize_inlist(features["arachnid_mandibles"], GLOB.arachnid_mandibles_list, "Plain")
features["horns_color"] = sanitize_hexcolor(features["horns_color"], 6, FALSE, "85615a")
features["wings_color"] = sanitize_hexcolor(features["wings_color"], 6, FALSE, "FFFFFF")
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
features["mcolor"] = sanitize_hexcolor(features["mcolor"], 6, FALSE)
features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human)
features["snout"] = sanitize_inlist(features["snout"], GLOB.snouts_list)
features["horns"] = sanitize_inlist(features["horns"], GLOB.horns_list)
features["ears"] = sanitize_inlist(features["ears"], GLOB.ears_list)
features["frills"] = sanitize_inlist(features["frills"], GLOB.frills_list)
features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list)
features["legs"] = sanitize_inlist(features["legs"], GLOB.legs_list, "Plantigrade")
features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list, "None")
features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None")
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
features["arachnid_legs"] = sanitize_inlist(features["arachnid_legs"], GLOB.arachnid_legs_list, "Plain")
features["arachnid_spinneret"] = sanitize_inlist(features["arachnid_spinneret"], GLOB.arachnid_spinneret_list, "Plain")
features["arachnid_mandibles"] = sanitize_inlist(features["arachnid_mandibles"], GLOB.arachnid_mandibles_list, "Plain")
var/static/size_min
if(!size_min)
@@ -939,7 +945,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
var/static/size_max
if(!size_max)
size_max = CONFIG_GET(number/body_size_max)
features["body_size"] = sanitize_num_clamp(features["body_size"], size_min, size_max, RESIZE_DEFAULT_SIZE, 0.01)
features["body_size"] = sanitize_num_clamp(features["body_size"], size_min, size_max, RESIZE_DEFAULT_SIZE, 0.01)
var/static/list/B_sizes
if(!B_sizes)
@@ -963,33 +969,33 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
var/list/L = CONFIG_GET(keyed_list/safe_visibility_toggles)
safe_visibilities = L.Copy()
features["breasts_size"] = sanitize_inlist(features["breasts_size"], B_sizes, BREASTS_SIZE_DEF)
features["cock_length"] = sanitize_integer(features["cock_length"], min_D, max_D, COCK_SIZE_DEF)
features["butt_size"] = sanitize_integer(features["butt_size"], min_B, max_B, BUTT_SIZE_DEF)
features["breasts_shape"] = sanitize_inlist(features["breasts_shape"], GLOB.breasts_shapes_list, DEF_BREASTS_SHAPE)
features["cock_shape"] = sanitize_inlist(features["cock_shape"], GLOB.cock_shapes_list, DEF_COCK_SHAPE)
features["balls_shape"] = sanitize_inlist(features["balls_shape"], GLOB.balls_shapes_list, DEF_BALLS_SHAPE)
features["vag_shape"] = sanitize_inlist(features["vag_shape"], GLOB.vagina_shapes_list, DEF_VAGINA_SHAPE)
features["breasts_color"] = sanitize_hexcolor(features["breasts_color"], 6, FALSE, "FFFFFF")
features["cock_color"] = sanitize_hexcolor(features["cock_color"], 6, FALSE, "FFFFFF")
features["balls_color"] = sanitize_hexcolor(features["balls_color"], 6, FALSE, "FFFFFF")
features["vag_color"] = sanitize_hexcolor(features["vag_color"], 6, FALSE, "FFFFFF")
features["breasts_visibility"] = sanitize_inlist(features["breasts_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["cock_visibility"] = sanitize_inlist(features["cock_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["balls_visibility"] = sanitize_inlist(features["balls_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["vag_visibility"] = sanitize_inlist(features["vag_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["butt_visibility"] = sanitize_inlist(features["butt_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["breasts_size"] = sanitize_inlist(features["breasts_size"], B_sizes, BREASTS_SIZE_DEF)
features["cock_length"] = sanitize_integer(features["cock_length"], min_D, max_D, COCK_SIZE_DEF)
features["butt_size"] = sanitize_integer(features["butt_size"], min_B, max_B, BUTT_SIZE_DEF)
features["breasts_shape"] = sanitize_inlist(features["breasts_shape"], GLOB.breasts_shapes_list, DEF_BREASTS_SHAPE)
features["cock_shape"] = sanitize_inlist(features["cock_shape"], GLOB.cock_shapes_list, DEF_COCK_SHAPE)
features["balls_shape"] = sanitize_inlist(features["balls_shape"], GLOB.balls_shapes_list, DEF_BALLS_SHAPE)
features["vag_shape"] = sanitize_inlist(features["vag_shape"], GLOB.vagina_shapes_list, DEF_VAGINA_SHAPE)
features["breasts_color"] = sanitize_hexcolor(features["breasts_color"], 6, FALSE, "FFFFFF")
features["cock_color"] = sanitize_hexcolor(features["cock_color"], 6, FALSE, "FFFFFF")
features["balls_color"] = sanitize_hexcolor(features["balls_color"], 6, FALSE, "FFFFFF")
features["vag_color"] = sanitize_hexcolor(features["vag_color"], 6, FALSE, "FFFFFF")
features["breasts_visibility"] = sanitize_inlist(features["breasts_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["cock_visibility"] = sanitize_inlist(features["cock_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["balls_visibility"] = sanitize_inlist(features["balls_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["vag_visibility"] = sanitize_inlist(features["vag_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
features["butt_visibility"] = sanitize_inlist(features["butt_visibility"], safe_visibilities, GEN_VISIBLE_NO_UNDIES)
custom_speech_verb = sanitize_inlist(custom_speech_verb, GLOB.speech_verbs, "default")
custom_tongue = sanitize_inlist(custom_tongue, GLOB.roundstart_tongues, "default")
additional_language = sanitize_inlist(additional_language, GLOB.roundstart_languages, "None")
custom_speech_verb = sanitize_inlist(custom_speech_verb, GLOB.speech_verbs, "default")
custom_tongue = sanitize_inlist(custom_tongue, GLOB.roundstart_tongues, "default")
additional_language = sanitize_inlist(additional_language, GLOB.roundstart_languages, "None")
security_records = copytext(security_records, 1, MAX_FLAVOR_LEN)
medical_records = copytext(medical_records, 1, MAX_FLAVOR_LEN)
security_records = copytext(security_records, 1, MAX_FLAVOR_LEN)
medical_records = copytext(medical_records, 1, MAX_FLAVOR_LEN)
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
//load every advanced coloring mode thing in one go
//THIS MUST BE DONE AFTER ALL FEATURE SAVES OR IT WILL NOT WORK
@@ -1011,11 +1017,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
message_admins("Sprite Accessory Failure (loading data): Accessory [accessory.type] is a matrixed item without any matrixed sections set!")
continue
if(S["feature_[primary_string]"])
S["feature_[primary_string]"] >> features[primary_string]
S["feature_[primary_string]"] >> features[primary_string]
if(S["feature_[secondary_string]"])
S["feature_[secondary_string]"] >> features[secondary_string]
S["feature_[secondary_string]"] >> features[secondary_string]
if(S["feature_[tertiary_string]"])
S["feature_[tertiary_string]"] >> features[tertiary_string]
S["feature_[tertiary_string]"] >> features[tertiary_string]
persistent_scars = sanitize_integer(persistent_scars)
scars_list["1"] = sanitize_text(scars_list["1"])
@@ -1024,7 +1030,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
scars_list["4"] = sanitize_text(scars_list["4"])
scars_list["5"] = sanitize_text(scars_list["5"])
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
bark_id = sanitize_inlist(bark_id, GLOB.bark_list, pick(GLOB.bark_random_list))
var/datum/bark/bark_path = GLOB.bark_list[bark_id]
bark_speed = sanitize_num_clamp(bark_speed, initial(bark_path.minspeed), initial(bark_path.maxspeed), initial(bark_speed))
bark_pitch = sanitize_num_clamp(bark_pitch, initial(bark_path.minpitch), initial(bark_path.maxpitch), BARK_PITCH_RAND(gender))
bark_variance = sanitize_num_clamp(bark_variance, initial(bark_path.minvariance), initial(bark_path.maxvariance), BARK_VARIANCE_RAND)
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs
for(var/j in job_preferences)
if(job_preferences["[j]"] != JP_LOW && job_preferences["[j]"] != JP_MEDIUM && job_preferences["[j]"] != JP_HIGH)
@@ -1032,10 +1044,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
all_quirks = SANITIZE_LIST(all_quirks)
vore_flags = sanitize_integer(vore_flags, 0, MAX_VORE_FLAG, 0)
vore_taste = copytext(vore_taste, 1, MAX_TASTE_LEN)
vore_smell = copytext(vore_smell, 1, MAX_TASTE_LEN)
belly_prefs = SANITIZE_LIST(belly_prefs)
vore_flags = sanitize_integer(vore_flags, 0, MAX_VORE_FLAG, 0)
vore_taste = copytext(vore_taste, 1, MAX_TASTE_LEN)
vore_smell = copytext(vore_smell, 1, MAX_TASTE_LEN)
belly_prefs = SANITIZE_LIST(belly_prefs)
cit_character_pref_load(S)
@@ -1091,6 +1103,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["custom_speech_verb"] , custom_speech_verb)
WRITE_FILE(S["custom_tongue"] , custom_tongue)
WRITE_FILE(S["additional_language"] , additional_language)
WRITE_FILE(S["bark_id"] , bark_id)
WRITE_FILE(S["bark_speed"] , bark_speed)
WRITE_FILE(S["bark_pitch"] , bark_pitch)
WRITE_FILE(S["bark_variance"] , bark_variance)
// records
WRITE_FILE(S["security_records"] , security_records)
@@ -227,6 +227,17 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggleprayersounds)()
return C.prefs.toggles & SOUND_PRAYERS
TOGGLE_CHECKBOX(/datum/verbs/menu/Settings/Sound, toggle_bark)()
set name = "Hear/Silence Vocal Barks"
set category = "Preferences"
set desc = "Hear Vocal Barks"
usr.client.prefs.toggles ^= SOUND_BARK
usr.client.prefs.save_preferences()
to_chat(usr, "You will now [(usr.client.prefs.toggles & SOUND_BARK) ? "hear" : "no longer hear"] vocal barks when other people talk.")
SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Vocal Barks", "[usr.client.prefs.toggles & SOUND_BARK ? "Enabled" : "Disabled"]"))
/datum/verbs/menu/Settings/Sound/toggle_bark/Get_checked(client/C)
return C.prefs.toggles & SOUND_BARK
/datum/verbs/menu/Settings/Sound/verb/stop_client_sounds()
set name = "Stop Sounds"
set category = "Preferences"
+1 -1
View File
@@ -32,7 +32,7 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color())
. += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
/obj/item/clothing/gloves/update_clothes_damaged_state()
..()
@@ -360,3 +360,12 @@
desc = "Thin, pretty gloves intended for use in sexy feminine attire. A tag on the hem claims they pair great with black stockings."
icon_state = "eveningblack"
item_state = "eveningblack"
/obj/item/clothing/gloves/polymaid
name = "polychromic maid gloves"
desc = "Colourable maid gloves!"
icon_state = "maid_arms"
/obj/item/clothing/gloves/polymaid/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#333333", "#FFFFFF"), 2)
+1 -1
View File
@@ -55,7 +55,7 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color())
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
/obj/item/clothing/head/update_clothes_damaged_state()
..()
+9
View File
@@ -477,6 +477,15 @@
item_state = "maid"
dynamic_hair_suffix = ""
/obj/item/clothing/head/maid/polychromic
name = "polychromic maid headband"
icon_state = "polymaid"
item_state = "polymaid"
/obj/item/clothing/head/maid/polychromic/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#333333", "#FFFFFF"), 2)
/obj/item/clothing/head/widered
name = "Wide red hat"
desc = "It is both wide, and red. Stylish!"
+1 -1
View File
@@ -36,7 +36,7 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
/obj/item/clothing/mask/update_clothes_damaged_state()
..()
@@ -113,6 +113,50 @@
to_chat(user, "<span class='notice'>Your Joy mask now has a [choice] Emotion!</span>")
return 1
/obj/item/clothing/mask/kitsuneblk
name = "Black Kitsune Mask"
desc = "An oriental styled porcelain mask, this one is black and gold."
icon_state = "blackkitsunemask"
item_state = "blackkitsunemask"
w_class = WEIGHT_CLASS_TINY
flags_cover = MASKCOVERSMOUTH
flags_inv = HIDEFACE|HIDEFACIALHAIR
visor_flags_inv = HIDEFACE|HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
slot_flags = ITEM_SLOT_MASK
/obj/item/clothing/mask/kitsuneblk/attack_self(mob/user)
adjustmask(user)
/obj/item/clothing/mask/kitsuneblk/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
adjustmask(user)
return TRUE
/obj/item/clothing/mask/kitsunewhi
name = "White Kitsune Mask"
desc = "An oriental styled porcelain mask, this one is white and red."
icon_state = "whitekitsunemask"
item_state = "whitekitsunemask"
w_class = WEIGHT_CLASS_TINY
flags_cover = MASKCOVERSMOUTH
flags_inv = HIDEFACE|HIDEFACIALHAIR
visor_flags_inv = HIDEFACE|HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
slot_flags = ITEM_SLOT_MASK
/obj/item/clothing/mask/kitsunewhi/attack_self(mob/user)
adjustmask(user)
/obj/item/clothing/mask/kitsunewhi/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
adjustmask(user)
return TRUE
/obj/item/clothing/mask/pig
name = "pig mask"
desc = "A rubber pig mask with a builtin voice modulator."
+10 -1
View File
@@ -13,7 +13,7 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color())
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
/obj/item/clothing/neck/tie
name = "tie"
@@ -259,6 +259,15 @@
name = "Collar Key"
desc = "A key for a tiny lock on a collar or bag."
/obj/item/clothing/neck/maid
name = "polychromic maid collar"
desc = "A collar that goes with the polychromic maid outfit."
icon_state = "maid_neck"
/obj/item/clothing/neck/maid/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#333333", "#FFFFFF"), 2)
//////////////
//DOPE BLING//
//////////////
+3 -1
View File
@@ -19,6 +19,7 @@
var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans
var/last_blood_DNA = "" //same as last one
var/last_blood_color = ""
var/last_blood_blend = null
///Whether these shoes have laces that can be tied/untied
var/can_be_tied = TRUE
@@ -68,6 +69,7 @@
last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works
last_blood_DNA = blood_dna[blood_dna.len]
last_blood_color = blood_dna["color"]
last_blood_blend = blood_dna["blendmode"]
/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
@@ -82,7 +84,7 @@
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
if(bloody)
var/file2use = style_flags & STYLE_DIGITIGRADE ? 'icons/mob/clothing/feet_digi.dmi' : 'icons/effects/blood.dmi'
. += mutable_appearance(file2use, "shoeblood", color = blood_DNA_to_color())
. += mutable_appearance(file2use, "shoeblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
/obj/item/clothing/shoes/equipped(mob/user, slot)
. = ..()
@@ -213,6 +213,7 @@
heat_protection = FEET|LEGS
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF
lace_time = 10 SECONDS
/obj/item/clothing/shoes/cult
name = "\improper Nar'Sien invoker boots"
+2 -2
View File
@@ -20,14 +20,14 @@
. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
if(blood_DNA)
var/file2use = (style_flags & STYLE_ALL_TAURIC) ? 'modular_citadel/icons/mob/64x32_effects.dmi' : 'icons/effects/blood.dmi'
. += mutable_appearance(file2use, "[blood_overlay_type]blood", color = blood_DNA_to_color())
. += mutable_appearance(file2use, "[blood_overlay_type]blood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
var/mob/living/carbon/human/M = loc
if(ishuman(M) && M.w_uniform)
var/obj/item/clothing/under/U = M.w_uniform
if(istype(U) && U.attached_accessory)
var/obj/item/clothing/accessory/A = U.attached_accessory
if(A.above_suit)
. += U.accessory_overlay
. += U.accessory_overlays
/obj/item/clothing/suit/update_clothes_damaged_state()
..()
+17
View File
@@ -84,6 +84,23 @@
"Cloak" = "trenchcloak"
)
/obj/item/clothing/suit/armor/hos/platecarrier
name = "plate carrier"
desc = "An armor vest with attached pockets for holding and sorting equipment or ammo."
icon_state = "platecarrier"
item_state = "platecarrier"
body_parts_covered = CHEST|GROIN|ARMS
armor = list (MELEE = 30, BULLET = 40, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, WOUND = 10)
cold_protection = CHEST|ARMS
heat_protection = CHEST|ARMS
strip_delay = 80
mutantrace_variation = STYLE_DIGITIGRADE
/obj/item/clothing/suit/armor/hos/platecarrier/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/storage = AddComponent(/datum/component/storage/concrete)
storage.max_items = 5
/obj/item/clothing/suit/armor/vest/warden
name = "warden's jacket"
desc = "A navy-blue armored jacket with blue shoulder designations and '/Warden/' stitched into one of the chest pockets."
+13 -7
View File
@@ -20,7 +20,7 @@
var/alt_covers_chest = FALSE // for adjusted/rolled-down jumpsuits, FALSE = exposes chest and arms, TRUE = exposes arms only
var/dummy_thick = FALSE // is able to hold accessories on its item
var/obj/item/clothing/accessory/attached_accessory
var/mutable_appearance/accessory_overlay
var/list/accessory_overlays
/obj/item/clothing/under/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
@@ -29,9 +29,9 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
if(blood_DNA)
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color())
if(accessory_overlay)
. += accessory_overlay
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
if(length(accessory_overlays))
. += accessory_overlays
/obj/item/clothing/under/attackby(obj/item/I, mob/user, params)
if((sensordamage || (has_sensor < HAS_SENSORS && has_sensor != NO_SENSORS)) && istype(I, /obj/item/stack/cable_coil))
@@ -154,9 +154,15 @@
if((flags_inv & HIDEACCESSORY) || (A.flags_inv & HIDEACCESSORY))
return TRUE
accessory_overlay = mutable_appearance('icons/mob/clothing/accessories.dmi', attached_accessory.icon_state)
accessory_overlay.alpha = attached_accessory.alpha
accessory_overlay.color = attached_accessory.color
var/datum/element/polychromic/polychromic = LAZYACCESS(attached_accessory.comp_lookup, "item_worn_overlays")
if(!polychromic)
var/mutable_appearance/accessory_overlay = mutable_appearance('icons/mob/clothing/accessories.dmi', attached_accessory.icon_state)
accessory_overlay.alpha = attached_accessory.alpha
accessory_overlay.color = attached_accessory.color
accessory_overlays = list(accessory_overlay)
else
accessory_overlays = list()
polychromic.apply_worn_overlays(I, FALSE, 'icons/mob/clothing/accessories.dmi', I.item_state || I.icon_state, NONE, accessory_overlays)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
+10 -1
View File
@@ -57,7 +57,7 @@
plane = initial(plane)
U.cut_overlays()
U.attached_accessory = null
U.accessory_overlay = null
U.accessory_overlays = null
/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
return
@@ -255,6 +255,15 @@
item_state = "maidapron"
minimize_when_attached = FALSE
/obj/item/clothing/accessory/maidapron/polychromic
name = "polychromic maid apron"
icon_state = "polymaidapron"
item_state = "polymaidapron"
/obj/item/clothing/accessory/maidapron/polychromic/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#333333", "#FFFFFF"), 2)
/obj/item/clothing/accessory/sleevecrop
name = "one sleeved crop top"
desc = "Off the shoulder crop top, for those nights out partying."
-1
View File
@@ -2,7 +2,6 @@
name = "Anomaly: Hyper-Energetic Flux"
typepath = /datum/round_event/anomaly/anomaly_flux
min_players = 10
max_occurrences = 5
weight = 20
+1
View File
@@ -2,6 +2,7 @@
name = "Anomaly: Pyroclastic"
typepath = /datum/round_event/anomaly/anomaly_pyro
min_players = 5
max_occurrences = 5
weight = 20
+4 -4
View File
@@ -1,13 +1,13 @@
/datum/round_event_control/atmos_flux
name = "Atmospheric Flux"
typepath = /datum/round_event/atmos_flux
max_occurrences = 1
weight = 5
endWhen = 600
var/original_speed
max_occurrences = 5
weight = 10
/datum/round_event/atmos_flux
announceWhen = 1
endWhen = 600
var/original_speed
/datum/round_event/atmos_flux/announce(fake)
priority_announce("Atmospheric flux in your sector detected. Sensors show that air may move [(SSair.share_max_steps_target > original_speed) ? "faster" : "slower"] than usual for some time.", "Atmos Alert")
+2 -1
View File
@@ -5,7 +5,8 @@
min_players = 5
/datum/round_event_control/brain_trauma/canSpawnEvent(var/players_amt, var/gamemode)
var/list/enemy_roles = list("Medical Doctor","Chief Medical Officer","Paramedic")
if(!..()) return FALSE
var/list/enemy_roles = list("Medical Doctor","Chief Medical Officer","Paramedic","AI","Chemist","Virologist","Captain","Head of Personnel","Roboticist")
for (var/mob/M in GLOB.alive_mob_list)
if(M.stat != DEAD && (M.mind?.assigned_role in enemy_roles))
return TRUE
+1 -1
View File
@@ -2,7 +2,7 @@
name = "Cat Surgeon"
typepath = /datum/round_event/cat_surgeon
max_occurrences = 1
weight = 8
weight = 5
/datum/round_event/cat_surgeon/announce(fake)
priority_announce("One of our... ahem... 'special' cases has escaped. As it happens their last known location before their tracker went dead is your station so keep an eye out for them. On an unrelated note, has anyone seen our cats?",
+12 -2
View File
@@ -2,7 +2,7 @@
name = "Disease Outbreak"
typepath = /datum/round_event/disease_outbreak
max_occurrences = 1
min_players = 10
min_players = 3
weight = 5
/datum/round_event/disease_outbreak
@@ -12,6 +12,13 @@
var/max_severity = 3
/datum/round_event_control/disease_outbreak/canSpawnEvent(var/players_amt, var/gamemode)
if(!..()) return FALSE
var/list/enemy_roles = list("Medical Doctor","Chief Medical Officer","Paramedic","AI","Chemist","Virologist","Captain","Head of Personnel", "Geneticist")
for (var/mob/M in GLOB.alive_mob_list)
if(M.stat != DEAD && (M.mind?.assigned_role in enemy_roles))
return TRUE
return FALSE
/datum/round_event/disease_outbreak/announce(fake)
priority_announce("Confirmed outbreak of level 7 viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", "outbreak7")
@@ -22,7 +29,10 @@
/datum/round_event/disease_outbreak/start()
var/advanced_virus = FALSE
max_severity = 3 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes
var/player_count = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE)
max_severity = 1 + max(FLOOR((world.time - control.earliest_start)/6000, 1),0) //3 symptoms at 20 minutes, plus 1 per 10 minutes
max_severity += player_count > 5
max_severity += player_count > 10
if(prob(20 + (10 * max_severity)))
advanced_virus = TRUE
+4 -3
View File
@@ -17,9 +17,10 @@
/datum/round_event_control/sandstorm
name = "Sandstorm"
typepath = /datum/round_event/sandstorm
weight = 0
max_occurrences = 0
earliest_start = 0 MINUTES
weight = 5
max_occurrences = 1
min_players = 5
earliest_start = 20 MINUTES
/datum/round_event/sandstorm
startWhen = 1
+10 -2
View File
@@ -1,9 +1,17 @@
/datum/round_event_control/heart_attack
name = "Random Heart Attack"
typepath = /datum/round_event/heart_attack
weight = 20
weight = 10
max_occurrences = 2
min_players = 40 // To avoid shafting lowpop
min_players = 10 // To avoid shafting lowpop
/datum/round_event_control/heart_attack/canSpawnEvent(var/players_amt, var/gamemode)
if(!..()) return FALSE
var/list/enemy_roles = list("Medical Doctor","Chief Medical Officer","Paramedic","Chemist")
for (var/mob/M in GLOB.alive_mob_list)
if(M.stat != DEAD && (M.mind?.assigned_role in enemy_roles))
return TRUE
return FALSE
/datum/round_event/heart_attack/start()
var/list/heart_attack_contestants = list()
+3 -3
View File
@@ -15,9 +15,9 @@
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/Ian in GLOB.mob_living_list)
Ian.place_on_head(new /obj/item/bedsheet(Ian))
for(var/mob/living/simple_animal/parrot/Poly/Poly in GLOB.mob_living_list)
new /mob/living/simple_animal/parrot/Poly/ghost(Poly.loc)
qdel(Poly)
for(var/mob/living/simple_animal/parrot/Polly/Polly in GLOB.mob_living_list)
new /mob/living/simple_animal/parrot/Polly/ghost(Polly.loc)
qdel(Polly)
/datum/round_event/spooky/announce(fake)
+1 -1
View File
@@ -2,7 +2,7 @@
name = "Mass Hallucination"
typepath = /datum/round_event/mass_hallucination
weight = 10
max_occurrences = 2
max_occurrences = 5
min_players = 1
var/forced_hallucination
+2 -2
View File
@@ -2,7 +2,7 @@
name = "Supermatter Surge"
typepath = /datum/round_event/supermatter_surge
weight = 20
max_occurrences = 4
max_occurrences = 5
earliest_start = 10 MINUTES
/datum/round_event_control/supermatter_surge/canSpawnEvent()
@@ -37,7 +37,7 @@
/datum/round_event/supermatter_surge/start()
var/obj/machinery/power/supermatter_crystal/supermatter = GLOB.main_supermatter_engine
var/power_proportion = supermatter.powerloss_inhibitor/2 // what % of the power goes into matter power, at most 50%
var/power_proportion = supermatter.powerloss_inhibitor * 0.75 // what % of the power goes into matter power, at most 50%
// we reduce the proportion that goes into actual matter power based on powerloss inhibitor
// primarily so the supermatter doesn't tesla the instant these happen
supermatter.matter_power += power * power_proportion
+2 -2
View File
@@ -1,8 +1,8 @@
/datum/round_event_control/supernova
name = "Supernova"
typepath = /datum/round_event/supernova
weight = 10
max_occurrences = 2
weight = 5
max_occurrences = 1
min_players = 2
/datum/round_event/supernova
+31
View File
@@ -0,0 +1,31 @@
/datum/round_event_control/untied_shoes
name = "Untied Shoes"
typepath = /datum/round_event/untied_shoes
weight = 100
max_occurrences = 20
alert_observers = FALSE
/datum/round_event/untied_shoes
fakeable = FALSE
/datum/round_event/untied_shoes/start()
var/budget = rand(5 SECONDS,20 SECONDS)
for(var/mob/living/carbon/C in shuffle(GLOB.alive_mob_list))
if(!C.client)
continue
if(C.stat == DEAD)
continue
if (HAS_TRAIT(C,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
if(!C.shoes || !C.shoes.can_be_tied || C.shoes.tied != SHOES_TIED || C.shoes.lace_time > budget)
continue
if(!is_station_level(C.z) && prob(50))
continue
if(prob(5))
C.shoes.adjust_laces(SHOES_KNOTTED)
budget -= C.shoes.lace_time // doubling up on the budget removal on purpose
else
C.shoes.adjust_laces(SHOES_UNTIED)
budget -= C.shoes.lace_time
if(budget < 5 SECONDS)
return
+4 -5
View File
@@ -3,7 +3,6 @@
typepath = /datum/round_event/vent_clog
weight = 10
max_occurrences = 3
min_players = 25
/datum/round_event/vent_clog
announceWhen = 1
@@ -11,7 +10,7 @@
endWhen = 35
var/interval = 2
var/list/vents = list()
var/randomProbability = 1
var/randomProbability = 0
var/reagentsAmount = 100
var/list/saferChems = list(
/datum/reagent/water,
@@ -92,7 +91,7 @@
var/datum/reagents/R = new/datum/reagents(1000)
R.my_atom = vent
if (prob(randomProbability))
if (randomProbability && prob(randomProbability))
R.add_reagent(get_random_reagent_id(), reagentsAmount)
else
R.add_reagent(pick(saferChems), reagentsAmount)
@@ -106,7 +105,7 @@
name = "Clogged Vents: Threatening"
typepath = /datum/round_event/vent_clog/threatening
weight = 4
min_players = 35
min_players = 15
max_occurrences = 1
earliest_start = 35 MINUTES
@@ -118,7 +117,7 @@
name = "Clogged Vents: Catastrophic"
typepath = /datum/round_event/vent_clog/catastrophic
weight = 2
min_players = 45
min_players = 25
max_occurrences = 1
earliest_start = 45 MINUTES
+11 -3
View File
@@ -311,6 +311,7 @@
/obj/item/reagent_containers/food/snacks/pizza/donkpocket = 0.3,
/obj/item/reagent_containers/food/snacks/pizza/dank = 0.1) //pizzas here are weighted by chance to be someone's favorite
var/static/list/pizza_preferences
COOLDOWN_DECLARE(next_pizza_attunement)
/obj/item/pizzabox/infinite/Initialize(mapload)
. = ..()
@@ -323,11 +324,18 @@
. += "<span class='deadsay'>This pizza box is anomalous, and will produce infinite pizza.</span>"
/obj/item/pizzabox/infinite/attack_self(mob/living/user)
QDEL_NULL(pizza)
if(ishuman(user))
attune_pizza(user)
if(COOLDOWN_FINISHED(src, next_pizza_attunement))
QDEL_NULL(pizza)
if(ishuman(user))
attune_pizza(user)
. = ..()
/obj/item/pizzabox/infinite/on_attack_hand(mob/user, act_intent, unarmed_attack_flags)
var/had_pizza = (pizza ? TRUE : FALSE)
. = ..()
if(had_pizza && !pizza)
COOLDOWN_START(src, next_pizza_attunement, (3 SECONDS))
/obj/item/pizzabox/infinite/proc/attune_pizza(mob/living/carbon/human/noms) //tonight on "proc names I never thought I'd type"
if(!pizza_preferences[noms.ckey])
pizza_preferences[noms.ckey] = pickweight(pizza_types)
@@ -771,8 +771,8 @@
/datum/chemical_reaction/pinkmilk
name = "Strawberry Milk"
id = /datum/reagent/consumable/pinkmilk
results = list(/datum/reagent/consumable/pinkmilk = 2)
id = /datum/reagent/consumable/milk/pinkmilk
results = list(/datum/reagent/consumable/milk/pinkmilk = 2)
required_reagents = list(/datum/reagent/consumable/strawberryjuice = 1, /datum/reagent/consumable/milk = 1)
mix_message = "You feel a sweet aroma drift up your nose as the lactic mixture swirls. It reminds you of... a cafeteria."
@@ -1016,8 +1016,8 @@
/datum/chemical_reaction/pinktea
name = "Strawberry Tea"
id = /datum/reagent/consumable/pinktea
results = list(/datum/reagent/consumable/pinktea = 5)
id = /datum/reagent/consumable/tea/pinktea
results = list(/datum/reagent/consumable/tea/pinktea = 5)
required_reagents = list(/datum/reagent/consumable/strawberryjuice = 1, /datum/reagent/consumable/tea/arnold_palmer = 1, /datum/reagent/consumable/sugar = 1)
/datum/chemical_reaction/catnip_tea
+1 -2
View File
@@ -6,5 +6,4 @@
return lowertext(ddd) in days
/datum/holiday/dynamic/celebrate()
GLOB.dynamic_forced_threat_level = rand(90, 100)
CONFIG_SET(string/force_gamemode, "dynamic") // prevents the round vote, which prevents extended
GLOB.dynamic_forced_threat_level = rand(50, 100)
+1 -1
View File
@@ -70,7 +70,7 @@
. = ..()
AddComponent(/datum/component/stationloving)
/mob/living/simple_animal/jacq/BiologicalLife(seconds, times_fired)
/mob/living/simple_animal/jacq/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
if(!ckey)
+10 -2
View File
@@ -11,8 +11,8 @@
growthstages = 1
instability = 40
growing_icon = 'goon/icons/obj/hydroponics.dmi'
icon_grow = "cannabis-grow" // Uses one growth icons set for all the subtypes
icon_dead = "cannabis-dead" // Same for the dead icon
icon_grow = "cannabis-grow"
icon_dead = "cannabis-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/cannabis/rainbow,
/obj/item/seeds/cannabis/death)
@@ -26,6 +26,8 @@
species = "megacannabis"
plantname = "Rainbow Weed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow
icon_grow = "megacannabis-grow"
icon_dead = "megacannabis-dead"
mutatelist = list(/obj/item/seeds/cannabis/ultimate)
reagents_add = list(/datum/reagent/toxin/mindbreaker = 0.15, /datum/reagent/toxin/lipolicide = 0.35)
rarity = 40
@@ -37,6 +39,8 @@
species = "blackcannabis"
plantname = "Deathweed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/death
icon_grow = "blackcannabis-grow"
icon_dead = "blackcannabis-dead"
mutatelist = list(/obj/item/seeds/cannabis/white)
reagents_add = list(/datum/reagent/toxin/cyanide = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15)
rarity = 40
@@ -48,6 +52,8 @@
species = "whitecannabis"
plantname = "Lifeweed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/white
icon_grow = "whitecannabis-grow"
icon_dead = "whitecannabis-dead"
mutatelist = list()
reagents_add = list(/datum/reagent/medicine/omnizine = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15)
rarity = 40
@@ -60,6 +66,8 @@
species = "ocannabis"
plantname = "Omega Weed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/ultimate
icon_grow = "ocannabis-grow"
icon_dead = "ocannabis-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/green)
mutatelist = list()
reagents_add = list(/datum/reagent/drug/space_drugs = 0.3,
+2 -2
View File
@@ -9,7 +9,7 @@
var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item.
var/tastes = list("indescribable" = 1) //Stops runtimes. Grown are un-eatable anyways so if you do then its a bug
/obj/item/grown/Initialize(mapload, newloc, obj/item/seeds/new_seed)
/obj/item/grown/Initialize(mapload, obj/item/seeds/new_seed)
. = ..()
create_reagents(50, NONE, HARVEST_REAGENTS_VALUE)
@@ -25,7 +25,7 @@
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
T.on_new(src, newloc)
T.on_new(src, loc)
if(istype(src, seed.product)) // no adding reagents if it is just a trash item
seed.prepare_result(src)
+76 -27
View File
@@ -47,21 +47,43 @@
var/meta_color = area_to_color[A]
if(!meta_color)
meta_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
var/meta_x = LAZYLEN(area_to_color) + 1
var/meta_y = (((meta_x + 1) - ((meta_x + 1) % 255)) / 255)
var/meta_z = (((meta_y + 1) - ((meta_y + 1) % 255)) / 255)
meta_color = rgb(meta_x % 255, meta_y % 255, meta_z % 255) //This supports exactly 16,581,374 areas with no conflicts whatsoever before it just gives up
area_to_color[A] = meta_color
color_area_names[meta_color] = A.name
meta_icon.DrawBox(meta_color, img_x, img_y)
if(istype(T, /turf/closed/wall))
if(A.minimap_show_walls && istype(T, /turf/closed/wall))
map_icon.DrawBox("#000000", img_x, img_y)
else if(!istype(A, /area/space))
var/color = A.minimap_color || "#FF00FF"
if(locate(/obj/machinery/power/solar) in T)
color = "#02026a"
var/color = (A.minimap_color2 ? (((img_x + img_y) % 2) ? A.minimap_color2 : A.minimap_color ) : A.minimap_color) || "#FF00FF"
if(A.minimap_show_walls)
var/overridden
for(var/obj/structure/O in T)
if(O.minimap_override_color)
color = O.minimap_override_color
overridden = TRUE
break
else if(O.density && O.anchored)
color = BlendRGB(color, "#000000", 0.5)
overridden = TRUE
break
//In an ideal world, we'd be able to get away with just doing for(var/obj/O in T) up there, and calling it a day. However. HOWEVER!
//Doing that causes the code to also loop through items. and that uh. Kinda bloats minimap gen time. A LOT. We're talking straight-up doubling the time it takes to gen.
//So instead we take our ctrl+c. We copy the above code. And we ctrl+v. It's awful. We hate it. But it works. It's faster. Funny mapgen go vroom
if(!overridden)
for(var/obj/machinery/O in T)
if(O.minimap_override_color)
color = O.minimap_override_color
break
else if(O.density && O.anchored)
color = BlendRGB(color, "#000000", 0.25)
break
if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T))
color = BlendRGB(color, "#000000", 0.5)
map_icon.DrawBox(color, img_x, img_y)
map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
@@ -102,22 +124,48 @@
var/list/datas = list()
var/list/info = list()
for(var/i in 1 to length(minimaps))// OLD: for(var/i in 1 to length(minimaps))
var/buttonfield = ""
var/totalmaps = length(minimaps)
for(var/i in 1 to totalmaps)// OLD: for(var/i in 1 to length(minimaps))
var/datum/minimap/M = minimaps[i]
var/map_name = "minimap-[M.id].png"
var/meta_name = "minimap-[M.id]-meta.png"
M.send(user)
info += {"
<div class="block">
<div class="block" id='layer-[i]' [i == 1 ? "" : "style='display:none'"]>
[totalmaps > 1 ? "<h3>Layer [i]</h3>" : ""]
<div> <!-- The div is in here to fit it both in the block div -->
<img id='map-[i]' src='[SSassets.transport.get_asset_url(map_name)]' />
<img id='map-[i]-meta' src='[SSassets.transport.get_asset_url(meta_name)]' style='display: none' />
</div>
<div class="statusDisplay" id='label-[i]'></div>
[totalmaps <= 1 ? "<div class='statusDisplay' id='label-[i]'> </div>" : ""]
</div>
"}
datas += json_encode(M.color_area_names);
buttonfield += "<a onclick='switchmap(\"layer-[i]\")'>Layer [i]</a> "
if(totalmaps > 1)
info += "<div class='block'><div class='statusDisplay'>[buttonfield]</div></div>"
//This is a hacky workaround; the status display is extremely buggy when multiple z-levels are present. We couldn't figure out how to fix this after 7 hours of banging our head against the wall
//We're coder
var/mousemove_bit = {"
canvas.onmousemove = function(e){
var rect = canvas.getBoundingClientRect();
var x = Math.floor(e.offsetX * img.width / rect.width);
var y = Math.floor(e.offsetY * img.height / rect.height);
var color_idx = x * 4 + (y * 4 * imagedata.width);
var color = "#" + hexify(imagedata.data\[color_idx]) + hexify(imagedata.data\[color_idx+1]) + hexify(imagedata.data\[color_idx+2]);
label.textContent = data\[color];
canvas.title = data\[color];
}
canvas.onmouseout = function(e){
label.textContent = " ";
canvas.title = "";
}
"}
info = info.Join()
//this is bad. Too bad!
@@ -133,6 +181,14 @@
}
return num;
}
function switchmap(mapid) {
var targetblock = document.getElementById(mapid);
for(var i = 0; i < [length(minimaps)]; i++) {
var currentblock = document.getElementById("layer-" + (i + 1));
currentblock.style.display = 'none';
}
targetblock.style.display = '';
}
window.onload = function() {
if(!window.HTMLCanvasElement) {
var label = document.getElementById("label-1");
@@ -150,6 +206,7 @@
var canvas = document.createElement("canvas");
canvas.width = img.width * 2;
canvas.height = img.height * 2;
canvas.id = "canvas-" + (i+1);
var ctx = canvas.getContext('2d');
ctx.msImageSmoothingEnabled = false;
@@ -158,31 +215,23 @@
ctx = document.createElement("canvas").getContext('2d');
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
ctx.id = "ctx-" + (i+1);
ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0);
var imagedata = ctx.getImageData(0, 0, img.width, img.height);
canvas.onmousemove = function(e){
var rect = canvas.getBoundingClientRect();
var x = Math.floor(e.offsetX * img.width / rect.width);
var y = Math.floor(e.offsetY * img.height / rect.height);
var color_idx = x * 4 + (y * 4 * imagedata.width);
var color = "#" + hexify(imagedata.data\[color_idx]) + hexify(imagedata.data\[color_idx+1]) + hexify(imagedata.data\[color_idx+2]);
var label = document.getElementById("label-" + (i+1)); //label-String(n)
label.textContent = data\[color];
canvas.title = data\[color];
}
canvas.onmouseout = function(e){
canvas.title = "";
}
var label = document.getElementById("label-" + (i+1)); //label-String(n);
[totalmaps <= 1 ? mousemove_bit : ""]
}
}
</script>
<style>
img, canvas {
width: 100%;
max-width: 100%;
width: auto;
margin: auto;
display: flex;
justify-content: center;
background-color: white;
}
</style>
@@ -19,6 +19,7 @@
attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped")
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/toggle_light)
obj_flags = UNIQUE_RENAME
var/list/trophies = list()
var/charged = TRUE
var/charge_time = 15
+14 -1
View File
@@ -9,6 +9,12 @@
..()
if(!age_verify())
return
if(!client) //client can end up null as a result of age_verify() kicking those who fail
return
var/motd = global.config.motd
if(motd)
to_chat(src, "<div class=\"motd\">[motd]</div>", handle_whitespace=FALSE)
@@ -22,8 +28,11 @@
sight |= SEE_TURFS
new_player_panel()
client.playtitlemusic()
var/datum/asset/asset_datum = get_asset_datum(/datum/asset/simple/lobby)
asset_datum.send(client)
if(SSticker.current_state < GAME_STATE_SETTING_UP)
var/tl = SSticker.GetTimeLeft()
var/postfix
@@ -32,3 +41,7 @@
else
postfix = "soon"
to_chat(src, "Please set up your character and select \"Ready\". The game will start [postfix].")
var/datum/hud/new_player/NH = hud_used
if(istype(NH))
NH.populate_buttons(src)
+26 -123
View File
@@ -1,5 +1,3 @@
#define LINKIFY_READY(string, value) "<a href='byond://?src=[REF(src)];ready=[value]'>[string]</a>"
/mob/dead/new_player
var/ready = 0
var/spawning = 0//Referenced when you want to delete the new_player later on in the code.
@@ -10,6 +8,8 @@
density = FALSE
stat = DEAD
hud_type = /datum/hud/new_player
hud_possible = list()
var/mob/living/new_character //for instant transfer once the round is set up
@@ -43,69 +43,6 @@
/mob/dead/new_player/prepare_huds()
return
/mob/dead/new_player/proc/new_player_panel()
var/output = "<center><p>Welcome, <b>[client ? client.prefs.real_name : "Unknown User"]</b></p>"
output += "<center><p><a href='byond://?src=[REF(src)];show_preferences=1'>Setup Character</a></p>"
if(SSticker.current_state <= GAME_STATE_PREGAME)
switch(ready)
if(PLAYER_NOT_READY)
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | <b>Not Ready</b> | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
if(PLAYER_READY_TO_PLAY)
output += "<p>\[ <b>Ready</b> | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
if(PLAYER_READY_TO_OBSERVE)
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | <b> Observe </b> \]</p>"
else
output += "<p><a href='byond://?src=[REF(src)];manifest=1'>View the Crew Manifest</a></p>"
output += "<p><a href='byond://?src=[REF(src)];late_join=1'>Join Game!</a></p>"
output += "<p>[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]</p>"
if(!IsGuestKey(src.key))
output += playerpolls()
output += "</center>"
//src << browse(output,"window=playersetup;size=210x240;can_close=0")
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 250, 265)
popup.set_window_options("can_close=0")
popup.set_content(output)
popup.open(FALSE)
/mob/dead/new_player/proc/playerpolls()
var/output = "" //hey tg why is this a list?
if (SSdbcore.Connect())
var/isadmin = FALSE
if(client?.holder)
isadmin = TRUE
var/datum/db_query/query_get_new_polls = SSdbcore.NewQuery({"
SELECT id FROM [format_table_name("poll_question")]
WHERE (adminonly = 0 OR :isadmin = 1)
AND Now() BETWEEN starttime AND endtime
AND deleted = 0
AND id NOT IN (
SELECT pollid FROM [format_table_name("poll_vote")]
WHERE ckey = :ckey
AND deleted = 0
)
AND id NOT IN (
SELECT pollid FROM [format_table_name("poll_textreply")]
WHERE ckey = :ckey
AND deleted = 0
)
"}, list("isadmin" = isadmin, "ckey" = ckey))
var/rs = REF(src)
if(!query_get_new_polls.Execute())
qdel(query_get_new_polls)
return
if(query_get_new_polls.NextRow())
output += "<p><b><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A> (NEW!)</b></p>"
else
output += "<p><a href='byond://?src=[rs];showpoll=1'>Show Player Polls</A></p>"
qdel(query_get_new_polls)
if(QDELETED(src))
return
return output
/mob/dead/new_player/proc/age_gate()
var/list/dat = list("<center>")
dat += "Enter your date of birth here, to confirm that you are over 18.<BR>"
@@ -152,6 +89,9 @@
if(!(client.prefs.db_flags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE)) //completed? Skip
return TRUE
if(!client)
return FALSE
var/age_verification = age_gate()
//ban them and kick them
if(age_verification != 1)
@@ -269,61 +209,12 @@
if(!age_verify())
return
//Determines Relevent Population Cap
var/relevant_cap
var/hpc = CONFIG_GET(number/hard_popcap)
var/epc = CONFIG_GET(number/extreme_popcap)
if(hpc && epc)
relevant_cap = min(hpc, epc)
else
relevant_cap = max(hpc, epc)
if(href_list["show_preferences"])
client.prefs.ShowChoices(src)
return 1
if(href_list["ready"])
var/tready = text2num(href_list["ready"])
//Avoid updating ready if we're after PREGAME (they should use latejoin instead)
//This is likely not an actual issue but I don't have time to prove that this
//no longer is required
if(SSticker.current_state <= GAME_STATE_PREGAME)
ready = tready
//if it's post initialisation and they're trying to observe we do the needful
if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE)
ready = tready
make_me_an_observer()
return
if(href_list["refresh"])
src << browse(null, "window=playersetup") //closes the player setup window
new_player_panel()
if(href_list["late_join"])
if(!SSticker || !SSticker.IsRoundInProgress())
to_chat(usr, "<span class='danger'>The round is either not ready, or has already finished...</span>")
return
if(href_list["late_join"] == "override")
LateChoices()
return
if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
to_chat(usr, "<span class='danger'>[CONFIG_GET(string/hard_popcap_message)]</span>")
var/queue_position = SSticker.queued_players.Find(usr)
if(queue_position == 1)
to_chat(usr, "<span class='notice'>You are next in line to join the game. You will be notified when a slot opens up.</span>")
else if(queue_position)
to_chat(usr, "<span class='notice'>There are [queue_position-1] players in front of you in the queue to join the game.</span>")
else
SSticker.queued_players += usr
to_chat(usr, "<span class='notice'>You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].</span>")
return
LateChoices()
if(href_list["manifest"])
ViewManifest()
return
if(href_list["SelectedJob"])
if(!SSticker || !SSticker.IsRoundInProgress())
@@ -337,6 +228,17 @@
to_chat(usr, "<span class='notice'>There is an administrative lock on entering the game!</span>")
return
//Determines Relevent Population Cap
var/relevant_cap
var/hpc = CONFIG_GET(number/hard_popcap)
var/epc = CONFIG_GET(number/extreme_popcap)
if(hpc && epc)
relevant_cap = min(hpc, epc)
else
relevant_cap = max(hpc, epc)
if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
to_chat(usr, "<span class='warning'>Server is full.</span>")
@@ -349,6 +251,15 @@
if(!GLOB.enter_allowed)
to_chat(usr, "<span class='notice'> There is an administrative lock on entering the game!</span>")
//Determines Relevent Population Cap
var/relevant_cap
var/hpc = CONFIG_GET(number/hard_popcap)
var/epc = CONFIG_GET(number/extreme_popcap)
if(hpc && epc)
relevant_cap = min(hpc, epc)
else
relevant_cap = max(hpc, epc)
if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums))
if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1]))
to_chat(usr, "<span class='warning'>Server is full.</span>")
@@ -360,13 +271,6 @@
SSticker.queue_delay = 4
qdel(src)
else if(!href_list["late_join"])
new_player_panel()
if(href_list["showpoll"])
handle_player_polling()
return
if(href_list["pollid"])
var/pollid = href_list["pollid"]
if(istext(pollid))
@@ -460,7 +364,6 @@
if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes")
ready = PLAYER_NOT_READY
src << browse(null, "window=playersetup") //closes the player setup window
new_player_panel()
return FALSE
var/mob/dead/observer/observer = new()
@@ -24,6 +24,9 @@
var/rando_race = pick(GLOB.roundstart_races)
pref_species = new rando_race()
features = random_features(pref_species?.id, gender)
bark_id = pick(GLOB.bark_random_list)
bark_pitch = BARK_PITCH_RAND(gender)
bark_variance = BARK_VARIANCE_RAND
age = rand(AGE_MIN,AGE_MAX)
/datum/preferences/proc/update_preview_icon(current_tab)
+5 -3
View File
@@ -121,7 +121,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
remove_verb(src, /mob/dead/observer/verb/boo)
remove_verb(src, /mob/dead/observer/verb/possess)
animate(src, pixel_y = 2, time = 10, loop = -1)
animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
add_to_dead_mob_list()
@@ -534,8 +535,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/stop_orbit(datum/component/orbiter/orbits)
. = ..()
//restart our floating animation after orbit is done.
pixel_y = 0
animate(src, pixel_y = 2, time = 10, loop = -1)
pixel_z = 0
animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
/mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
set category = "Ghost"
+53 -72
View File
@@ -30,7 +30,7 @@
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
/mob/living/carbon/human/handle_blood(delta_time, times_fired)
if(NOBLOOD in dna.species.species_traits || bleedsuppress || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
return
@@ -39,56 +39,57 @@
return
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
if(integrating_blood > 0)
var/blood_integrated = max(integrating_blood - 1, 0)
var/blood_diff = integrating_blood - blood_integrated
integrating_blood = blood_integrated
if(blood_volume < BLOOD_VOLUME_MAXIMUM)
blood_volume += blood_diff
if(blood_volume < BLOOD_VOLUME_NORMAL)
var/nutrition_ratio = 0
if(!HAS_TRAIT(src, TRAIT_NOHUNGER))
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
nutrition_ratio = 0.2
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
nutrition_ratio = 0.4
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
nutrition_ratio = 0.6
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
nutrition_ratio = 0.8
else
nutrition_ratio = 1
if(satiety > 80)
nutrition_ratio *= 1.25
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR)
blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
if(dna.species.handle_blood(src, delta_time, times_fired)) // if this returns TRUE, then the species is not handling blood itself and we can control everything
if(integrating_blood > 0)
var/blood_integrated = max(integrating_blood - 1, 0)
var/blood_diff = integrating_blood - blood_integrated
integrating_blood = blood_integrated
if(blood_volume < BLOOD_VOLUME_MAXIMUM)
blood_volume += blood_diff
if(blood_volume < BLOOD_VOLUME_NORMAL)
var/nutrition_ratio = 0
if(!HAS_TRAIT(src, TRAIT_NOHUNGER))
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
nutrition_ratio = 0.2
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
nutrition_ratio = 0.4
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
nutrition_ratio = 0.6
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
nutrition_ratio = 0.8
else
nutrition_ratio = 1
if(satiety > 80)
nutrition_ratio *= 1.25
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR)
blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
//Effects of bloodloss
if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) //Synths are immune to direct consequences of bloodloss, instead suffering penalties to heat exchange.
var/word = pick("dizzy","woozy","faint")
var/blood_effect_volume = blood_volume + integrating_blood
switch(blood_effect_volume)
if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS)
if(prob(10))
to_chat(src, "<span class='warning'>You feel terribly bloated.</span>")
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(5))
to_chat(src, "<span class='warning'>You feel [word].</span>")
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(prob(5))
blur_eyes(6)
to_chat(src, "<span class='warning'>You feel very [word].</span>")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
adjustOxyLoss(5)
if(prob(15))
Unconscious(rand(20,60))
to_chat(src, "<span class='warning'>You feel extremely [word].</span>")
if(-INFINITY to BLOOD_VOLUME_SURVIVE)
if(!HAS_TRAIT(src, TRAIT_NODEATH))
death()
//Effects of bloodloss
if(!HAS_TRAIT(src, TRAIT_ROBOTIC_ORGANISM)) //Synths are immune to direct consequences of bloodloss, instead suffering penalties to heat exchange.
var/word = pick("dizzy","woozy","faint")
var/blood_effect_volume = blood_volume + integrating_blood
switch(blood_effect_volume)
if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS)
if(prob(10))
to_chat(src, "<span class='warning'>You feel terribly bloated.</span>")
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(5))
to_chat(src, "<span class='warning'>You feel [word].</span>")
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(prob(5))
blur_eyes(6)
to_chat(src, "<span class='warning'>You feel very [word].</span>")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
adjustOxyLoss(5)
if(prob(15))
Unconscious(rand(20,60))
to_chat(src, "<span class='warning'>You feel extremely [word].</span>")
if(-INFINITY to BLOOD_VOLUME_SURVIVE)
if(!HAS_TRAIT(src, TRAIT_NODEATH))
death()
var/temp_bleed = 0
//Bleeding out
@@ -193,6 +194,7 @@
blood_data["blood_DNA"] = dna.unique_enzymes
blood_data["bloodcolor"] = dna.species.exotic_blood_color
blood_data["bloodblend"] = dna.species.exotic_blood_blend_mode
if(disease_resistances && disease_resistances.len)
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
@@ -264,7 +266,7 @@
"O-" = list("O-","SY"),
"O+" = list("O-", "O+","SY"),
"L" = list("L","SY"),
"U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U","SY"),
"U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U","SY", "BUG"),
"HF" = list("HF", "SY"),
"X*" = list("X*", "SY"),
"SY" = list("SY"),
@@ -370,27 +372,6 @@
if(!B)
B = new(T)
//This is a terrible way of handling it.
/mob/living/proc/ResetBloodVol()
if(ishuman(src))
var/mob/living/carbon/human/H = src
if (HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
blood_ratio = 1.2
H.handle_blood()
return
blood_ratio = 1
H.handle_blood()
return
blood_ratio = 1
/mob/living/proc/AdjustBloodVol(value)
if(blood_ratio == value)
return
blood_ratio = value
if(ishuman(src))
var/mob/living/carbon/human/H = src
H.handle_blood()
/mob/living/proc/adjust_integration_blood(value, remove_actual_blood, force)
if(integrating_blood + value < 0 && remove_actual_blood)
blood_volume += value + integrating_blood
+1 -1
View File
@@ -1,5 +1,5 @@
/mob/living/brain/BiologicalLife(seconds, times_fired)
/mob/living/brain/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
handle_emp_damage()
@@ -51,7 +51,7 @@
// update_icons() //Handled in update_transform(), leaving this here as a reminder
update_transform()
/mob/living/carbon/alien/humanoid/update_transform() //The old method of updating lying/standing was update_icons(). Aliens still expect that.
/mob/living/carbon/alien/humanoid/update_transform(do_animate) //The old method of updating lying/standing was update_icons(). Aliens still expect that.
if(lying > 0)
lying = 90 //Anything else looks silly
..()
@@ -1,4 +1,4 @@
/mob/living/carbon/alien/larva/BiologicalLife(seconds, times_fired)
/mob/living/carbon/alien/larva/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
// GROW!
@@ -21,7 +21,7 @@
else
icon_state = "larva[state]"
/mob/living/carbon/alien/larva/update_transform() //All this is handled in update_icons()
/mob/living/carbon/alien/larva/update_transform(do_animate) //All this is handled in update_icons()
..()
return update_icons()
+1 -1
View File
@@ -1,4 +1,4 @@
/mob/living/carbon/alien/BiologicalLife(seconds, times_fired)
/mob/living/carbon/alien/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
findQueen()
@@ -90,10 +90,12 @@
/mob/living/carbon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, toxins_type = TOX_DEFAULT)
if(!forced && HAS_TRAIT(src, TRAIT_TOXINLOVER) && toxins_type != TOX_SYSCORRUPT) //damage becomes healing and healing becomes damage
amount = -amount
// don't allow toxinlover to push blood levels past BLOOD_VOLUME_MAXIMUM, but also don't set it back down to this if it's higher from something else
var/blood_cap = blood_volume > BLOOD_VOLUME_MAXIMUM ? blood_volume : BLOOD_VOLUME_MAXIMUM
if(amount > 0)
blood_volume -= 3 * amount //5x was too much, this is punishing enough.
blood_volume = min((blood_volume - (3 * amount)), blood_cap) //5x was too much, this is punishing enough.
else
blood_volume -= amount
blood_volume = min((blood_volume - amount), blood_cap)
return ..()
/mob/living/carbon/getStaminaLoss()
+5 -2
View File
@@ -6,7 +6,7 @@
var/t_has = p_have()
var/t_is = p_are()
. = list("<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>!")
. = list("<span class='info'>This is [icon2html(src, user)] \a <EM>[src]</EM>!")
if (handcuffed)
. += "<span class='warning'>[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!</span>"
@@ -152,8 +152,11 @@
. += "[t_He] look[p_s()] very happy."
if(MOOD_LEVEL_HAPPY4 to INFINITY)
. += "[t_He] look[p_s()] ecstatic."
if(LAZYLEN(.) > 1)
.[2] = "<hr>[.[2]]"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
. += "*---------*</span>"
/mob/living/carbon/examine_more(mob/user)
if(!all_scars)
@@ -13,7 +13,7 @@
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
obscure_name = TRUE
. = list("<span class='info'>*---------*\nThis is <EM>[!obscure_name ? name : "Unknown"]</EM>!")
. = list("<span class='info'>This is <EM>[!obscure_name ? name : "Unknown"]</EM>!")
var/vampDesc = ReturnVampExamine(user) // Vamps recognize the names of other vamps.
var/vassDesc = ReturnVassalExamine(user) // Vassals recognize each other's marks.
@@ -442,9 +442,10 @@
else if(isobserver(user) && traitstring)
. += "<span class='info'><b>Traits:</b> [traitstring]</span>"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) //This also handles flavor texts now
if(LAZYLEN(.) > 2) //Want this to appear after species text
.[3] = "<hr>[.[3]]"
. += "*---------*</span>"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) //This also handles flavor texts now
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
var/list/dat = list()
@@ -550,7 +550,7 @@
to_chat(src, "<span class='notice'>You succesfuly remove the durathread strand.</span>")
remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
return
var/to_send = ""
var/to_send = "<blockquote class ='notice'>"
visible_message("[src] examines [p_them()]self.", \
"<span class='notice'>You check yourself for injuries.</span>")
@@ -597,27 +597,27 @@
var/no_damage
if(status == "OK" || status == "no damage")
no_damage = TRUE
to_send += "\t <span class='[no_damage ? "notice" : "warning"]'>Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].</span>\n"
to_send += "<span class='[no_damage ? "notice" : "warning"]'>Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].</span>\n"
for(var/thing in LB.wounds)
var/datum/wound/W = thing
var/msg
switch(W.severity)
if(WOUND_SEVERITY_TRIVIAL)
msg = "\t <span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>"
msg = "<span class='danger'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)].</span>"
if(WOUND_SEVERITY_MODERATE)
msg = "\t <span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>"
msg = "<span class='warning'>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</span>"
if(WOUND_SEVERITY_SEVERE)
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>"
msg = "<span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!</b></span>"
if(WOUND_SEVERITY_CRITICAL)
msg = "\t <span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>"
msg = "<span class='warning'><b>Your [LB.name] is suffering [W.a_or_from] [lowertext(W.name)]!!</b></span>"
to_chat(src, msg)
for(var/obj/item/I in LB.embedded_objects)
if(I.isEmbedHarmless())
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
to_chat(src, "<a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
else
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
to_chat(src, "<a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
for(var/t in missing)
to_send += "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>\n"
@@ -724,6 +724,8 @@
if(roundstart_quirks.len)
to_send += "<span class='notice'>You have these quirks: [get_trait_string()].</span>\n"
to_send += "</blockquote>"
to_chat(src, to_send)
else
if(wear_suit)
@@ -85,6 +85,7 @@
FP.blood_DNA["color"] = S.last_blood_color
else
FP.blood_DNA["color"] = BlendRGB(FP.blood_DNA["color"], S.last_blood_color)
FP.blood_DNA["blendmode"] = S.last_blood_blend
FP.update_icon()
update_inv_shoes()
//End bloody footprints
@@ -30,6 +30,10 @@
currently_coiled.pixel_x = 12
/datum/action/innate/ability/coiling/proc/coil_mob(var/mob/living/carbon/human/H)
if(currently_coiling)
to_chat(owner, span_warning("You are already coiling someone!"))
return
// begin the coiling action
H.visible_message("<span class='warning'>[owner] coils [H] with their tail!</span>", \
"<span class='userdanger'>[owner] coils you with their tail!</span>")
@@ -58,6 +62,9 @@
/datum/action/innate/ability/coiling/proc/cancel_coil()
var/mob/living/carbon/human/H = owner
if(!currently_coiling)
return
// cancel the coiling action by removing the overlay
currently_coiled.pixel_x = 0
@@ -25,25 +25,21 @@
/datum/action/innate/ability/limb_regrowth/Activate()
var/mob/living/carbon/human/H = owner
var/list/limbs_to_heal = H.get_missing_limbs()
if(limbs_to_heal.len < 1)
to_chat(H, "<span class='notice'>You feel intact enough as it is.</span>")
if(!length(limbs_to_heal))
to_chat(H, span_notice("You feel intact enough as it is."))
return
to_chat(H, "<span class='notice'>You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...</span>")
var/mode = H.get_ability_property(INNATE_ABILITY_LIMB_REGROWTH, PROPERTY_LIMB_REGROWTH_USAGE_TYPE)
switch(mode)
if(REGROWTH_USES_BLOOD)
if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
H.regenerate_limbs()
H.blood_volume -= 40*limbs_to_heal.len
to_chat(H, "<span class='notice'>...and after a moment you finish reforming!</span>")
return
else if(H.blood_volume >= 40)//We can partially heal some limbs
while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
var/healed_limb = pick(limbs_to_heal)
H.regenerate_limb(healed_limb)
limbs_to_heal -= healed_limb
H.blood_volume -= 40
to_chat(H, "<span class='warning'>...but there is not enough of you to fix everything! You must attain more mass to heal completely!</span>")
return
to_chat(H, "<span class='warning'>...but there is not enough of you to go around! You must attain more mass to heal!</span>")
to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]..."))
if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY)
H.regenerate_limbs()
H.blood_volume -= 40*length(limbs_to_heal)
to_chat(H, span_notice("...and after a moment you finish reforming!"))
return
else if(H.blood_volume >= 40)//We can partially heal some limbs
while(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
var/healed_limb = pick(limbs_to_heal)
H.regenerate_limb(healed_limb)
limbs_to_heal -= healed_limb
H.blood_volume -= 40
to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!"))
return
to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!"))
+1 -1
View File
@@ -18,7 +18,7 @@
#define THERMAL_PROTECTION_HAND_LEFT 0.025
#define THERMAL_PROTECTION_HAND_RIGHT 0.025
/mob/living/carbon/human/BiologicalLife(seconds, times_fired)
/mob/living/carbon/human/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
handle_active_genes()
@@ -7,8 +7,8 @@
return
var/list/print_msg = list()
print_msg += "<span class='info'>*---------*</span>"
print_msg += "<span class='userdanger'>As you snap back to consciousness, you recall people messing with your stuff...</span>"
print_msg += "<blockquote class='warning'>"
afk_thefts = reverseRange(afk_thefts)
@@ -22,13 +22,14 @@
var/time_since = world.time - iter_theft[AFK_THEFT_TIME]
if(time_since > AFK_THEFT_FORGET_DETAILS_TIME)
print_msg += "\t<span class='danger'><b>Someone [theft_message], but it was at least [DisplayTimeText(AFK_THEFT_FORGET_DETAILS_TIME)] ago.</b></span>"
print_msg += "<span class='danger'><b>Someone [theft_message], but it was at least [DisplayTimeText(AFK_THEFT_FORGET_DETAILS_TIME)] ago.</b></span>"
else
print_msg += "\t<span class='danger'><b>[thief_name] [theft_message] roughly [DisplayTimeText(time_since, 10)] ago.</b></span>"
print_msg += "<span class='danger'><b>[thief_name] [theft_message] roughly [DisplayTimeText(time_since, 10)] ago.</b></span>"
print_msg += "</blockquote>"
if(LAZYLEN(afk_thefts) >= AFK_THEFT_MAX_MESSAGES)
print_msg += "<span class='warning'>There may have been more, but that's all you can remember...</span>"
print_msg += "<span class='info'>*---------*</span>"
to_chat(src, print_msg.Join("\n"))
LAZYNULL(afk_thefts)
@@ -65,6 +65,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/exotic_bloodtype = ""
/// Assume human as the default blood colour, override this default by species subtypes
var/exotic_blood_color = BLOOD_COLOR_HUMAN
/// Which blend mode should this species blood use?
var/exotic_blood_blend_mode = BLEND_MULTIPLY
///What the species drops when gibbed by a gibber machine.
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
@@ -826,13 +828,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/left_state = DEFAULT_LEFT_EYE_STATE
var/right_state = DEFAULT_RIGHT_EYE_STATE
if(eye_type in GLOB.eye_types)
left_state = eye_type + "_left_eye"
right_state = eye_type + "_right_eye"
left_state = "[eye_type]_left_eye"
right_state = "[eye_type]_right_eye"
var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER)
var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER)
if((EYECOLOR in species_traits) && has_eyes)
left_eye.color = "#" + H.left_eye_color
right_eye.color = "#" + H.right_eye_color
left_eye.color = "#[H.left_eye_color]"
right_eye.color = "#[H.right_eye_color]"
if(OFFSET_EYES in offset_features)
left_eye.pixel_x += offset_features[OFFSET_EYES][1]
left_eye.pixel_y += offset_features[OFFSET_EYES][2]
@@ -2450,6 +2452,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return TRUE
return FALSE
////////////////
//Blood Stuff///
////////////////
// true = handle blood normally, false = do not (and then handle blood in this proc instead please!!)
/datum/species/proc/handle_blood(mob/living/carbon/human/H, delta_time, times_fired)
return TRUE
////////////////
//Tail Wagging//
////////////////
@@ -17,6 +17,7 @@
exotic_blood = /datum/reagent/blood/jellyblood
exotic_bloodtype = "GEL"
exotic_blood_color = "BLOOD_COLOR_SLIME"
exotic_blood_blend_mode = BLEND_DEFAULT
damage_overlay_type = ""
liked_food = TOXIC | MEAT
disliked_food = null
@@ -31,6 +32,7 @@
species_category = SPECIES_CATEGORY_JELLY
wings_icons = SPECIES_WINGS_JELLY
ass_image = 'icons/ass/assslime.png'
blacklisted_quirks = list(/datum/quirk/glass_bones)
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
C.faction -= "slime"
@@ -53,38 +55,46 @@
//update blood color to body color
exotic_blood_color = "#" + H.dna.features["mcolor"]
/datum/species/jelly/spec_life(mob/living/carbon/human/H)
if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for bloodsuckers
return
if(!H.blood_volume)
H.adjust_integration_blood(5)
H.adjustBruteLoss(5)
to_chat(H, "<span class='danger'>You feel empty!</span>")
/datum/species/jelly/handle_blood(mob/living/carbon/human/H, delta_time, times_fired)
if(H.stat == DEAD) //can't farm slime jelly from a dead slime/jelly person indefinitely
return TRUE // we dont handle blood when dead
if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
if(H.blood_volume <= 0)
H.blood_volume += 2.5 * delta_time
H.adjustBruteLoss(2.5 * delta_time)
to_chat(H, span_danger("You feel empty!"))
if(H.blood_volume < BLOOD_VOLUME_NORMAL)
if(H.nutrition >= NUTRITION_LEVEL_STARVING)
H.adjust_integration_blood(3)
H.nutrition -= 2.5
if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
if(prob(5))
to_chat(H, "<span class='danger'>You feel drained!</span>")
if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
H.blood_volume += 1.5 * delta_time
H.adjust_nutrition(-1.25 * delta_time)
if(H.blood_volume < BLOOD_VOLUME_OKAY)
if(DT_PROB(2.5, delta_time))
to_chat(H, span_danger("You feel drained!"))
if(H.blood_volume < BLOOD_VOLUME_BAD)
Cannibalize_Body(H)
..()
var/datum/action/innate/ability/regrowth = H.ability_actions[INNATE_ABILITY_LIMB_REGROWTH]
if(regrowth)
regrowth.UpdateButtonIcon()
return FALSE // to let living/handle_blood know that the species is handling blood instead
/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H)
var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs()
var/obj/item/bodypart/consumed_limb
if(!limbs_to_consume.len)
if(!length(limbs_to_consume))
H.losebreath++
return
if(H.get_num_legs(FALSE)) //Legs go before arms
limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
consumed_limb = H.get_bodypart(pick(limbs_to_consume))
consumed_limb.drop_limb()
to_chat(H, "<span class='userdanger'>Your [consumed_limb] is drawn back into your body, unable to maintain its shape!</span>")
to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!"))
qdel(consumed_limb)
H.adjust_integration_blood(20)
H.blood_volume += 20
////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
@@ -26,6 +26,7 @@
wings_icons = SPECIES_WINGS_SKELETAL
ass_image = 'icons/ass/assplasma.png'
blacklisted_quirks = list(/datum/quirk/paper_skin)
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
@@ -17,6 +17,7 @@
species_category = SPECIES_CATEGORY_SKELETON //they have their own category that's disassociated from undead, paired with plasmapeople
wings_icons = SPECIES_WINGS_SKELETAL
blacklisted_quirks = list(/datum/quirk/paper_skin)
/datum/species/skeleton/New()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season!
@@ -209,7 +209,7 @@ There are several things that need to be remembered:
inv.update_icon()
if(!gloves && bloody_hands)
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
if(get_num_arms(FALSE) < 2)
if(has_left_hand(FALSE))
bloody_overlay.icon_state = "bloodyhands_left"
+5 -5
View File
@@ -1,6 +1,6 @@
/mob/living/carbon/BiologicalLife(seconds, times_fired)
/mob/living/carbon/BiologicalLife(delta_time, times_fired)
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs(seconds, times_fired)
handle_organs(delta_time, times_fired)
. = ..() // if . is false, we are dead.
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
@@ -9,7 +9,7 @@
. = FALSE
if(!.)
return
handle_blood()
handle_blood(delta_time, times_fired)
// handle_blood *could* kill us.
// we should probably have a better system for if we need to check for death or something in the future hmw
if(stat != DEAD)
@@ -23,7 +23,7 @@
handle_brain_damage()
if(stat != DEAD)
handle_liver(seconds, times_fired)
handle_liver(delta_time, times_fired)
if(stat != DEAD)
handle_corruption()
@@ -375,7 +375,7 @@
miasma_turf.air_update_turf()
/mob/living/carbon/proc/handle_blood()
/mob/living/carbon/proc/handle_blood(delta_time, times_fired)
return
/mob/living/carbon/proc/handle_bodyparts(seconds, times_fired)
@@ -3,7 +3,7 @@
/mob/living/carbon/monkey
/mob/living/carbon/monkey/BiologicalLife(seconds, times_fired)
/mob/living/carbon/monkey/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
if(client)
@@ -33,7 +33,7 @@
if(relic_mask)
equip_to_slot_or_del(new relic_mask, ITEM_SLOT_MASK)
/mob/living/carbon/monkey/punpun/BiologicalLife(seconds, times_fired)
/mob/living/carbon/monkey/punpun/BiologicalLife(delta_time, times_fired)
if(!(. = ..()))
return
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
@@ -46,6 +46,7 @@
..()
/mob/living/carbon/monkey/punpun/proc/Read_Memory()
var/saved_color
if(fexists("data/npc_saves/Punpun.sav")) //legacy compatability to convert old format to new
var/savefile/S = new /savefile("data/npc_saves/Punpun.sav")
S["ancestor_name"] >> ancestor_name
@@ -62,6 +63,9 @@
ancestor_chain = json["ancestor_chain"]
relic_hat = json["relic_hat"]
relic_mask = json["relic_hat"]
saved_color = json["color"]
if(!isnull(saved_color))
add_atom_colour(json_decode(saved_color), FIXED_COLOUR_PRIORITY)
/mob/living/carbon/monkey/punpun/proc/Write_Memory(dead, gibbed)
var/json_file = file("data/npc_saves/Punpun.json")
@@ -71,10 +75,12 @@
file_data["ancestor_chain"] = null
file_data["relic_hat"] = null
file_data["relic_mask"] = null
file_data["color"] = null
else
file_data["ancestor_name"] = ancestor_name ? ancestor_name : name
file_data["ancestor_chain"] = dead ? ancestor_chain + 1 : ancestor_chain
file_data["relic_hat"] = head ? head.type : null
file_data["relic_mask"] = wear_mask ? wear_mask.type : null
file_data["color"] = color ? json_encode(color) : null
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
+2
View File
@@ -518,6 +518,8 @@
/datum/emote/living/circle/run_emote(mob/user, params)
. = ..()
if(!.)
return
var/obj/item/circlegame/N = new(user)
if(user.put_in_hands(N))
to_chat(user, "<span class='notice'>You make a circle with your hand.</span>")
+3 -3
View File
@@ -42,8 +42,8 @@
* Handles biological life processes like chemical metabolism, breathing, etc
* Returns TRUE or FALSE based on if we were interrupted. This is used by overridden variants to check if they should stop.
*/
/mob/living/proc/BiologicalLife(seconds, times_fired)
SEND_SIGNAL(src,COMSIG_LIVING_BIOLOGICAL_LIFE, seconds, times_fired)
/mob/living/proc/BiologicalLife(delta_time, times_fired)
SEND_SIGNAL(src,COMSIG_LIVING_BIOLOGICAL_LIFE, delta_time, times_fired)
handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
handle_wounds()
@@ -67,7 +67,7 @@
//stuff in the stomach
handle_stomach()
handle_block_parry(seconds)
handle_block_parry(delta_time)
handle_traits() // eye, ear, brain damages
+78 -48
View File
@@ -81,6 +81,7 @@
//Called when we bump onto a mob
/mob/living/proc/MobBump(mob/M)
SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
@@ -88,6 +89,7 @@
return TRUE
var/they_can_move = TRUE
if(isliving(M))
var/mob/living/L = M
they_can_move = CHECK_MOBILITY(L, MOBILITY_MOVE)
@@ -105,16 +107,16 @@
//Should stop you pushing a restrained person out of the way
if(L.pulledby && L.pulledby != src && L.restrained())
if(!(world.time % 5))
to_chat(src, "<span class='warning'>[L] is restrained, you cannot push past.</span>")
return 1
to_chat(src, span_warning("[L] is restrained, you cannot push past."))
return TRUE
if(L.pulling)
if(ismob(L.pulling))
var/mob/P = L.pulling
if(P.restrained())
if(!(world.time % 5))
to_chat(src, "<span class='warning'>[L] is restraining [P], you cannot push past.</span>")
return 1
to_chat(src, span_warning("[L] is restraining [P], you cannot push past."))
return TRUE
//CIT CHANGES START HERE - makes it so resting stops you from moving through standing folks or over prone bodies without a short delay
if(!CHECK_MOBILITY(src, MOBILITY_STAND))
@@ -142,7 +144,7 @@
//END OF CIT CHANGES
if(moving_diagonally)//no mob swap during diagonal moves.
return 1
return TRUE
if(!M.buckled && !M.has_buckled_mobs())
var/mob_swap = FALSE
@@ -151,7 +153,8 @@
if(!too_strong)
mob_swap = TRUE
else
if(M.pulledby == src && a_intent == INTENT_GRAB)
//You can swap with the person you are dragging on grab intent, and restrained people in most cases
if(M.pulledby == src && !too_strong)
mob_swap = TRUE
//restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
@@ -159,8 +162,8 @@
if(mob_swap)
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
return 1
now_pushing = 1
return TRUE
now_pushing = TRUE
var/oldloc = loc
var/oldMloc = M.loc
@@ -180,27 +183,31 @@
if(!M_passmob)
M.pass_flags &= ~PASSMOB
now_pushing = 0
now_pushing = FALSE
if(!move_failed)
return 1
return TRUE
//okay, so we didn't switch. but should we push?
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
return 1
return TRUE
if(isliving(M))
var/mob/living/L = M
if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE))
return 1
//If they're a human, and they're not in help intent, block pushing
if(ishuman(M) && (M.a_intent != INTENT_HELP))
return TRUE
return TRUE
if(M.a_intent != INTENT_HELP)
//If they're a human, and they're not in help intent, block pushing
if(ishuman(M))
return TRUE
//if they are a cyborg, and they're alive and not in help intent, block pushing
if(iscyborg(M) && M.stat != DEAD)
return TRUE
//anti-riot equipment is also anti-push
for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing))
if(prob(I.block_chance*2))
return 1
return TRUE
/mob/living/get_photo_description(obj/item/camera/camera)
var/list/mob_details = list()
@@ -231,21 +238,40 @@
if(!client && (mob_size < MOB_SIZE_SMALL))
return
now_pushing = TRUE
var/t = get_dir(src, AM)
SEND_SIGNAL(src, COMSIG_LIVING_PUSHING_MOVABLE, AM)
var/dir_to_target = get_dir(src, AM)
// If there's no dir_to_target then the player is on the same turf as the atom they're trying to push.
// This can happen when a player is stood on the same turf as a directional window. All attempts to push
// the window will fail as get_dir will return 0 and the player will be unable to move the window when
// it should be pushable.
// In this scenario, we will use the facing direction of the /mob/living attempting to push the atom as
// a fallback.
if(!dir_to_target)
dir_to_target = dir
var/push_anchored = FALSE
if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force)
if(move_crush(AM, move_force, t))
if(move_crush(AM, move_force, dir_to_target))
push_anchored = TRUE
if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
if(force_push(AM, move_force, t, push_anchored))
if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
if(force_push(AM, move_force, dir_to_target, push_anchored))
push_anchored = TRUE
if(ismob(AM))
var/mob/mob_to_push = AM
var/atom/movable/mob_buckle = mob_to_push.buckled
// If we can't pull them because of what they're buckled to, make sure we can push the thing they're buckled to instead.
// If neither are true, we're not pushing anymore.
if(mob_buckle && (mob_buckle.buckle_prevents_pull || (force < (mob_buckle.move_resist * MOVE_FORCE_PUSH_RATIO))))
now_pushing = FALSE
return
if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO)))
now_pushing = FALSE
return
if (istype(AM, /obj/structure/window))
if(istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(W.fulltile)
for(var/obj/structure/window/win in get_step(W,t))
for(var/obj/structure/window/win in get_step(W, dir_to_target))
now_pushing = FALSE
return
if(pulling == AM)
@@ -253,8 +279,9 @@
var/current_dir
if(isliving(AM))
current_dir = AM.dir
if(step(AM, t) && Process_Spacemove(t))
step(src, t)
if(AM.Move(get_step(AM.loc, dir_to_target), dir_to_target, glide_size))
AM.add_fingerprint(src)
Move(get_step(loc, dir_to_target), dir_to_target)
if(current_dir)
AM.setDir(current_dir)
now_pushing = FALSE
@@ -354,29 +381,33 @@
offset = GRAB_PIXEL_SHIFT_NECK
if(GRAB_KILL)
offset = GRAB_PIXEL_SHIFT_NECK
M.setDir(get_dir(M, src))
switch(M.dir)
if(NORTH)
animate(M, pixel_x = 0, pixel_y = offset, 3)
if(SOUTH)
animate(M, pixel_x = 0, pixel_y = -offset, 3)
if(EAST)
if(M.lying == 270) //update the dragged dude's direction if we've turned
M.lying = 90
M.update_transform() //force a transformation update, otherwise it'll take a few ticks for update_mobility() to do so
M.lying_prev = M.lying
animate(M, pixel_x = offset, pixel_y = 0, 3)
if(WEST)
if(M.lying == 90)
M.lying = 270
M.update_transform()
M.lying_prev = M.lying
animate(M, pixel_x = -offset, pixel_y = 0, 3)
var/target_dir = get_dir(M, src)
M.setDir(target_dir)
var/target_x
var/target_y
if(target_dir & NORTH)
target_y += offset
if(target_dir & SOUTH)
target_y -= offset
if(target_dir & EAST)
target_x += offset
if(target_dir & WEST)
target_x -= offset
if(target_x || target_y)
if(0 < target_x && M.lying == 270)
M.lying = 90
M.update_transform(FALSE) //force a transformation update, otherwise it'll take a few ticks for update_mobility() to do so
M.lying_prev = M.lying
if(0 > target_x && M.lying == 90)
M.lying = 270
M.update_transform(FALSE)
M.lying_prev = M.lying
animate(M, pixel_x = target_x, pixel_y = target_y, time = 3, flags = ANIMATION_PARALLEL)
/mob/living/proc/reset_pull_offsets(mob/living/M, override)
if(!override && M.buckled)
return
animate(M, pixel_x = 0, pixel_y = 0, 1)
animate(M, pixel_x = 0, pixel_y = 0, time = 3, flags = ANIMATION_PARALLEL)
//mob verbs are a lot faster than object verbs
//for more info on why this is not atom/pull, see examinate() in mob.dm
@@ -885,12 +916,11 @@
if(anchored || (buckled && buckled.anchored))
fixed = 1
if(on && !(movement_type & FLOATING) && !fixed)
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
sleep(10)
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
setMovetype(movement_type | FLOATING)
else if(((!on || fixed) && (movement_type & FLOATING)))
animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10)
animate(src, pixel_z = get_standard_pixel_y_offset(lying), time = 10)
setMovetype(movement_type & ~FLOATING)
// The src mob is trying to strip an item from someone
@@ -989,7 +1019,7 @@
var/pixel_y_diff = rand(-amplitude/3, amplitude/3)
var/final_pixel_x = get_standard_pixel_x_offset(lying)
var/final_pixel_y = get_standard_pixel_y_offset(lying)
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6)
animate(src, pixel_x = pixel_x_diff, pixel_y = pixel_y_diff , time = 2, loop = 6, flags = ANIMATION_PARALLEL | ANIMATION_RELATIVE)
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2)
floating_need_update = TRUE
+23 -3
View File
@@ -238,7 +238,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args) //parent calls can't overwrite the current proc args.
if(!client)
if(!client && !audiovisual_redirect)
return
var/deaf_message
var/deaf_type
@@ -297,8 +297,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
AM.Hear(rendered, src, message_language, message, null, spans, message_mode, source)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
if(client && !eavesdrop_range && say_test(message) == "2") // Yell hook
process_yelling(listening, rendered, src, message_language, message, spans, message_mode, source)
var/is_yell = (say_test(message) == "2")
if(client && !eavesdrop_range && is_yell) // Yell hook
listening |= process_yelling(listening, rendered, src, message_language, message, spans, message_mode, source)
//speech bubble
var/list/speech_bubble_recipients = list()
@@ -309,6 +310,23 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30)
//Listening gets trimmed here if a vocal bark's present. If anyone ever makes this proc return listening, make sure to instead initialize a copy of listening in here to avoid wonkiness
if(SEND_SIGNAL(src, COMSIG_MOVABLE_QUEUE_BARK, listening, args) || vocal_bark || vocal_bark_id)
for(var/mob/M in listening)
if(!M.client)
continue
if(!(M.client.prefs.toggles & SOUND_BARK))
listening -= M
var/barks = min(round((LAZYLEN(message) / vocal_speed)) + 1, BARK_MAX_BARKS)
var/total_delay
vocal_current_bark = world.time
for(var/i in 1 to barks)
if(total_delay > BARK_MAX_TIME)
break
addtimer(CALLBACK(src, /atom/movable/proc/bark, listening, (message_range * (is_yell ? 4 : 1)), (vocal_volume * (is_yell ? 1.5 : 1)), BARK_DO_VARY(vocal_pitch, vocal_pitch_range), vocal_current_bark), total_delay)
total_delay += rand(DS2TICKS(vocal_speed / BARK_SPEED_BASELINE), DS2TICKS(vocal_speed / BARK_SPEED_BASELINE) + DS2TICKS((vocal_speed / BARK_SPEED_BASELINE) * (is_yell ? 0.5 : 1))) TICKS
/atom/movable/proc/process_yelling(list/already_heard, rendered, atom/movable/speaker, datum/language/message_language, message, list/spans, message_mode, obj/source)
if(last_yell > (world.time - 10))
to_chat(src, "<span class='warning'>Your voice doesn't project as far as you try to yell in such quick succession.") // yeah no, no spamming an expensive floodfill.
@@ -333,6 +351,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/atom/movable/AM = _AM
AM.Hear(rendered, speaker, message_language, message, null, spans, message_mode, source)
return overhearing
/mob/proc/binarycheck()
return FALSE
+14 -2
View File
@@ -47,6 +47,7 @@
var/mob/living/simple_animal/bot/Bot
var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
var/obj/machinery/status_display/controlled_display
//MALFUNCTION
var/datum/module_picker/malf_picker
@@ -660,7 +661,7 @@
"goat" = 'icons/mob/animal.dmi',
"cat" = 'icons/mob/pets.dmi',
"cat2" = 'icons/mob/pets.dmi',
"poly" = 'icons/mob/animal.dmi',
"polly" = 'icons/mob/animal.dmi',
"pug" = 'icons/mob/pets.dmi',
"spider" = 'icons/mob/animal.dmi'
)
@@ -669,7 +670,7 @@
if(input)
qdel(holo_icon)
switch(input)
if("poly")
if("polly")
holo_icon = getHologramIcon(icon(icon_list[input],"parrot_fly"))
if("chicken")
holo_icon = getHologramIcon(icon(icon_list[input],"chicken_brown"))
@@ -1043,3 +1044,14 @@
/mob/living/silicon/ai/zMove(dir, feedback = FALSE)
. = eyeobj.zMove(dir, feedback)
/mob/living/silicon/ai/proc/stop_controlling_display()
if(!controlled_display)
return
controlled_display.master = null
controlled_display.cut_overlay(controlled_display.ai_vtuber_overlay)
controlled_display.ai_vtuber_overlay = null
if(current == controlled_display)
current = null
controlled_display.update_appearance()
controlled_display = null
@@ -1,5 +1,5 @@
/mob/living/silicon/ai/examine(mob/user)
. = list("<span class='info'>*---------*\nThis is [icon2html(src, user)] <EM>[src]</EM>!")
. = list("<span class='info'>This is [icon2html(src, user)] <EM>[src]</EM>!")
if (stat == DEAD)
. += "<span class='deadsay'>It appears to be powered-down.</span>"
else
@@ -17,6 +17,8 @@
. += "The wireless networking light is blinking."
else if (!shunted && !client)
. += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem..."
. += "*---------*</span>"
if(LAZYLEN(.) > 1)
.[2] = "<hr>[.[2]]"
. += ..()
@@ -92,6 +92,8 @@
ai.light_cameras()
if(ai.master_multicam)
ai.master_multicam.refresh_view()
if(ai.controlled_display)
ai.stop_controlling_display()
//it uses setLoc not forceMove, talks to the sillycone and not the camera mob
/mob/camera/aiEye/zMove(dir, feedback = FALSE)
@@ -168,6 +170,9 @@
if(!user.tracking)
user.cameraFollow = null
if(user.controlled_display)
user.stop_controlling_display()
// Return to the Core.
/mob/living/silicon/ai/proc/view_core()
if(istype(current,/obj/machinery/holopad))

Some files were not shown because too many files have changed in this diff Show More