Merge remote-tracking branch 'upstream/master'
@@ -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!
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
12
code/modules/language/signlanguage.dm
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -938,43 +938,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 +992,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 +1010,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,6 +50,77 @@
|
||||
-->
|
||||
<div class="commit sansserif">
|
||||
|
||||
<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">
|
||||
|
||||
@@ -28361,3 +28361,55 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
|
||||
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.
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
@@ -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
|
||||
@@ -148,7 +148,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
BIN
sound/weapons/gunshot_smg_alt.ogg
Normal file
BIN
sound/weapons/gunshotshotgunshot.ogg
Normal file
BIN
sound/weapons/lmgshot.ogg
Normal file
BIN
sound/weapons/noscope.ogg
Normal file
BIN
sound/weapons/revolvershot.ogg
Normal file
BIN
sound/weapons/rifleshot.ogg
Normal file
@@ -2336,6 +2336,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"
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { createSearch } from 'common/string';
|
||||
import { multiline } from 'common/string';
|
||||
import { resolveAsset } from '../assets';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Box, Button, Flex, Icon, Input, Section } from '../components';
|
||||
import { Box, Button, Divider, Flex, Icon, Input, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const PATTERN_DESCRIPTOR = / \[(?:ghost|dead)\]$/;
|
||||
const PATTERN_NUMBER = / \(([0-9]+)\)$/;
|
||||
|
||||
const searchFor = searchText => createSearch(searchText, thing => thing.name);
|
||||
@@ -43,7 +43,7 @@ const BasicSection = (props, context) => {
|
||||
{things.map(thing => (
|
||||
<Button
|
||||
key={thing.name}
|
||||
content={thing.name.replace(PATTERN_DESCRIPTOR, "")}
|
||||
content={thing.name}
|
||||
onClick={() => act("orbit", {
|
||||
ref: thing.ref,
|
||||
})} />
|
||||
@@ -82,6 +82,7 @@ export const Orbit = (props, context) => {
|
||||
const {
|
||||
alive,
|
||||
antagonists,
|
||||
auto_observe,
|
||||
dead,
|
||||
ghosts,
|
||||
misc,
|
||||
@@ -140,6 +141,27 @@ export const Orbit = (props, context) => {
|
||||
onInput={(_, value) => setSearchText(value)}
|
||||
onEnter={(_, value) => orbitMostRelevant(value)} />
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Divider vertical />
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Button
|
||||
inline
|
||||
color="transparent"
|
||||
tooltip={multiline`Toggle Auto-Observe. When active, you'll
|
||||
see the UI / full inventory of whoever you're orbiting. Neat!`}
|
||||
tooltipPosition="bottom-left"
|
||||
selected={auto_observe}
|
||||
icon={auto_observe ? "toggle-on" : "toggle-off"}
|
||||
onClick={() => act("toggle_observe")} />
|
||||
<Button
|
||||
inline
|
||||
color="transparent"
|
||||
tooltip="Refresh"
|
||||
tooltipPosition="bottom-left"
|
||||
icon="sync-alt"
|
||||
onClick={() => act("refresh")} />
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
{antagonists.length > 0 && (
|
||||
@@ -161,7 +183,7 @@ export const Orbit = (props, context) => {
|
||||
</Section>
|
||||
)}
|
||||
|
||||
<Section title="Alive">
|
||||
<Section title={`Alive - (${alive.length})`}>
|
||||
{alive
|
||||
.filter(searchFor(searchText))
|
||||
.sort(compareNumberedText)
|
||||
@@ -174,7 +196,7 @@ export const Orbit = (props, context) => {
|
||||
</Section>
|
||||
|
||||
<BasicSection
|
||||
title="Ghosts"
|
||||
title={`Ghosts - (${ghosts.length})`}
|
||||
source={ghosts}
|
||||
searchText={searchText}
|
||||
/>
|
||||
|
||||