Merge remote-tracking branch 'origin/master' into hardsync-1.5

This commit is contained in:
Letter N
2021-02-12 13:18:09 +08:00
118 changed files with 1105 additions and 196 deletions

View File

@@ -881,7 +881,7 @@
/turf/open/floor/plating,
/area/awaymission/cabin)
"cT" = (
/obj/vehicle/ridden/atv,
/obj/vehicle/ridden/atv/snowmobile,
/turf/open/floor/plating{
icon_state = "platingdmg3"
},
@@ -893,7 +893,7 @@
/turf/open/floor/plating,
/area/awaymission/cabin)
"cV" = (
/obj/vehicle/ridden/atv,
/obj/vehicle/ridden/atv/snowmobile,
/turf/open/floor/plating,
/area/awaymission/cabin)
"cW" = (

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
@@ -58655,8 +58669,11 @@
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/door/airlock/vault,
/obj/effect/mapping_helpers/airlock/locked,
/obj/machinery/door/airlock/vault{
name = "Vault Door";
req_access_txt = "53"
},
/turf/open/floor/plasteel/dark,
/area/ai_monitored/nuke_storage)
"puh" = (
@@ -58822,6 +58839,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 +60885,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" = (
@@ -61051,7 +61078,6 @@
/area/science/circuit)
"uOJ" = (
/obj/effect/mapping_helpers/airlock/locked,
/obj/machinery/door/airlock/vault,
/obj/structure/cable{
icon_state = "1-2"
},
@@ -61065,6 +61091,10 @@
/obj/effect/turf_decal/tile/neutral{
dir = 8
},
/obj/machinery/door/airlock/vault{
name = "Vault Door";
req_access_txt = "53"
},
/turf/open/floor/plasteel/dark,
/area/ai_monitored/nuke_storage)
"uQR" = (
@@ -84618,7 +84648,7 @@ ayD
nez
ngV
xPY
aOH
pMQ
hcb
hcb
syJ
@@ -84875,7 +84905,7 @@ ayE
ayE
ayE
ayE
ayE
lLf
ayE
ayE
ayE
@@ -85132,7 +85162,7 @@ ayH
ayH
ayH
ayH
ayH
lqO
ayH
aFV
ayH

View File

@@ -47138,13 +47138,9 @@
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
"bEx" = (
/obj/structure/closet/radiation,
/obj/machinery/light/small{
dir = 1
},
/obj/structure/extinguisher_cabinet{
pixel_x = 26
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
},
@@ -48383,7 +48379,10 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/machinery/light/small,
/obj/structure/extinguisher_cabinet{
pixel_x = 26
},
/obj/structure/closet/radiation,
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
"bGg" = (
@@ -49543,6 +49542,9 @@
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 4
},
/obj/machinery/light/small{
dir = 4
},
/turf/open/floor/plasteel,
/area/engine/gravity_generator)
"bHV" = (

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!

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.

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)

View File

@@ -263,7 +263,7 @@ Turf and target are separate in case you want to teleport some distance from a t
return .
//Returns a list of all items of interest with their name
/proc/getpois(mobs_only=0,skip_mindless=0)
/proc/getpois(mobs_only = FALSE, skip_mindless = FALSE, specify_dead_role = TRUE)
var/list/mobs = sortmobs()
var/list/namecounts = list()
var/list/pois = list()
@@ -277,7 +277,7 @@ Turf and target are separate in case you want to teleport some distance from a t
if(M.real_name && M.real_name != M.name)
name += " \[[M.real_name]\]"
if(M.stat == DEAD)
if(M.stat == DEAD && specify_dead_role)
if(isobserver(M))
name += " \[ghost\]"
else

View File

@@ -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

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()

View File

@@ -146,9 +146,11 @@
if(!istype(A) || !get_turf(A) || A == src)
return
orbit_target = A
return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/atom/movable/proc/stop_orbit(datum/component/orbiter/orbits)
orbit_target = null
return // We're just a simple hook
/atom/proc/transfer_observers_to(atom/target)

View File

@@ -37,7 +37,7 @@
qdel(src)
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force)
handle_vehicle_offsets()
handle_vehicle_offsets(M.buckled?.dir)
/datum/component/riding/proc/handle_vehicle_layer(dir)
var/atom/movable/AM = parent

