Merge remote-tracking branch 'upstream/master'

This commit is contained in:
DeltaFire
2021-02-11 04:03:00 +01:00
91 changed files with 879 additions and 153 deletions
+32 -8
View File
@@ -13605,13 +13605,10 @@
/obj/structure/cable{
icon_state = "1-2"
},
/obj/structure/disposalpipe/sorting/mail{
dir = 2;
sortType = 18
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 4
},
/obj/structure/disposalpipe/segment,
/turf/open/floor/plating,
/area/maintenance/starboard/fore)
"aEB" = (
@@ -56987,6 +56984,17 @@
icon_state = "wood-broken6"
},
/area/maintenance/bar)
"lqO" = (
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/disposalpipe/sorting/mail/flip{
dir = 1;
sortType = 18
},
/turf/open/floor/plating,
/area/maintenance/fore)
"lre" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/table/wood/poker,
@@ -57108,6 +57116,12 @@
},
/turf/closed/wall,
/area/maintenance/disposal/incinerator)
"lLf" = (
/obj/structure/disposalpipe/segment{
dir = 4
},
/turf/closed/wall/r_wall,
/area/maintenance/fore)
"lMg" = (
/obj/effect/turf_decal/stripes/line{
dir = 9
@@ -58822,6 +58836,14 @@
},
/turf/open/floor/plating,
/area/maintenance/disposal)
"pMQ" = (
/obj/structure/window/reinforced,
/obj/machinery/disposal/bin,
/obj/structure/disposalpipe/trunk{
dir = 4
},
/turf/open/floor/wood,
/area/crew_quarters/theatre)
"pPi" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -60860,11 +60882,13 @@
/obj/structure/cable{
icon_state = "2-8"
},
/obj/structure/disposalpipe/junction,
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/effect/turf_decal/tile/neutral,
/obj/structure/disposalpipe/sorting/mail{
sortType = 26
},
/turf/open/floor/plasteel,
/area/crew_quarters/dorms)
"uys" = (
@@ -84618,7 +84642,7 @@ ayD
nez
ngV
xPY
aOH
pMQ
hcb
hcb
syJ
@@ -84875,7 +84899,7 @@ ayE
ayE
ayE
ayE
ayE
lLf
ayE
ayE
ayE
@@ -85132,7 +85156,7 @@ ayH
ayH
ayH
ayH
ayH
lqO
ayH
aFV
ayH
+1 -1
View File
@@ -290,7 +290,7 @@
#define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items)
#define COMPONENT_PREVENT_BLOCK_START 1
#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items)
#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override)
#define COMPONENT_PREVENT_PARRY_START 1
//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
+1
View File
@@ -197,6 +197,7 @@
#define TRAIT_EMPATH "empath"
#define TRAIT_FRIENDLY "friendly"
#define TRAIT_SNOB "snob"
#define TRAIT_MULTILINGUAL "multilingual"
#define TRAIT_CULT_EYES "cult_eyes"
#define TRAIT_AUTO_CATCH_ITEM "auto_catch_item"
#define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman.
+1 -1
View File
@@ -10,7 +10,7 @@
announcement += "<br><h2 class='alert'>[html_encode(title)]</h2>"
else if(type == "Captain")
announcement += "<h1 class='alert'>Captain Announces</h1>"
GLOB.news_network.SubmitArticle(text, "Captain's Announcement", "Station Announcements", null)
GLOB.news_network.SubmitArticle(html_encode(text), "Captain's Announcement", "Station Announcements", null)
else
if(!sender_override)
@@ -484,6 +484,8 @@
/datum/config_entry/flag/modetier_voting
/datum/config_entry/flag/must_be_readied_to_vote_gamemode
/datum/config_entry/number/dropped_modes
config_entry_value = 3
+12
View File
@@ -68,6 +68,10 @@ SUBSYSTEM_DEF(vote)
//get the highest number of votes
var/greatest_votes = 0
var/total_votes = 0
if(mode == "gamemode" && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
for(var/mob/dead/new_player/P in GLOB.player_list)
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
choices[choices[voted[P.ckey]]]--
for(var/option in choices)
var/votes = choices[option]
total_votes += votes
@@ -101,6 +105,10 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text)
// https://en.wikipedia.org/wiki/Schulze_method#Implementation
if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
for(var/mob/dead/new_player/P in GLOB.player_list)
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
voted -= P.ckey
var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b
for(var/ckey in voted)
var/list/this_vote = voted[ckey]
@@ -147,6 +155,10 @@ SUBSYSTEM_DEF(vote)
for(var/choice in choices)
scores_by_choice += "[choice]"
scores_by_choice["[choice]"] = list()
if((mode == "gamemode" || mode == "dynamic") && CONFIG_GET(flag/must_be_readied_to_vote_gamemode))
for(var/mob/dead/new_player/P in GLOB.player_list)
if(P.ready != PLAYER_READY_TO_PLAY && voted[P.ckey])
voted -= P.ckey
for(var/ckey in voted)
var/list/this_vote = voted[ckey]
var/list/pretty_vote = list()
+16
View File
@@ -219,3 +219,19 @@
/datum/quirk/night_vision/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
H.update_sight()
/datum/quirk/multilingual
name = "Multi-Lingual"
desc = "You spent a portion of your life learning to understand an additional language. You may or may not be able to speak it based on your anatomy."
value = 1
mob_trait = TRAIT_MULTILINGUAL
gain_text = "You've learned an extra language!"
lose_text = "You've forgotten your extra language."
/datum/quirk/multilingual/add()
var/mob/living/carbon/human/H = quirk_holder
H.grant_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MIND)
/datum/quirk/multilingual/remove()
var/mob/living/carbon/human/H = quirk_holder
H.remove_language(H.client.prefs.language, TRUE, TRUE, LANGUAGE_MIND)
@@ -33,6 +33,7 @@
/datum/sabotage_objective/processing/check_conditions()
return won
/*
/datum/sabotage_objective/processing/power_sink
name = "Drain at least 100 megajoules of power using a power sink."
sabotage_type = "powersink"
@@ -44,6 +45,7 @@
for(var/s in GLOB.power_sinks)
var/obj/item/powersink/sink = s
won = max(won,sink.power_drained/1e8)
*/
/obj/item/paper/guides/antag/supermatter_sabotage
info = "Ways to sabotage a supermatter:<br>\
+8 -1
View File
@@ -151,7 +151,14 @@
var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list
if(!target)
return
target.vars[type] = target.setsubsystem(text2num(value))
value = target.setsubsystem(text2num(value))
switch(type) // Sanity check
if("equipment", "lighting", "environ")
target.vars[type] = value
else
message_admins("Warning: possible href exploit by [key_name(usr)] - attempted to set [type] on [target] to [value]")
log_game("Warning: possible href exploit by [key_name(usr)] - attempted to set [type] on [target] to [value]")
return
target.update_icon()
target.update()
var/setTo = ""
+6 -4
View File
@@ -97,7 +97,7 @@
icon_state = "mecha_ion"
energy_drain = 120
projectile = /obj/item/projectile/ion
fire_sound = 'sound/weapons/laser.ogg'
fire_sound = 'sound/weapons/IonRifle.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla
equip_cooldown = 35
@@ -195,7 +195,7 @@
//Base ballistic weapon type
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
name = "general ballistic weapon"
fire_sound = 'sound/weapons/gunshot.ogg'
fire_sound = 'sound/weapons/lmgshot.ogg'
var/projectiles
var/projectiles_cache //ammo to be loaded in, if possible.
var/projectiles_cache_max
@@ -285,6 +285,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
name = "\improper LBX AC 10 \"Scattershot\""
desc = "A weapon for combat exosuits. Shoots a spread of pellets."
fire_sound = 'sound/weapons/gunshotshotgunshot.ogg'
icon_state = "mecha_scatter"
equip_cooldown = 20
projectile = /obj/item/projectile/bullet/scattershot
@@ -299,6 +300,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter
name = "\improper Melon Seed \"Scattershot\""
desc = "A weapon for combat exosuits. Shoots a spread of pellets, shaped as seed."
fire_sound = 'sound/weapons/gunshotshotgunshot.ogg'
icon_state = "mecha_scatter"
equip_cooldown = 20
projectile = /obj/item/projectile/bullet/seed
@@ -331,7 +333,7 @@
desc = "A weapon for combat exosuits. Launches light explosive missiles."
icon_state = "mecha_missilerack"
projectile = /obj/item/projectile/bullet/a84mm_he
fire_sound = 'sound/weapons/grenadelaunch.ogg'
fire_sound = 'sound/weapons/rocketlaunch.ogg'
projectiles = 8
projectiles_cache = 0
projectiles_cache_max = 0
@@ -345,7 +347,7 @@
desc = "A weapon for combat exosuits. Launches low-explosive breaching missiles designed to explode only when striking a sturdy target."
icon_state = "mecha_missilerack_six"
projectile = /obj/item/projectile/bullet/a84mm_br
fire_sound = 'sound/weapons/grenadelaunch.ogg'
fire_sound = 'sound/weapons/rocketlaunch.ogg'
projectiles = 6
projectiles_cache = 0
projectiles_cache_max = 0
@@ -81,6 +81,7 @@
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
name = "blood"
icon = 'icons/effects/blood.dmi'
icon_state = "ltrails_1"
desc = "Your instincts say you shouldn't be following these."
random_icon_states = null
@@ -69,7 +69,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans,datum/language/language)
if (!listening)
return ITALICS | REDUCE_RANGE
return ..()
if (language != /datum/language/signlanguage)
return ..()
/obj/item/radio/headset/can_receive(freq, level, AIuser)
if(ishuman(src.loc))
@@ -208,6 +208,8 @@
return
if(!M.IsVocal())
return
if(language == /datum/language/signlanguage)
return
if(use_command)
spans |= commandspan
@@ -44,7 +44,7 @@
icon_state = "warp"
uses = -1
var/total_delay = 10 SECONDS
var/cooldown = 10 SECONDS
var/cooldown = 30 SECONDS
var/last_use = 0
var/list/positions = list()
var/next_prune = 0
+1 -1
View File
@@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
custom_materials = list(/datum/material/iron=1000)
max_amount = 50
attack_verb = list("hit", "bludgeoned", "whacked")
hitsound = 'sound/weapons/grenadelaunch.ogg'
hitsound = 'sound/items/trayhit1.ogg'
embedding = list()
novariants = TRUE
+1 -1
View File
@@ -302,7 +302,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
damtype = STAMINA
attack_verb = list("whacked", "smacked", "struck")
total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
hitsound = 'sound/weapons/grenadelaunch.ogg' // no good wood thunk sounds
hitsound = 'sound/weapons/woodbonk.ogg'
var/harm = FALSE // TRUE = brute, FALSE = stam
var/reinforced = FALSE
var/burnt = FALSE
@@ -5,6 +5,7 @@
viable_mobtypes = list(/mob/living/carbon/human)
mutable = FALSE
var/mob/camera/disease/overmind
infectable_biotypes = MOB_ORGANIC|MOB_ROBOTIC
/datum/disease/advance/sentient_disease/New()
..()
+25
View File
@@ -99,6 +99,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/be_random_body = 0 //whether we'll have a random body every round
var/gender = MALE //gender of character (well duh)
var/age = 30 //age of character
var/language = "Random" //bonus language
var/choselanguage = "Random" //language appearance
var/underwear = "Nude" //underwear type
var/undie_color = "FFFFFF"
var/undershirt = "Nude" //undershirt type
@@ -308,6 +310,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender;task=input'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
dat += "<b>Age:</b> <a style='display:block;width:30px' href='?_src_=prefs;preference=age;task=input'>[age]</a><BR>"
dat += "<b>Language:</b> <a href='?_src_=prefs;preference=language;task=input'>[choselanguage]</a><BR>"
dat += "<b>Special Names:</b><BR>"
var/old_group
@@ -2315,6 +2318,28 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["body_model"] = chosengender
gender = chosengender
if("language")
choselanguage = input(user, "Select a language.", "Language", language) as null|anything in list("Beachtongue","Draconic","Dwarven",
"Chimpanzee","Space Sign Language","Random")
if(!choselanguage)
return
switch(choselanguage)
if("Rachidian")
language = /datum/language/arachnid
if("Beachtongue")
language = /datum/language/beachbum
if("Draconic")
language = /datum/language/draconic
if("Dwarven")
language = /datum/language/dwarf
if("Chimpanzee")
language = /datum/language/monkey
if("Space Sign Language")
language = /datum/language/signlanguage
if("Random")
language = pick(list("Rachidian", "Beachtongue","Draconic","Dwarven",
"Chimpanzee","Space Sign Language"))
if("body_size")
var/new_body_size = input(user, "Choose your desired sprite size: (90-125%)\nWarning: This may make your character look distorted. Additionally, any size under 100% takes a 10% maximum health penalty", "Character Preference", features["body_size"]*100) as num|null
if(new_body_size)
@@ -604,6 +604,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["body_model"] >> features["body_model"]
S["body_size"] >> features["body_size"]
S["age"] >> age
S["language"] >> language
S["choselanguage"] >> choselanguage
S["hair_color"] >> hair_color
S["facial_hair_color"] >> facial_hair_color
S["eye_type"] >> eye_type
@@ -947,6 +949,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["body_model"] , features["body_model"])
WRITE_FILE(S["body_size"] , features["body_size"])
WRITE_FILE(S["age"] , age)
WRITE_FILE(S["language"] , language)
WRITE_FILE(S["choselanguage"] , choselanguage)
WRITE_FILE(S["hair_color"] , hair_color)
WRITE_FILE(S["facial_hair_color"] , facial_hair_color)
WRITE_FILE(S["eye_type"] , eye_type)
@@ -161,6 +161,68 @@
return NO_AUTO_CLICKDELAY_HANDLING | ATTACK_IGNORE_ACTION
/obj/item/clothing/gloves/fingerless/ablative
name = "ablative armwraps"
desc = "Armwraps made out of a highly durable, reflective metal. Has the side effect of absorbing shocks."
siemens_coefficient = 0
icon_state = "ablative_armwraps"
item_state = "ablative_armwraps"
block_parry_data = /datum/block_parry_data/ablative_armwraps
var/wornonce = FALSE
/obj/item/clothing/gloves/fingerless/ablative/proc/get_component_parry_data(datum/source, parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override)
if(parrying_method && !(parrying_method == UNARMED_PARRY))
return
override[src] = ITEM_PARRY
/obj/item/clothing/gloves/fingerless/ablative/equipped(mob/user, slot)
. = ..()
if(current_equipped_slot == SLOT_GLOVES)
RegisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START, .proc/get_component_parry_data)
wornonce = TRUE
/obj/item/clothing/gloves/fingerless/ablative/dropped(mob/user)
. = ..()
if(wornonce)
UnregisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START)
wornonce = FALSE
/obj/item/clothing/gloves/fingerless/ablative/can_active_parry(mob/user)
var/mob/living/carbon/human/H = user
if(!istype(H))
return FALSE
return src == H.gloves
/obj/item/clothing/gloves/fingerless/ablative/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time)
. = ..()
if(parry_efficiency > 0)
owner.visible_message("<span class='warning'>[owner] deflects \the [object] with their armwraps!</span>")
/datum/block_parry_data/ablative_armwraps
parry_stamina_cost = 4
parry_attack_types = ATTACK_TYPE_UNARMED | ATTACK_TYPE_PROJECTILE | ATTACK_TYPE_TACKLE | ATTACK_TYPE_THROWN | ATTACK_TYPE_MELEE
parry_flags = NONE
parry_time_windup = 0
parry_time_spindown = 0
parry_time_active = 7.5
parry_time_perfect = 1
parry_time_perfect_leeway = 7.5
parry_imperfect_falloff_percent = 20
parry_efficiency_perfect = 100
parry_time_perfect_leeway_override = list(
TEXT_ATTACK_TYPE_MELEE = 1
)
parry_efficiency_considered_successful = 0.01
parry_efficiency_to_counterattack = INFINITY // no auto counter
parry_max_attacks = INFINITY
parry_failed_cooldown_duration = 2.25 SECONDS
parry_failed_stagger_duration = 2.25 SECONDS
parry_cooldown = 0
parry_failed_clickcd_duration = 0
/obj/item/clothing/gloves/botanic_leather
name = "botanist's leather gloves"
desc = "These leather gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin. They're also quite warm."
+1 -1
View File
@@ -36,7 +36,7 @@
/obj/item/clothing/mask/surgical/aesthetic
name = "aesthetic sterile mask"
desc = "A sterile mask designed to help prevent the spread of diseases. This one doesn't seem like it does a whole lot, somehow."
flags_inv = HIDEFACE
flags_inv = null
flags_cover = null
visor_flags_inv = null
visor_flags_cover = null
+22 -3
View File
@@ -97,12 +97,14 @@
SEND_SIGNAL(t_loc, COMSIG_TURF_MAKE_DRY, TURF_WET_WATER, TRUE, INFINITY)
/obj/item/clothing/shoes/clown_shoes
desc = "The prankster's standard-issue clowning shoes. Damn, they're huge!"
desc = "The prankster's standard-issue clowning shoes. Damn, they're huge! Ctrl-click to toggle waddle dampeners."
name = "clown shoes"
icon_state = "clown_shoes"
slowdown = SHOES_SLOWDOWN+1
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes/clown
lace_time = 20 SECONDS // how the hell do these laces even work??
var/datum/component/waddle
var/enabled_waddle = TRUE
/obj/item/clothing/shoes/clown_shoes/Initialize()
. = ..()
@@ -110,14 +112,31 @@
/obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot)
. = ..()
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY))
SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "noshoes")
if(slot == SLOT_SHOES)
if(enabled_waddle)
waddle = user.AddComponent(/datum/component/waddling)
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY))
SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "noshoes")
/obj/item/clothing/shoes/clown_shoes/dropped(mob/user)
. = ..()
QDEL_NULL(waddle)
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY))
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "noshoes", /datum/mood_event/noshoes)
/obj/item/clothing/shoes/clown_shoes/CtrlClick(mob/living/user)
if(!isliving(user))
return
if(user.get_active_held_item() != src)
to_chat(user, "<span class='warning'>You must hold the [src] in your hand to do this!</span>")
return
if (!enabled_waddle)
to_chat(user, "<span class='notice'>You switch off the waddle dampeners!</span>")
enabled_waddle = TRUE
else
to_chat(user, "<span class='notice'>You switch on the waddle dampeners!</span>")
enabled_waddle = FALSE
/obj/item/clothing/shoes/clown_shoes/jester
name = "jester shoes"
desc = "A court jester's shoes, updated with modern squeaking technology."
@@ -487,6 +487,13 @@
item_state = "militaryjacket"
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/radio)
/obj/item/clothing/suit/jacket/urbanjacket
name = "urban jacket"
desc = "A canvas jacket styled with a fur neck piece, stylish."
icon_state = "urbanjacket"
item_state = "urbanjacket"
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/radio)
/obj/item/clothing/suit/jacket/letterman
name = "letterman jacket"
desc = "A classic brown letterman jacket. Looks pretty hot and heavy."
+6
View File
@@ -91,6 +91,12 @@
icon_state = "tan_suit"
item_state = "tan_suit"
/obj/item/clothing/under/suit/charismatic_suit
name = "charismatic suit"
desc = "Luck is for losers, baby."
icon_state = "charismatic_suit"
item_state = "charismatic_suit"
/obj/item/clothing/under/suit/white
name = "white suit"
desc = "A white suit and jacket with a blue shirt. You wanna play rough? OKAY!"
+12
View File
@@ -0,0 +1,12 @@
/datum/language/signlanguage
name = "Space Sign Language"
desc = "Those who cannot speak can learn this instead."
speech_verb = "signs"
whisper_verb = "gestures"
key = "9"
flags = TONGUELESS_SPEECH
syllables = list(".")
icon_state = "ssl"
default_priority = 90
@@ -11,6 +11,10 @@
bubble_icon = "alien"
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
/// Whether they can ventcrawl; this is set individually for 'humanoid' and 'royal' types
/// 'royal' types (Praetorian, Queen) cannot ventcrawl
var/can_ventcrawl
/// How much brute damage without armor piercing they do against mobs in melee
var/meleeSlashHumanPower = 20
/// How much power they have for DefaultCombatKnockdown when attacking humans
@@ -38,7 +42,8 @@
create_internal_organs()
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
if(can_ventcrawl)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
. = ..()
@@ -20,6 +20,8 @@
bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien,
/obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien)
can_ventcrawl = TRUE
//This is fine right now, if we're adding organ specific damage this needs to be updated
/mob/living/carbon/alien/humanoid/Initialize()
@@ -9,6 +9,7 @@
layer = LARGE_MOB_LAYER //above most mobs, but below speechbubbles
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 20, /obj/item/stack/sheet/animalhide/xeno = 3)
can_ventcrawl = FALSE
meleeKnockdownPower = 125
meleeSlashHumanPower = 30
@@ -281,11 +281,13 @@
dropItemToGround(pocket_item)
if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item))
pocket_item.forceMove(drop_location())
log_combat(usr, src, "pickpocketed of item: [pocket_item]")
else
if(place_item)
if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE))
usr.temporarilyRemoveItemFromInventory(place_item, TRUE)
equip_to_slot(place_item, pocket_id, TRUE)
log_combat(usr, src, "placed item [place_item] onto")
//do nothing otherwise
// Update strip window
@@ -293,8 +295,9 @@
show_inv(usr)
else
// Display a warning if the user mocks up
if (!strip_silence)
if(!strip_silence)
to_chat(src, "<span class='warning'>You feel your [pocket_side] pocket being fumbled with!</span>")
log_combat(usr, src, "failed to [pocket_item ? "pickpocket item [pocket_item] from" : "place item [place_item] onto "]")
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY, null, FALSE))
// separate from first canusetopic
+2
View File
@@ -10,6 +10,8 @@
/mob/living/carbon/can_speak_vocal(message)
if(silent)
return 0
if(get_message_language(message) == /datum/language/signlanguage && (handcuffed || (!src.get_bodypart(BODY_ZONE_L_ARM) && !src.get_bodypart(BODY_ZONE_R_ARM)) || get_num_held_items() == held_items.len))
return 0
return ..()
/mob/living/carbon/could_speak_language(datum/language/language)
+1 -1
View File
@@ -866,7 +866,7 @@
if(istype(G))
strip_mod = G.strip_mod
strip_silence = G.strip_silence
if (!strip_silence)
if(!strip_silence)
who.visible_message("<span class='danger'>[src] tries to remove [who]'s [what.name].</span>", \
"<span class='userdanger'>[src] tries to remove your [what.name].</span>", target = src,
target_message = "<span class='danger'>You try to remove [who]'s [what.name].</span>")
+28 -5
View File
@@ -2,7 +2,7 @@
/**
* Determines if we can actively parry.
*/
/obj/item/proc/can_active_parry()
/obj/item/proc/can_active_parry(mob/user)
return block_parry_data && (item_flags & ITEM_CAN_PARRY)
/**
@@ -29,7 +29,7 @@
var/datum/block_parry_data/data
var/datum/tool
var/method
if(using_item?.can_active_parry())
if(using_item?.can_active_parry(src))
data = using_item.block_parry_data
method = ITEM_PARRY
tool = using_item
@@ -50,9 +50,20 @@
using_item = backup
method = ITEM_PARRY
var/list/other_items = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START)
var/list/override = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items, override) & COMPONENT_PREVENT_PARRY_START)
to_chat(src, "<span class='warning'>Something is preventing you from parrying!</span>")
return
if(length(override))
var/datum/thing = override[1]
var/_method = override[thing]
if(_method == ITEM_PARRY)
using_item = thing
method = ITEM_PARRY
data = using_item.block_parry_data
else if(_method == UNARMED_PARRY)
method = UNARMED_PARRY
data = thing
if(!using_item && !method && length(other_items))
using_item = other_items[1]
method = ITEM_PARRY
@@ -94,7 +105,7 @@
*/
/mob/living/proc/find_backup_parry_item()
for(var/obj/item/I in held_items - get_active_held_item())
if(I.can_active_parry())
if(I.can_active_parry(src))
return I
/**
@@ -231,7 +242,7 @@
var/efficiency = data.get_parry_efficiency(attack_type, get_parry_time())
switch(parrying)
if(ITEM_PARRY)
if(!active_parry_item.can_active_parry())
if(!active_parry_item.can_active_parry(src))
return BLOCK_NONE
. = active_parry_item.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time())
if(UNARMED_PARRY)
@@ -243,6 +254,18 @@
if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now.
return
. |= BLOCK_SHOULD_PARTIAL_MITIGATE
if(efficiency >= data.parry_efficiency_perfect)
. |= data.perfect_parry_block_return_flags
if(data.perfect_parry_block_return_list)
return_list |= data.perfect_parry_block_return_list
else if(efficiency >= data.parry_efficiency_considered_successful)
. |= data.imperfect_parry_block_return_flags
if(data.imperfect_parry_block_return_list)
return_list |= data.imperfect_parry_block_return_list
else
. |= data.failed_parry_block_return_flags
if(data.failed_parry_block_return_list)
return_list |= data.failed_parry_block_return_list
if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence.
return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now.
if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0))
@@ -157,6 +157,16 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!!
var/parry_failed_cooldown_duration = 0 SECONDS
// Advanced
/// Flags added to return value
var/perfect_parry_block_return_flags = NONE
var/imperfect_parry_block_return_flags = NONE
var/failed_parry_block_return_flags = NONE
/// List appended to block return
var/perfect_parry_block_return_list
var/imperfect_parry_block_return_list
var/failed_parry_block_return_list
/**
* Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag.
*/
+1 -1
View File
@@ -329,7 +329,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
if(HAS_TRAIT(src, TRAIT_MUTE))
if(HAS_TRAIT(src, TRAIT_MUTE) && get_message_language(message) != /datum/language/signlanguage)
return 0
if(is_muzzled())
@@ -12,6 +12,7 @@
name = "\improper Nanotrasen Saber SMG"
desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors."
icon_state = "saber"
fire_sound = "sound/weapons/gunshot_smg_alt.ogg"
mag_type = /obj/item/ammo_box/magazine/smgm9mm
pin = null
@@ -125,6 +126,7 @@
desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG."
icon_state = "wt550"
item_state = "arg"
fire_sound = "sound/weapons/gunshot_smg_alt.ogg"
mag_type = /obj/item/ammo_box/magazine/wt550m9
can_suppress = FALSE
burst_size = 2
@@ -138,6 +140,10 @@
. = ..()
spread = 15
/obj/item/gun/ballistic/automatic/wt550/afterattack()
. = ..()
empty_alarm()
/obj/item/gun/ballistic/automatic/wt550/disable_burst()
. = ..()
spread = 0
@@ -158,7 +164,7 @@
icon_state = "m90"
item_state = "m90"
mag_type = /obj/item/ammo_box/magazine/m556
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_sound = 'sound/weapons/rifleshot.ogg'
can_suppress = FALSE
automatic_burst_overlay = FALSE
var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
@@ -243,7 +249,7 @@
item_state = "arg"
slot_flags = 0
mag_type = /obj/item/ammo_box/magazine/m556
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_sound = 'sound/weapons/rifleshot.ogg'
can_suppress = FALSE
burst_size = 3
burst_shot_delay = 1
@@ -258,7 +264,7 @@
w_class = WEIGHT_CLASS_NORMAL
weapon_weight = WEAPON_MEDIUM
mag_type = /obj/item/ammo_box/magazine/m12g
fire_sound = 'sound/weapons/gunshot.ogg'
fire_sound = 'sound/weapons/gunshotshotgunshot.ogg'
automatic_burst_overlay = FALSE
can_suppress = FALSE
burst_size = 1
@@ -293,11 +299,11 @@
desc = "A heavily modified 1.95x129mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
icon_state = "l6closed100"
item_state = "l6closedmag"
fire_sound = "sound/weapons/lmgshot.ogg"
w_class = WEIGHT_CLASS_HUGE
slot_flags = 0
mag_type = /obj/item/ammo_box/magazine/mm195x129
weapon_weight = WEAPON_HEAVY
fire_sound = 'sound/weapons/gunshot_smg.ogg'
var/cover_open = FALSE
can_suppress = FALSE
burst_size = 3
@@ -363,6 +369,7 @@
desc = "A long ranged weapon that does significant damage. No, you can't quickscope."
icon_state = "sniper"
item_state = "sniper"
fire_sound = "sound/weapons/noscope.ogg"
recoil = 2
weapon_weight = WEAPON_HEAVY
mag_type = /obj/item/ammo_box/magazine/sniper_rounds
@@ -397,6 +404,7 @@
desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing."
icon_state = "surplus"
item_state = "moistnugget"
fire_sound = 'sound/weapons/rifleshot.ogg'
weapon_weight = WEAPON_HEAVY
mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
fire_delay = 30
@@ -35,7 +35,7 @@
name = "gyrojet pistol"
desc = "A prototype pistol designed to fire self propelled rockets."
icon_state = "gyropistol"
fire_sound = 'sound/weapons/grenadelaunch.ogg'
fire_sound = 'sound/weapons/rocketlaunch.ogg'
mag_type = /obj/item/ammo_box/magazine/m75
burst_size = 1
fire_delay = 0
@@ -138,7 +138,7 @@
can_suppress = FALSE
w_class = WEIGHT_CLASS_NORMAL
actions_types = list()
fire_sound = 'sound/weapons/blastcannon.ogg'
fire_sound = 'sound/weapons/noscope.ogg'
spread = 20 //damn thing has no rifling.
automatic_burst_overlay = FALSE
@@ -3,6 +3,7 @@
desc = "A suspicious revolver. Uses .357 ammo." //usually used by syndicates
icon_state = "revolver"
mag_type = /obj/item/ammo_box/magazine/internal/cylinder
fire_sound = "sound/weapons/revolvershot.ogg"
casing_ejector = FALSE
/obj/item/gun/ballistic/revolver/Initialize()
@@ -3,6 +3,7 @@
desc = "A traditional shotgun with wood furniture and a four-shell capacity underneath."
icon_state = "shotgun"
item_state = "shotgun"
fire_sound = "sound/weapons/gunshotshotgunshot.ogg"
w_class = WEIGHT_CLASS_BULKY
force = 10
flags_1 = CONDUCT_1
+3 -3
View File
@@ -973,10 +973,8 @@
for(var/A in cached_reagents)
var/datum/reagent/R = A
if (R.type == reagent)
if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
pH = REAGENT_NORMAL_PH
//In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people.
else if (!ignore_pH)
if(!ignore_pH)
//if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7)))
pH = (((pH - R.pH) / total_volume) * amount) + pH
if(istype(my_atom, /obj/item/reagent_containers/))
@@ -987,6 +985,8 @@
amount = clamp(amount, 0, R.volume)
R.volume -= amount
update_total()
if(total_volume <= 0)//Because this can result in 0, I don't want it to crash.
pH = REAGENT_NORMAL_PH
if(!safety)//So it does not handle reactions when it need not to
handle_reactions()
if(my_atom)
@@ -24,9 +24,11 @@
circuit = /obj/item/circuitboard/machine/chem_dispenser
var/obj/item/stock_parts/cell/cell
var/powerefficiency = 0.0666666
var/dispenceUnit = 5
var/amount = 30
var/recharge_amount = 10
var/recharge_counter = 0
var/canStore = TRUE//If this can hold reagents or not
var/mutable_appearance/beaker_overlay
var/working_state = "dispenser_working"
var/nopower_state = "dispenser_nopower"
@@ -102,6 +104,7 @@
if(upgrade_reagents3)
upgrade_reagents3 = sortList(upgrade_reagents3, /proc/cmp_reagents_asc)
dispensable_reagents = sortList(dispensable_reagents, /proc/cmp_reagents_asc)
create_reagents(200, NO_REACT)
update_icon()
/obj/machinery/chem_dispenser/Destroy()
@@ -190,24 +193,27 @@
data["amount"] = amount
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
data["maxEnergy"] = cell.maxcharge * powerefficiency
data["storedVol"] = reagents.total_volume
data["maxVol"] = reagents.maximum_volume
data["isBeakerLoaded"] = beaker ? 1 : 0
data["stepAmount"] = dispenceUnit
data["canStore"] = canStore
var/beakerContents[0]
var/beakerCurrentVolume = 0
if(beaker && beaker.reagents && beaker.reagents.reagent_list.len)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = round(R.volume, 0.01)))) // list in a list because Byond merges the first list...
beakerCurrentVolume += R.volume
data["beakerContents"] = beakerContents
if (beaker)
data["beakerCurrentVolume"] = beakerCurrentVolume
data["beakerCurrentVolume"] = round(beakerCurrentVolume, 0.01)
data["beakerMaxVolume"] = beaker.volume
data["beakerTransferAmounts"] = beaker.possible_transfer_amounts
data["beakerCurrentpH"] = beaker.reagents.pH
//pH accuracy
for(var/obj/item/stock_parts/capacitor/C in component_parts)
data["partRating"]= 10**(C.rating-1)
data["beakerCurrentpH"] = round(beaker.reagents.pH, 10**-(C.rating+1))
else
data["beakerCurrentVolume"] = null
@@ -225,11 +231,17 @@
var/chemname = temp.name
if(is_hallucinating && prob(5))
chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name))))
chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "pH" = temp.pH, "pHCol" = ConvertpHToCol(temp.pH))))
data["chemicals"] = chemicals
data["recipes"] = saved_recipes
data["recordingRecipe"] = recording_recipe
var/storedContents[0]
if(reagents.total_volume)
for(var/datum/reagent/N in reagents.reagent_list)
storedContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume)))
data["storedContents"] = storedContents
return data
/obj/machinery/chem_dispenser/ui_act(action, params)
@@ -240,10 +252,9 @@
if(!is_operational() || QDELETED(beaker))
return
var/target = text2num(params["target"])
if(target in beaker.possible_transfer_amounts)
amount = target
work_animation()
. = TRUE
SetAmount(target)
work_animation()
. = TRUE
if("dispense")
if(!is_operational() || QDELETED(cell))
return
@@ -269,10 +280,9 @@
if(!is_operational() || recording_recipe)
return
var/amount = text2num(params["amount"])
if(beaker && (amount in beaker.possible_transfer_amounts))
beaker.reagents.remove_all(amount)
work_animation()
. = TRUE
beaker.reagents.remove_all(amount) //This should be set correctly in "amount"
work_animation()
. = TRUE
if("eject")
replace_beaker(usr)
. = TRUE
@@ -350,6 +360,52 @@
recording_recipe = null
. = TRUE
//Storing and unstoring reagents
if("store")
if(!is_operational() || QDELETED(cell))
return
if(!beaker)
return
if(recording_recipe)
say("Cannot store while recording!")
return
if(beaker.reagents.fermiIsReacting)
say("Cannot store ongoing reactions!")
return
var/reagent = text2path(params["id"])
var/datum/reagent/R = beaker.reagents.has_reagent(reagent)
var/potentialAmount = min(amount, R.volume)
if(reagents.total_volume+potentialAmount > reagents.maximum_volume)
say("Not enough storage space left!")
return
beaker.reagents.trans_id_to(src, R.type, potentialAmount)
work_animation()
. = TRUE
if("unstore")
if(!is_operational() || QDELETED(cell))
return
if(!beaker)
return
if(recording_recipe)
say("Cannot distribute while recording!")
return
var/reagent = text2path(params["id"])
var/datum/reagent/R = reagents.has_reagent(reagent)
reagents.trans_id_to(beaker, R.type, amount)
work_animation()
. = TRUE
/obj/machinery/chem_dispenser/proc/SetAmount(inputAmount)
if(inputAmount % 5 == 0) //Always allow 5u values
amount = inputAmount
return
inputAmount -= inputAmount % dispenceUnit
if(inputAmount == 0) //Prevent ghost entries in macros
amount = dispenceUnit
return
amount = inputAmount
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
if(default_unfasten_wrench(user, I))
return
@@ -402,6 +458,8 @@
cell = P
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
newpowereff += 0.0166666666*M.rating
if(reagents)
reagents.maximum_volume = 200*(M.rating)
for(var/obj/item/stock_parts/capacitor/C in component_parts)
recharge_amount *= C.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
@@ -411,6 +469,15 @@
dispensable_reagents |= upgrade_reagents2
if(M.rating > 3)
dispensable_reagents |= upgrade_reagents3
switch(M.rating)
if(-INFINITY to 1)
dispenceUnit = 5
if(2)
dispenceUnit = 3
if(3)
dispenceUnit = 2
if(4 to INFINITY)
dispenceUnit = 1
powerefficiency = round(newpowereff, 0.01)
/obj/machinery/chem_dispenser/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
@@ -421,6 +488,8 @@
user.put_in_hands(B)
if(new_beaker)
beaker = new_beaker
if(amount > beaker.reagents.maximum_volume)
amount = beaker.reagents.maximum_volume
else
beaker = null
update_icon()
@@ -439,6 +508,32 @@
replace_beaker(user)
return TRUE
/obj/machinery/chem_dispenser/proc/ConvertpHToCol(pH)
switch(pH)
if(-INFINITY to 1)
return "red"
if(1 to 2)
return "orange"
if(2 to 3)
return "average"
if(3 to 4)
return "yellow"
if(4 to 5)
return "olive"
if(5 to 6)
return "good"
if(6 to 8)
return "green"
if(8 to 9.5)
return "teal"
if(9.5 to 11)
return "blue"
if(11 to 12.5)
return "violet"
if(12.5 to INFINITY)
return "purple"
/obj/machinery/chem_dispenser/drinks/Initialize()
. = ..()
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE)
@@ -466,6 +561,7 @@
b_o.pixel_x = rand(-9, 9)
return b_o
/obj/machinery/chem_dispenser/drinks
name = "soda dispenser"
desc = "Contains a large reservoir of soft drinks."
@@ -479,6 +575,7 @@
working_state = null
nopower_state = null
pass_flags = PASSTABLE
canStore = FALSE
dispensable_reagents = list(
/datum/reagent/water,
/datum/reagent/consumable/ice,
@@ -611,12 +708,14 @@
dispensable_reagents = list(/datum/reagent/toxin/mutagen)
upgrade_reagents = null
emagged_reagents = list(/datum/reagent/toxin/plasma)
canStore = FALSE
/obj/machinery/chem_dispenser/mutagensaltpeter
name = "botanical chemical dispenser"
desc = "Creates and dispenses chemicals useful for botany."
flags_1 = NODECONSTRUCT_1
canStore = FALSE
dispensable_reagents = list(
/datum/reagent/toxin/mutagen,
@@ -739,6 +838,7 @@
working_state = "minidispenser_working"
nopower_state = "minidispenser_nopower"
circuit = /obj/item/circuitboard/machine/chem_dispenser/apothecary
canStore = FALSE
powerefficiency = 0.0833333
dispensable_reagents = list( //radium and stable plasma moved to upgrade tier 1 and 2, they've little to do with most medicines anyway.
/datum/reagent/hydrogen,
@@ -126,7 +126,7 @@
var beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume, "purity" = R.purity))) // list in a list because Byond merges the first list...
beakerContents.Add(list(list("name" = R.name, "volume" = round(R.volume, 0.01), "purity" = round(R.purity, 0.01)))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
return data
@@ -184,13 +184,13 @@
var/beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list...
beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
var/bufferContents[0]
if(reagents.total_volume)
for(var/datum/reagent/N in reagents.reagent_list)
bufferContents.Add(list(list("name" = N.name, "id" = ckey(N.name), "volume" = N.volume))) // ^
bufferContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume))) // ^
data["bufferContents"] = bufferContents
//Calculated at init time as it never changes
@@ -216,7 +216,7 @@
if(action == "transfer")
if(!beaker)
return FALSE
var/reagent = GLOB.name2reagent[params["id"]]
var/reagent = text2path(params["id"])
var/amount = text2num(params["amount"])
var/to_container = params["to"]
// Custom amount
@@ -386,7 +386,7 @@
if(action == "analyze")
// var/datum/reagent/R = GLOB.name2reagent[params["id"]]
var/reagent = GLOB.name2reagent[params["id"]]
var/reagent = text2path(params["id"])
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent]
if(R)
var/state = "Unknown"
@@ -405,7 +405,7 @@
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity)
screen = "analyze"
return TRUE
@@ -116,7 +116,10 @@
holder.remove_reagent(id, added_volume*temp_ratio)
if(St.purity < 1)
St.volume *= St.purity
added_volume *= St.purity
St.purity = 1
if(!N)
return
var/amount = clamp(0.002, 0, N.volume)
N.volume -= amount
St.data["grown_volume"] = St.data["grown_volume"] + added_volume
@@ -469,6 +469,10 @@
qdel(src)
return ..()
/datum/status_effect/stabilized/Destroy()
linked_extract = null
return ..()
/datum/status_effect/stabilized/null //This shouldn't ever happen, but just in case.
id = "stabilizednull"
@@ -884,7 +888,8 @@
/datum/status_effect/stabilized/oil/tick()
if(owner.stat == DEAD)
explosion(get_turf(owner),1,2,4,flame_range = 5)
owner.remove_status_effect(/datum/status_effect/stabilized/oil)
qdel(linked_extract)
return
return ..()
/datum/status_effect/stabilized/black
+1
View File
@@ -25,6 +25,7 @@
/datum/language/slime,
/datum/language/vampiric,
/datum/language/dwarf,
/datum/language/signlanguage,
))
healing_factor = STANDARD_ORGAN_HEALING*5 //Fast!!
decay_factor = STANDARD_ORGAN_DECAY/2
@@ -104,3 +104,10 @@
desc = "An eyepatch that connects itself to your eye socket, enhancing your shooting to an impossible degree, allowing your bullets to ricochet far more often than usual."
item = /obj/item/clothing/glasses/eyepatch/syndicate
cost = 8
/datum/uplink_item/device_tools/ablative_armwraps
name = "Ablative Armwraps"
desc = "A pair of highly reinforced armwraps allowing the user to parry almost anything. Fully reflects projectiles, no downsides to failing, but is very hard to parry melee with."
cost = 6
item = /obj/item/clothing/gloves/fingerless/ablative
exclude_modes = list(/datum/game_mode/nuclear)
+4
View File
@@ -31,7 +31,10 @@
/obj/item/clothing/under/suit/burgundy = 3,
/obj/item/clothing/under/suit/charcoal = 3,
/obj/item/clothing/under/suit/white = 3,
/obj/item/clothing/under/suit/tan = 3,
/obj/item/clothing/under/suit/charismatic_suit = 3,
/obj/item/clothing/under/costume/kilt = 3,
/obj/item/clothing/suit/suspenders = 3,
/obj/item/clothing/under/misc/overalls = 3,
/obj/item/clothing/under/suit/sl = 3,
/obj/item/clothing/accessory/sweater = 3,
@@ -70,6 +73,7 @@
/obj/item/clothing/accessory/suitjacket/burgundy = 2,
/obj/item/clothing/accessory/suitjacket/checkered = 2,
/obj/item/clothing/suit/jacket/miljacket = 5,
/obj/item/clothing/suit/jacket/urbanjacket = 5,
/obj/item/clothing/under/suit/white_on_white/skirt = 2,
/obj/item/clothing/under/rank/captain/suit/skirt = 2,
/obj/item/clothing/under/rank/civilian/head_of_personnel/suit/skirt = 2,
+1
View File
@@ -207,6 +207,7 @@
product_ads = "You turn me TRUE, use defines!;0110001101101100011011110111010001101000011001010111001101101000011001010111001001100101"
vend_reply = "Thank you for using the RoboDrobe!"
products = list(/obj/item/clothing/glasses/hud/diagnostic = 3,
/obj/item/stack/medical/nanogel = 5,
/obj/item/clothing/head/beret/robo = 3,
/obj/item/clothing/under/rank/rnd/roboticist = 3,
/obj/item/clothing/under/rank/rnd/roboticist/sleek = 3,
+109
View File
@@ -50,6 +50,115 @@
-->
<div class="commit sansserif">
<h2 class="date">11 February 2021</h2>
<h3 class="author">Adelphon updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Charismatic Suit</li>
<li class="rscadd">Urban Jacket</li>
</ul>
<h3 class="author">DeltaFire15 updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Added nanogel to the robodrobe.</li>
</ul>
<h3 class="author">Putnam3145 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Config to keep unreadied players from mode voting</li>
</ul>
<h3 class="author">dzahlus updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixes grenadelaunch.ogg being used where it shouldn't and makes mech weapons use correct sound</li>
</ul>
<h3 class="author">keronshb updated:</h3>
<ul class="changes bgimages16">
<li class="balance">10 > 30 second for Warp Implant cooldown</li>
<li class="rscdel">Comments out power sink objective.</li>
</ul>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">persistent blood should stop being invisible and alt clicking it shouldn't return the entire spritesheet</li>
<li class="admin">pickpocketing is now logged using log_combat</li>
</ul>
<h3 class="author">zeroisthebiggay updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">the aesthetic sterile mask no longer hides faces so you can cosplay egirls and keep flavortexts</li>
</ul>
<h2 class="date">09 February 2021</h2>
<h3 class="author">Chiirno updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Adds clown waddle to clown shoes. Enhanced Clown Waddle Dampeners can be engaged in-hand with ctrl+click, _but why would you?_</li>
</ul>
<h3 class="author">MrJWhit updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Re-adds theater disposal outlet, and makes dorms disposal able to have things sent to it on boxstation.</li>
</ul>
<h3 class="author">TyrianTyrell updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">made default tongue able to speak signed language.</li>
</ul>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">
<li class="balance">sentient viruses can now infect synths and ipcs</li>
</ul>
<h2 class="date">07 February 2021</h2>
<h3 class="author">Thalpy updated:</h3>
<ul class="changes bgimages16">
<li class="refactor">Dispenser: Adds the ability to store a small amount of reagents in the machine itself for dispensing. Reacting recipies cannot be stored. Size of storage increases with bin size.</li>
<li class="refactor">Dispenser: Allows reagents to be color coded by pH</li>
<li class="refactor">Dispenser: Each reagent displays it's pH on hover</li>
<li class="refactor">Dispenser: Allows the user to toggle between buttons and a radial dial</li>
<li class="refactor">Dispenser: When the dispencer is upgraded it can dispense 5/3/2/1 volumes based on rating refactor: Dispenser: as it was before. This does not break recorded recipes.</li>
<li class="tweak">Adds a round function to some numbers so they're not huge</li>
<li class="tweak">The Chem master can now get purity for all reagents when analysed</li>
<li class="bugfix">Synthissue fixes</li>
<li class="tweak">buffers now have a strong and weak variant. Weak can be dispensed, and strong can be created. Strong buffers are 6x more effective.</li>
<li class="bugfix">Some buffer pH edge calculation fixes</li>
</ul>
<h3 class="author">TyrianTyrell updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">added a signed language, that can't be used over the radio but can be used if you're mute. also added the multilingual trait.</li>
<li class="imageadd">hopefully added an icon for the signed language.</li>
<li class="code_imp">changed how some traits function slightly.</li>
</ul>
<h3 class="author">dzahlus updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">tweaked a few sounds</li>
<li class="soundadd">added a new weapon sounds</li>
<li class="sounddel">removed old weapon sounds</li>
<li class="code_imp">changed some sound related code</li>
</ul>
<h3 class="author">silicons updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">syndicate ablative armwraps have been added.</li>
</ul>
<h2 class="date">05 February 2021</h2>
<h3 class="author">SmArtKar updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">The orbit menu now has an Auto-Observe button! No more sifting through the lame observe menu to snoop in people's backpacks! Also, orbit menu now refreshes.</li>
<li class="bugfix">KAs are no longer getting broken when fired by a circuit</li>
</ul>
<h3 class="author">keronshb updated:</h3>
<ul class="changes bgimages16">
<li class="balance">Force and damage > 15 from 18/25</li>
<li class="balance">Knockdown put down to 5 from 30</li>
<li class="balance">Armor pen down to 10 from 100.</li>
<li class="balance">Makes cell chargers, charge faster.</li>
</ul>
<h3 class="author">raspy-on-osu updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">alien royals can no longer ventcrawl</li>
</ul>
<h3 class="author">shellspeed1 updated:</h3>
<ul class="changes bgimages16">
<li class="balance">There actually needs to be people for zombies to happen now.</li>
</ul>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">dwarf facial hair is no longer randomised</li>
</ul>
<h2 class="date">03 February 2021</h2>
<h3 class="author">Hatterhat updated:</h3>
<ul class="changes bgimages16">
+77
View File
@@ -28368,3 +28368,80 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2021-02-03:
Hatterhat:
- bugfix: The green energy sabre's sprite now respects proper handedness.
2021-02-05:
SmArtKar:
- rscadd: The orbit menu now has an Auto-Observe button! No more sifting through
the lame observe menu to snoop in people's backpacks! Also, orbit menu now refreshes.
- bugfix: KAs are no longer getting broken when fired by a circuit
keronshb:
- balance: Force and damage > 15 from 18/25
- balance: Knockdown put down to 5 from 30
- balance: Armor pen down to 10 from 100.
- balance: Makes cell chargers, charge faster.
raspy-on-osu:
- bugfix: alien royals can no longer ventcrawl
shellspeed1:
- balance: There actually needs to be people for zombies to happen now.
timothyteakettle:
- rscadd: dwarf facial hair is no longer randomised
2021-02-07:
Thalpy:
- refactor: 'Dispenser: Adds the ability to store a small amount of reagents in
the machine itself for dispensing. Reacting recipies cannot be stored. Size
of storage increases with bin size.'
- refactor: 'Dispenser: Allows reagents to be color coded by pH'
- refactor: 'Dispenser: Each reagent displays it''s pH on hover'
- refactor: 'Dispenser: Allows the user to toggle between buttons and a radial dial'
- refactor: 'Dispenser: When the dispencer is upgraded it can dispense 5/3/2/1 volumes
based on rating refactor: Dispenser: as it was before. This does not break recorded
recipes.'
- tweak: Adds a round function to some numbers so they're not huge
- tweak: The Chem master can now get purity for all reagents when analysed
- bugfix: Synthissue fixes
- tweak: buffers now have a strong and weak variant. Weak can be dispensed, and
strong can be created. Strong buffers are 6x more effective.
- bugfix: Some buffer pH edge calculation fixes
TyrianTyrell:
- rscadd: added a signed language, that can't be used over the radio but can be
used if you're mute. also added the multilingual trait.
- imageadd: hopefully added an icon for the signed language.
- code_imp: changed how some traits function slightly.
dzahlus:
- tweak: tweaked a few sounds
- soundadd: added a new weapon sounds
- sounddel: removed old weapon sounds
- code_imp: changed some sound related code
silicons:
- rscadd: syndicate ablative armwraps have been added.
2021-02-09:
Chiirno:
- rscadd: Adds clown waddle to clown shoes. Enhanced Clown Waddle Dampeners can
be engaged in-hand with ctrl+click, _but why would you?_
MrJWhit:
- rscadd: Re-adds theater disposal outlet, and makes dorms disposal able to have
things sent to it on boxstation.
TyrianTyrell:
- bugfix: made default tongue able to speak signed language.
timothyteakettle:
- balance: sentient viruses can now infect synths and ipcs
2021-02-11:
Adelphon:
- rscadd: Charismatic Suit
- rscadd: Urban Jacket
DeltaFire15:
- tweak: Added nanogel to the robodrobe.
Putnam3145:
- rscadd: Config to keep unreadied players from mode voting
dzahlus:
- bugfix: fixes grenadelaunch.ogg being used where it shouldn't and makes mech weapons
use correct sound
keronshb:
- balance: 10 > 30 second for Warp Implant cooldown
- rscdel: Comments out power sink objective.
timothyteakettle:
- bugfix: persistent blood should stop being invisible and alt clicking it shouldn't
return the entire spritesheet
- admin: pickpocketing is now logged using log_combat
zeroisthebiggay:
- tweak: the aesthetic sterile mask no longer hides faces so you can cosplay egirls
and keep flavortexts
@@ -1,4 +0,0 @@
author: "shellspeed1"
delete-after: True
changes:
- balance: "There actually needs to be people for zombies to happen now."
@@ -1,4 +0,0 @@
author: "SmArtKar"
delete-after: True
changes:
- rscadd: "The orbit menu now has an Auto-Observe button! No more sifting through the lame observe menu to snoop in people's backpacks! Also, orbit menu now refreshes."
@@ -1,4 +0,0 @@
author: "SmArtKar"
delete-after: True
changes:
- bugfix: "KAs are no longer getting broken when fired by a circuit"
@@ -1,4 +0,0 @@
author: "keronshb"
delete-after: True
changes:
- balance: "Makes cell chargers, charge faster."
@@ -1,6 +0,0 @@
author: "keronshb"
delete-after: True
changes:
- balance: "Force and damage > 15 from 18/25"
- balance: "Knockdown put down to 5 from 30"
- balance: "Armor pen down to 10 from 100."
@@ -1,4 +0,0 @@
author: "timothyteakettle"
delete-after: True
changes:
- rscadd: "dwarf facial hair is no longer randomised"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 KiB

After

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 KiB

After

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

@@ -537,4 +537,9 @@
path = /obj/item/clothing/suit/custom/exo
ckeywhitelist = list("jesterz7")
/datum/gear/donator/choker
name = "NT Choker"
slot = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/choker
ckeywhitelist = list("trigillass")
@@ -159,6 +159,11 @@
path = /obj/item/clothing/suit/jacket/miljacket
subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
/datum/gear/suit/urbanjacket
name = "Urban Jacket"
path = /obj/item/clothing/suit/jacket/urbanjacket
subcategory = LOADOUT_SUBCATEGORY_SUIT_JACKETS
/datum/gear/suit/ianshirt
name = "Ian Shirt"
path = /obj/item/clothing/suit/ianshirt
@@ -32,6 +32,10 @@
name = "Tan suit"
path = /obj/item/clothing/under/suit/tan
/datum/gear/uniform/suit/charismatic_suit
name = "Charismatic suit"
path = /obj/item/clothing/under/suit/charismatic_suit
/datum/gear/uniform/suit/white
name = "White suit"
path = /obj/item/clothing/under/suit/white
@@ -585,3 +585,12 @@
icon = 'icons/obj/custom.dmi'
mob_overlay_icon = 'icons/mob/clothing/custom_w.dmi'
mutantrace_variation = NONE
/obj/item/clothing/neck/petcollar/choker
name = "NT Choker"
desc = "NT property since January 21st, 2562."
icon = 'icons/obj/custom.dmi'
icon_state = "choker"
mob_overlay_icon = 'icons/mob/clothing/custom_w.dmi'
item_state = "choker"
tagname = null
@@ -9,7 +9,7 @@
item_state = "arg"
slot_flags = 0
mag_type = /obj/item/ammo_box/magazine/m556 //Uses the m90gl's magazine, just like the NT-ARG
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_sound = 'sound/weapons/rifleshot.ogg'
can_suppress = 0
burst_size = 6 //in line with XCOMEU stats. This can fire 5 bursts from a full magazine.
fire_delay = 1
@@ -85,23 +85,20 @@
///projectiles///
/obj/item/projectile/bullet/cflechetteap //shreds armor
/obj/item/projectile/bullet/cflechetteap //shreds armor but no wounds
name = "flechette (armor piercing)"
damage = 8
armour_penetration = 80
damage = 15
armour_penetration = 100
wound_bonus = -100
/obj/item/projectile/bullet/cflechettes //shreds flesh and forces bleeding
/obj/item/projectile/bullet/cflechettes //causes wounds fast but is heavily countered by armor
name = "flechette (serrated)"
damage = 15
dismemberment = 10
armour_penetration = -80
/obj/item/projectile/bullet/cflechettes/on_hit(atom/target, blocked = FALSE)
if((blocked != 100) && iscarbon(target))
var/mob/living/carbon/C = target
C.bleed(10)
return ..()
wound_bonus = 15
sharpness = SHARP_EDGED
wound_falloff_tile = 0
///ammo casings (CASELESS AMMO CASINGS WOOOOOOOO)///
/obj/item/ammo_casing/caseless/flechetteap
@@ -148,7 +145,7 @@
slot_flags = 0
pin = /obj/item/firing_pin/implant/pindicate
mag_type = /obj/item/ammo_box/magazine/flechette
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_sound = 'sound/weapons/rifleshot.ogg'
can_suppress = 0
burst_size = 5
fire_delay = 1
@@ -168,15 +165,19 @@
///unique variant///
/obj/item/projectile/bullet/cflechetteshredder
/obj/item/projectile/bullet/cflechetteshredder //you only get this with a 30TC bundle,5 magazines, as such this should be the superior ammotype
name = "flechette (shredder)"
damage = 5
dismemberment = 40
damage = 10
dismemberment = 50
wound_bonus = 50
armour_penetration = 100
sharpness = SHARP_EDGED
wound_falloff_tile = 0
/obj/item/ammo_casing/caseless/flechetteshredder
name = "flechette (shredder)"
desc = "A serrated flechette made of a special alloy that forms a monofilament edge."
projectile_type = /obj/item/projectile/bullet/cflechettes
projectile_type = /obj/item/projectile/bullet/cflechetteshredder
/obj/item/ammo_box/magazine/flechette/shredder
name = "flechette magazine (shredder)"
@@ -185,7 +186,7 @@
/obj/item/gun/ballistic/automatic/flechette/shredder
name = "\improper CX Shredder"
desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofilament flechettes."
w_class = WEIGHT_CLASS_SMALL
spread = 15
recoil = 0.1
@@ -334,39 +334,75 @@
holder.clear_reagents()
/datum/reagent/fermi/acidic_buffer
name = "Acidic buffer"
name = "Strong acidic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards acidity when added to another."
color = "#fbc314"
pH = 0
chemical_flags = REAGENT_FORCEONNEW
can_synth = TRUE
var/strength = 1.5
//Consumes self on addition and shifts pH
/datum/reagent/fermi/acidic_buffer/on_new(datapH)
if(!holder)
return ..()
if(holder.reagents_holder_flags & NO_REACT)
return..()
if(holder.has_reagent(/datum/reagent/stabilizing_agent))
return ..()
data = datapH
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
if(holder.pH < pH)
holder.my_atom.visible_message("<span class='warning'>The beaker fizzes as the buffer is added, to no effect.</b></span>")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
return ..()
holder.pH = clamp((((holder.pH * (holder.total_volume-(volume*strength)))+(pH * (volume*strength)) )/holder.total_volume), 0, 14) //This is BEFORE removal
holder.my_atom.visible_message("<span class='warning'>The beaker fizzes as the pH changes!</b></span>")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
..()
/datum/reagent/fermi/acidic_buffer/weak
name = "Acidic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards acidity when added to another."
color = "#fbf344"
pH = 4
can_synth = TRUE
strength = 0.25
/datum/reagent/fermi/basic_buffer
name = "Basic buffer"
name = "Strong basic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards alkalinity when added to another."
color = "#3853a4"
pH = 14
chemical_flags = REAGENT_FORCEONNEW
can_synth = TRUE
var/strength = 1.5
/datum/reagent/fermi/basic_buffer/weak
name = "Basic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards alkalinity when added to another."
color = "#5873c4"
pH = 10
can_synth = TRUE
strength = 0.25
/datum/reagent/fermi/basic_buffer/on_new(datapH)
if(!holder)
return ..()
if(holder.reagents_holder_flags & NO_REACT)
return..()
if(holder.has_reagent(/datum/reagent/stabilizing_agent))
return ..()
data = datapH
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
if(holder.pH > pH)
holder.my_atom.visible_message("<span class='warning'>The beaker froths as the buffer is added, to no effect.</b></span>")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
return ..()
holder.pH = clamp((((holder.pH * (holder.total_volume-(volume*strength)))+(pH * (volume*strength)) )/holder.total_volume), 0, 14) //This is BEFORE removal
holder.my_atom.visible_message("<span class='warning'>The beaker froths as the pH changes!</b></span>")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -504,6 +504,7 @@
#include "code\datums\components\twohanded.dm"
#include "code\datums\components\uplink.dm"
#include "code\datums\components\virtual_reality.dm"
#include "code\datums\components\waddling.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm"
#include "code\datums\components\crafting\crafting.dm"
@@ -2336,6 +2337,7 @@
#include "code\modules\language\mushroom.dm"
#include "code\modules\language\narsian.dm"
#include "code\modules\language\ratvarian.dm"
#include "code\modules\language\signlanguage.dm"
#include "code\modules\language\slime.dm"
#include "code\modules\language\swarmer.dm"
#include "code\modules\language\sylvan.dm"
+159 -38
View File
@@ -1,13 +1,20 @@
import { toFixed } from 'common/math';
import { toTitleCase } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section } from '../components';
import { useBackend, useLocalState } from '../backend';
import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section, Table, NumberInput } from '../components';
import { Window } from '../layouts';
export const ChemDispenser = (props, context) => {
const { act, data } = useBackend(context);
const recording = !!data.recordingRecipe;
const [hasCol, setHasCol] = useLocalState(
context, 'fs_title', false);
const [modeToggle, setModeToggle] = useLocalState(
context, 'mode_toggle', true);
const {
storedContents = [],
} = data;
// TODO: Change how this piece of shit is built on server side
// It has to be a list, not a fucking OBJECT!
const recipes = Object.keys(data.recipes)
@@ -28,17 +35,27 @@ export const ChemDispenser = (props, context) => {
return (
<Window
width={565}
height={620}
height={data.canStore ? 720 : 620}
resizable>
<Window.Content scrollable>
<Section
title="Status"
buttons={recording && (
<Box inline mx={1} color="red">
<Icon name="circle" mr={1} />
Recording
</Box>
)}>
buttons={
[(recording && (
<Box inline mx={1} color="red">
<Icon name="circle" mr={1} />
Recording
</Box>
)),
<Button // eslint-disable-line
key="colorButton"
icon="cog"
disabled={!data.isBeakerLoaded}
tooltip="Alternate between buttons and radial input"
tooltipPosition="bottom-left"
selected={modeToggle}
onClick={() => setModeToggle(!modeToggle)} />]
}>
<LabeledList>
<LabeledList.Item label="Energy">
<ProgressBar
@@ -103,18 +120,40 @@ export const ChemDispenser = (props, context) => {
</Box>
</Section>
<Section
key="dispense"
title="Dispense"
buttons={(
beakerTransferAmounts.map(amount => (
<Button
key={amount}
icon="plus"
selected={amount === data.amount}
content={amount}
onClick={() => act('amount', {
target: amount,
})} />
))
[modeToggle ? (
beakerTransferAmounts.map(amount => (
<Button
key={amount}
icon="plus"
selected={amount === data.amount}
content={amount}
onClick={() => act('amount', {
target: amount,
})} />
))) : (!!data.isBeakerLoaded
&& <NumberInput
key="dispenseInput"
width="65px"
unit="u"
step={data.stepAmount}
stepPixelSize={data.stepAmount}
disabled={!data.isBeakerLoaded}
value={data.amount}
minValue={1}
maxValue={data.beakerMaxVolume}
onDrag={(e, amount) => act('amount', {
target: amount,
})} />),
<Button // eslint-disable-line
key="colorButton"
icon="cog"
tooltip="Color code the reagents by pH"
tooltipPosition="bottom-left"
selected={hasCol}
onClick={() => setHasCol(!hasCol)} />]
)}>
<Box mr={-1}>
{data.chemicals.map(chemical => (
@@ -124,12 +163,40 @@ export const ChemDispenser = (props, context) => {
width="129.5px"
lineHeight={1.75}
content={chemical.title}
tooltip={"pH: " + chemical.pH}
backgroundColor={hasCol ? chemical.pHCol : "primary"}
onClick={() => act('dispense', {
reagent: chemical.id,
})} />
))}
</Box>
</Section>
{!!data.canStore && (
<Section
title="Storage"
buttons={
<Box>
Transfer amount:
<AnimatedNumber
initial={5}
value={data.amount} />
u
</Box>
}>
<ProgressBar
value={data.storedVol / data.maxVol}>
{toFixed(data.storedVol) + ' units / ' + data.maxVol + ' units'}
</ProgressBar>
<ChemicalBuffer>
{storedContents.map(chemical => (
<ChemicalBufferEntry
key={chemical.id}
chemical={chemical}
transferTo="beaker" />
))}
</ChemicalBuffer>
</Section>
)}
<Section
title="Beaker"
buttons={(
@@ -155,14 +222,14 @@ export const ChemDispenser = (props, context) => {
{recording
&& 'Virtual beaker'
|| data.isBeakerLoaded
&& (
<Fragment>
<AnimatedNumber
initial={0}
value={data.beakerCurrentVolume} />
/{data.beakerMaxVolume} units
</Fragment>
)
&& (
<Fragment>
<AnimatedNumber
initial={0}
value={data.beakerCurrentVolume} />
/{data.beakerMaxVolume} units
</Fragment>
)
|| 'No beaker'}
</LabeledList.Item>
<LabeledList.Item
@@ -171,17 +238,14 @@ export const ChemDispenser = (props, context) => {
{(!data.isBeakerLoaded && !recording) && 'N/A'
|| beakerContents.length === 0 && 'Nothing'}
</Box>
{beakerContents.map(chemical => (
<Box
key={chemical.name}
color="label">
<AnimatedNumber
initial={0}
value={chemical.volume} />
{' '}
units of {chemical.name}
</Box>
))}
<ChemicalBeaker>
{beakerContents.map(chemical => (
<ChemicalBeakerEntry
key={chemical.id}
chemical={chemical}
transferTo="beaker" />
))}
</ChemicalBeaker>
<Box
key={"pH"}>
pH:
@@ -196,3 +260,60 @@ export const ChemDispenser = (props, context) => {
</Window>
);
};
const ChemicalBuffer = Table;
const ChemicalBufferEntry = (props, context) => {
const { act, data } = useBackend(context);
const { chemical, transferTo } = props;
return (
<Table.Row key={chemical.id}>
<Table.Cell color="label">
<AnimatedNumber
value={chemical.volume}
initial={0} />
{` units of ${chemical.name}`}
</Table.Cell>
<Table.Cell collapsing>
<Button
content="Dispense"
icon="download"
disabled={!!data.recordingRecipe || !data.isBeakerLoaded}
mt={0.5}
onClick={() => act('unstore', {
id: chemical.id,
})} />
</Table.Cell>
</Table.Row>
);
};
const ChemicalBeaker = Table;
const ChemicalBeakerEntry = (props, context) => {
const { act, data } = useBackend(context);
const { chemical, transferTo } = props;
return (
<Table.Row key={chemical.id}>
<Table.Cell color="label">
<AnimatedNumber
value={chemical.volume}
initial={0} />
{` units of ${chemical.name}`}
</Table.Cell>
{!!data.canStore && (
<Table.Cell collapsing>
<Button
content="Store"
icon="upload"
disabled={!!data.recordingRecipe}
mt={0.5}
onClick={() => act('store', {
id: chemical.id,
})} />
</Table.Cell>
)}
</Table.Row>
);
};
+4 -4
View File
@@ -400,11 +400,11 @@ const AnalysisResults = (props, context) => {
<LabeledList.Item label="Addiction Threshold">
{analyzeVars.addicD}
</LabeledList.Item>
{!!fermianalyze && ( // why did you do that before? it's fucking bad.
<LabeledList.Item label="Purity">
{analyzeVars.purityF}
</LabeledList.Item>
{!! data.fermianalyze && ( // why did you do that before? it's bad.
<Fragment>
<LabeledList.Item label="Purity">
{analyzeVars.purityF}
</LabeledList.Item>
<LabeledList.Item label="Inverse Ratio">
{analyzeVars.inverseRatioF}
</LabeledList.Item>
File diff suppressed because one or more lines are too long