View File

@@ -11,6 +11,8 @@
var/antag_removal_text // Text will be given to the quirk holder if they get an antag that has it blacklisted.
var/mood_quirk = FALSE //if true, this quirk affects mood and is unavailable if moodlets are disabled
var/mob_trait //if applicable, apply and remove this mob trait
/// should we immediately call on_spawn or add a timer to trigger
var/on_spawn_immediate = TRUE
var/mob/living/quirk_holder
/datum/quirk/New(mob/living/quirk_mob, spawn_effects)
@@ -26,7 +28,10 @@
START_PROCESSING(SSquirks, src)
add()
if(spawn_effects)
on_spawn()
if(on_spawn_immediate)
on_spawn()
else
addtimer(CALLBACK(src, .proc/on_spawn), 0)
addtimer(CALLBACK(src, .proc/post_add), 30)
/datum/quirk/Destroy()

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)

View File

@@ -184,6 +184,7 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
gain_text = null // Handled by trauma.
lose_text = null
medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities."
on_spawn_immediate = FALSE
/datum/quirk/paraplegic/add()
var/datum/brain_trauma/severe/paralysis/paraplegic/T = new()

View File

@@ -99,6 +99,9 @@
///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy()
var/list/targeted_by
///Reference to atom being orbited
var/atom/orbit_target
/**
* Called when an atom is created in byond (built in engine proc)
*

View File

@@ -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>\

View File

@@ -10,7 +10,7 @@
circuit = /obj/item/circuitboard/machine/cell_charger
pass_flags = PASSTABLE
var/obj/item/stock_parts/cell/charging = null
var/charge_rate = 500
var/recharge_coeff = 1
/obj/machinery/cell_charger/update_overlays()
. += ..()
@@ -28,9 +28,10 @@
. = ..()
. += "There's [charging ? "a" : "no"] cell in the charger."
if(charging)
. += "Current charge: [round(charging.percent(), 1)]%."
var/obj/item/stock_parts/cell/C = charging.get_cell()
. += "Current charge: [C.percent()]%."
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Charge rate at <b>[charge_rate]J</b> per cycle.</span>"
. += "<span class='notice'>The status display reads: Charge rate at <b>[recharge_coeff*10]J</b> per cycle.</span>"
/obj/machinery/cell_charger/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stock_parts/cell) && !panel_open)
@@ -122,17 +123,18 @@
charging.emp_act(severity)
/obj/machinery/cell_charger/RefreshParts()
charge_rate = 500
for(var/obj/item/stock_parts/capacitor/C in component_parts)
charge_rate *= C.rating
recharge_coeff = C.rating
/obj/machinery/cell_charger/process()
if(!charging || !anchored || (stat & (BROKEN|NOPOWER)))
return
if(charging.percent() >= 100)
return
use_power(charge_rate)
charging.give(charge_rate) //this is 2558, efficient batteries exist
if(charging)
var/obj/item/stock_parts/cell/C = charging.get_cell()
if(C)
if(C.charge < C.maxcharge)
C.give(C.chargerate * recharge_coeff)
use_power(250 * recharge_coeff)
update_icon()

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 = ""

View File

@@ -393,6 +393,27 @@
spark_system.start() //creates some sparks because they look cool
qdel(cover) //deletes the cover - no need on keeping it there!
//turret healing
/obj/machinery/porta_turret/examine(mob/user)
. = ..()
if(obj_integrity < max_integrity)
. += "<span class='notice'>[src] is damaged, use a lit welder to fix it.</span>"
/obj/machinery/porta_turret/welder_act(mob/living/user, obj/item/I)
. = TRUE
if(cover && obj_integrity < max_integrity)
if(!I.tool_start_check(user, amount=0))
return
user.visible_message("[user] is welding the turret.", \
"<span class='notice'>You begin repairing the turret...</span>", \
"<span class='italics'>You hear welding.</span>")
if(I.use_tool(src, user, 40, volume=50))
obj_integrity = max_integrity
user.visible_message("[user.name] has repaired [src].", \
"<span class='notice'>You finish repairing the turret.</span>")
else
to_chat(user, "<span class='notice'>The turret doesn't need repairing.</span>")
/obj/machinery/porta_turret/process()
//the main machinery process
if(cover == null && anchored) //if it has no cover and is anchored

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

View File

@@ -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

View File

@@ -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))

View File

@@ -208,6 +208,8 @@
return
if(!M.IsVocal())
return
if(language == /datum/language/signlanguage)
return
if(use_command)
spans |= commandspan

View File

@@ -245,6 +245,9 @@
slowdown = 7
breakouttime = 300 //Deciseconds = 30s = 0.5 minute
/obj/item/restraints/legcuffs/proc/on_removed()
return
/obj/item/restraints/legcuffs/beartrap
name = "bear trap"
throw_speed = 1
@@ -376,4 +379,8 @@
icon_state = "ebola"
hitsound = 'sound/weapons/taserhit.ogg'
w_class = WEIGHT_CLASS_SMALL
breakouttime = 60
breakouttime = 25
/obj/item/restraints/legcuffs/bola/energy/on_removed()
do_sparks(1, TRUE, src)
qdel(src)

View File

@@ -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

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

View File

@@ -319,7 +319,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

View File

@@ -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()
..()

View File

@@ -105,6 +105,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
@@ -323,6 +325,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
@@ -2330,6 +2333,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)

View File

@@ -271,7 +271,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
loadout_data["SAVE_[i]"] = list()
for(var/some_gear_item in saved_loadout_paths)
if(!ispath(text2path(some_gear_item)))
message_admins("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path")
log_game("Failed to copy item [some_gear_item] to new loadout system when migrating from version [current_version] to 40, issue: item is not a path")
continue
var/datum/gear/gear_item = text2path(some_gear_item)
if(!(initial(gear_item.loadout_flags) & LOADOUT_CAN_COLOR_POLYCHROMIC))
@@ -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)

View File

@@ -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."

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

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."

View File

@@ -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."

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!"

View File

@@ -137,6 +137,10 @@
//Shooting Code:
A.preparePixelProjectile(target, src)
A.fire()
if(ismob(loc.loc))
installed_gun.shoot_live_shot(loc.loc)
else
installed_gun.shoot_live_shot() //Shitcode, but we don't have much of a choice
log_attack("[assembly] [REF(assembly)] has fired [installed_gun].")
return A

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

View File

@@ -522,7 +522,7 @@
max_charges = 1
item_flags = NEEDS_PERMIT | NOBLUDGEON
w_class = WEIGHT_CLASS_BULKY
force = 18
force = 15
/obj/item/ammo_casing/magic/hook
name = "hook"
@@ -536,11 +536,11 @@
icon_state = "hook"
icon = 'icons/obj/lavaland/artefacts.dmi'
pass_flags = PASSTABLE
damage = 25
armour_penetration = 100
damage = 15
armour_penetration = 10
knockdown = 5
damage_type = BRUTE
hitsound = 'sound/effects/splat.ogg'
knockdown = 30
var/chain
/obj/item/projectile/hook/fire(setAngle)

View File

@@ -556,7 +556,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/list/dest = list() //List of possible destinations (mobs)
var/target = null //Chosen target.
dest += getpois(mobs_only=1) //Fill list, prompt user with list
dest += getpois(mobs_only = TRUE) //Fill list, prompt user with list
target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest
if (!target)//Make sure we actually have a target
@@ -893,7 +893,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if (!eye_name)
return
var/mob/mob_eye = creatures[eye_name]
do_observe(creatures[eye_name])
/mob/dead/observer/proc/do_observe(mob/mob_eye)
//Istype so we filter out points of interest that are not mobs
if(client && mob_eye && istype(mob_eye))
client.eye = mob_eye

View File

@@ -1,5 +1,6 @@
/datum/orbit_menu
var/mob/dead/observer/owner
var/auto_observe = FALSE
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
@@ -10,6 +11,7 @@
return GLOB.observer_state
/datum/orbit_menu/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "Orbit")
ui.open()
@@ -18,15 +20,35 @@
if (..())
return
if (action == "orbit")
var/ref = params["ref"]
var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list)
if (poi != null)
switch(action)
if ("orbit")
var/ref = params["ref"]
var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list)
if (poi == null)
. = TRUE
return
owner.ManualFollow(poi)
owner.reset_perspective(null)
if (auto_observe)
owner.do_observe(poi)
. = TRUE
if ("refresh")
update_static_data(owner, ui)
. = TRUE
if ("toggle_observe")
auto_observe = !auto_observe
if (auto_observe && owner.orbit_target)
owner.do_observe(owner.orbit_target)
else
owner.reset_perspective(null)
/datum/orbit_menu/ui_data(mob/user)
var/list/data = list()
data["auto_observe"] = auto_observe
return data
/datum/orbit_menu/ui_static_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
@@ -34,7 +56,7 @@
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(skip_mindless = 1)
var/list/pois = getpois(skip_mindless = TRUE, specify_dead_role = FALSE)
for (var/name in pois)
var/list/serialized = list()
serialized["name"] = name
@@ -80,7 +102,7 @@
data["npcs"] = npcs
return data
/datum/orbit_menu/ui_assets()
. = ..() || list()
. += get_asset_datum(/datum/asset/simple/orbit)

View File

@@ -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)
. = ..()

View File

@@ -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()

View File

@@ -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

View File

@@ -434,6 +434,9 @@
legcuffed.forceMove(drop_location())
legcuffed = null
I.dropped(src)
if(istype(I, /obj/item/restraints/legcuffs))
var/obj/item/restraints/legcuffs/lgcf = I
lgcf.on_removed()
update_inv_legcuffed()
return
else

View File

@@ -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
@@ -938,43 +941,43 @@
admin_ticket_log(src, msg)
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
var/GS_needed = istype(target, /mob/living/silicon/pai)? GRAB_PASSIVE : GRAB_AGGRESSIVE
if(pulling == target && grab_state >= GS_needed && stat == CONSCIOUS)
//If they dragged themselves and we're currently aggressively grabbing them try to piggyback
if(user == target && can_piggyback(target))
piggyback(target)
return
//If you dragged them to you and you're aggressively grabbing try to fireman carry them
else if(user != target)
else if(user == src)
if(user.a_intent == INTENT_GRAB)
fireman_carry(target)
return
. = ..()
//src is the user that will be carrying, target is the mob to be carried
/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
return (istype(target) && target.stat == CONSCIOUS)
/mob/living/carbon/human/proc/can_piggyback(mob/living/target)
return (iscarbon(target) || ispAI(target)) && target.stat == CONSCIOUS
/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND))
return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND)) || ispAI(target)
/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
var/carrydelay = 50 //if you have latex you are faster at grabbing
var/skills_space = "" //cobby told me to do this
if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY))
carrydelay = 30
skills_space = "expertly"
skills_space = "expertly "
else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY))
carrydelay = 40
skills_space = "quickly"
skills_space = "quickly "
if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
visible_message("<span class='notice'>[src] starts [skills_space] lifting [target] onto their back..</span>",
visible_message("<span class='notice'>[src] starts [skills_space]lifting [target] onto their back..</span>",
//Joe Medic starts quickly/expertly lifting Grey Tider onto their back..
"<span class='notice'>[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space] start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]</span>")
"<span class='notice'>[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space]start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]</span>")
//(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...)
if(do_after(src, carrydelay, TRUE, target))
//Second check to make sure they're still valid to be carried
if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
target.set_resting(FALSE, TRUE)
buckle_mob(target, TRUE, TRUE, 90, 1, 0, TRUE)
return
visible_message("<span class='warning'>[src] fails to fireman carry [target]!")
@@ -992,13 +995,13 @@
if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
target.visible_message("<span class='warning'>[target] can't hang onto [src]!</span>")
return
buckle_mob(target, TRUE, TRUE, FALSE, 1, 2, FALSE)
buckle_mob(target, TRUE, TRUE, 0, 1, 2, FALSE)
else
visible_message("<span class='warning'>[target] fails to climb onto [src]!</span>")
else
to_chat(target, "<span class='warning'>You can't piggyback ride [src] right now!</span>")
/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0, fireman = FALSE)
/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = 0, hands_needed = 0, target_hands_needed = 0, fireman = FALSE)
if(!force)//humans are only meant to be ridden through piggybacking and special cases
return
if(!is_type_in_typecache(target, can_ride_typecache))
@@ -1010,6 +1013,9 @@
riding_datum.ride_check_rider_restrained = TRUE
if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
return
if(istype(target, /mob/living/silicon/pai))
hands_needed = 1
target_hands_needed = 0
var/equipped_hands_self
var/equipped_hands_target
if(hands_needed)

View File

@@ -71,7 +71,7 @@
var/list/datum/bioware = list()
var/creamed = FALSE //to use with creampie overlays
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot))
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot, /mob/living/silicon/pai))
var/lastpuke = 0
var/account_id
var/last_fire_update

View File

@@ -30,10 +30,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
/datum/species/dwarf/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
var/dwarf_hair = pick("Beard (Dwarf)", "Beard (Very Long)", "Beard (Long)") //beard roullette
var/mob/living/carbon/human/H = C
H.facial_hair_style = dwarf_hair
H.update_hair()
H.AddElement(/datum/element/dwarfism, COMSIG_SPECIES_LOSS, src)
RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used.

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)

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>")

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))

View File

@@ -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.
*/

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())

View File

@@ -143,6 +143,10 @@
custom_holoform.Grant(src)
emitter_next_use = world.time + 10 SECONDS
/mob/living/silicon/pai/deployed/Initialize()
. = ..()
fold_out(TRUE)
/mob/living/silicon/pai/ComponentInitialize()
. = ..()
if(possible_chassis[chassis])

View File

@@ -175,7 +175,7 @@
if("PRG_edit")
if(!computer || !authenticated || !target_id_card)
return
var/new_name = params["name"]
var/new_name = reject_bad_name(params["name"])
if(!new_name)
return
target_id_card.registered_name = new_name
@@ -190,7 +190,7 @@
return
if(target == "Custom")
var/custom_name = params["custom_name"]
var/custom_name = reject_bad_name(params["custom_name"])
if(custom_name)
target_id_card.assignment = custom_name
target_id_card.update_label()

View File

@@ -12,3 +12,7 @@
/datum/movespeed_modifier/reagent/nitryl
multiplicative_slowdown = -1
/datum/movespeed_modifier/reagent/meth
multiplicative_slowdown = -0.5
absolute_max_tiles_per_second = 11

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -504,6 +504,14 @@
glass_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland."
value = REAGENT_VALUE_COMMON
/datum/reagent/consumable/nuka_cola/on_mob_metabolize(mob/living/carbon/M)
M.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
return ..()
/datum/reagent/consumable/nuka_cola/on_mob_end_metabolize(mob/living/carbon/M)
M.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
return ..()
/datum/reagent/consumable/nuka_cola/on_mob_life(mob/living/carbon/M)
M.Jitter(20)
M.set_drugginess(30)

View File

@@ -174,11 +174,13 @@
ADD_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type)
L.update_movespeed()
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
/datum/reagent/drug/methamphetamine/on_mob_end_metabolize(mob/living/L)
REMOVE_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type)
L.update_movespeed()
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
..()
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)

View File

@@ -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

View File

@@ -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

View File

@@ -404,6 +404,7 @@
on_mob.set_light(1, 1, current_color_string)
/obj/effect/abstract/eye_lighting
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/obj/item/organ/eyes/robotic/glow/parent
/obj/effect/abstract/eye_lighting/Initialize()

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

View File

@@ -1,4 +1,5 @@
#define COOLDOWN_STUN 1200
#define COOLDOWN_KNOCKDOWN 600
#define COOLDOWN_DAMAGE 600
#define COOLDOWN_MEME 300
#define COOLDOWN_NONE 100
@@ -213,7 +214,6 @@
var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown")
var/static/regex/sleep_words = regex("sleep|slumber|rest")
var/static/regex/vomit_words = regex("vomit|throw up|sick")
var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush")
var/static/regex/hallucinate_words = regex("see the truth|hallucinate")
@@ -264,26 +264,20 @@
cooldown = COOLDOWN_STUN
for(var/V in listeners)
var/mob/living/L = V
L.Stun(60 * power_multiplier)
L.Stagger(60 * power_multiplier)
//KNOCKDOWN
else if(findtext(message, knockdown_words))
cooldown = COOLDOWN_STUN
cooldown = COOLDOWN_KNOCKDOWN
for(var/V in listeners)
var/mob/living/L = V
L.DefaultCombatKnockdown(60 * power_multiplier)
//SLEEP
else if((findtext(message, sleep_words)))
cooldown = COOLDOWN_STUN
for(var/mob/living/carbon/C in listeners)
C.Sleeping(40 * power_multiplier)
L.DefaultCombatKnockdown()
//VOMIT
else if((findtext(message, vomit_words)))
cooldown = COOLDOWN_STUN
cooldown = COOLDOWN_DAMAGE
for(var/mob/living/carbon/C in listeners)
C.vomit(10 * power_multiplier, distance = power_multiplier)
C.vomit(10 * power_multiplier, distance = power_multiplier, stun = FALSE)
//SILENCE
else if((findtext(message, silence_words)))

View File

@@ -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)

View File

@@ -102,6 +102,7 @@
along with slurred speech, aggression, and the ability to infect others with this agent."
item = /obj/item/storage/box/syndie_kit/romerol
cost = 25
player_minimum = 25
cant_discount = TRUE
exclude_modes = list(/datum/game_mode/nuclear)

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,

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,

View File

@@ -675,3 +675,6 @@ TURF_DIRT_THRESHOLD 100
## Default alpha of dirt on spawn
DIRT_ALPHA_STARTING 127
## Allows pAI custom holoforms
PAI_CUSTOM_HOLOFORMS

View File

@@ -50,6 +50,149 @@
-->
<div class="commit sansserif">
<h2 class="date">12 February 2021</h2>
<h3 class="author">Hatterhat updated:</h3>
<ul class="changes bgimages16">
<li class="balance">The ATVs on SnowCabin.dmm have been replaced with snowmobiles.</li>
</ul>
<h3 class="author">MrJWhit updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Random deltastation fixes.</li>
<li class="tweak">Gives boxstation vault door actual vault door access</li>
</ul>
<h3 class="author">silicons updated:</h3>
<ul class="changes bgimages16">
<li class="balance">Voice of God - sleep removed, stun staggers instead, knockdown is faster but does not do stamina damage, vomit is faster but doesn't stun</li>
</ul>
<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">
<li class="bugfix">The green energy sabre's sprite now respects proper handedness.</li>
</ul>
<h2 class="date">02 February 2021</h2>
<h3 class="author">silicons updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">pais can now be carried around piggybacking/fireman</li>
<li class="balance">Meth and Nuka Cola once again, speed you up.</li>
</ul>
<h2 class="date">31 January 2021</h2>
<h3 class="author">Putnam3145 updated:</h3>
<ul class="changes bgimages16">
<li class="balance">fermichem explosion EMPs don't cover the entire station</li>
</ul>
<h2 class="date">30 January 2021</h2>
<h3 class="author">timothyteakettle updated:</h3>
<ul class="changes bgimages16">

View File

@@ -28358,3 +28358,99 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
zeroisthebiggay:
- rscadd: some more FUCKING hairs
- imageadd: uncodersprites the advanced extinguisher
2021-01-31:
Putnam3145:
- balance: fermichem explosion EMPs don't cover the entire station
2021-02-02:
silicons:
- rscadd: pais can now be carried around piggybacking/fireman
- balance: Meth and Nuka Cola once again, speed you up.
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
2021-02-12:
Hatterhat:
- balance: The ATVs on SnowCabin.dmm have been replaced with snowmobiles.
MrJWhit:
- tweak: Random deltastation fixes.
- tweak: Gives boxstation vault door actual vault door access
silicons:
- balance: Voice of God - sleep removed, stun staggers instead, knockdown is faster
but does not do stamina damage, vomit is faster but doesn't stun

View File

@@ -0,0 +1,4 @@
author: "Hatterhat"
delete-after: True
changes:
- balance: "Energy bolas now take 2.5 seconds to remove and dissipate on removal."

View File

@@ -0,0 +1,4 @@
author: "timothyteakettle"
delete-after: True
changes:
- admin: "migration error to version 39+ of savefiles is now logged instead of messaging all online admins in the chat"

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: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 125 KiB

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -93,9 +93,8 @@
e.set_up(round((volume/28)*(pH-9)), T, 0, 0)
e.start()
if(!ImpureTot == 0) //If impure, v.small emp (0.6 or less)
ImpureTot *= volume
empulse(T, volume, 1)
if(ImpureTot) //If impure, v.small emp (0.6 or less)
empulse(T, ImpureTot, 1)
my_atom.reagents.clear_reagents() //just in case
return

Binary file not shown.

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