Merge remote-tracking branch 'citadel/master' into unarmed_parry
@@ -69,7 +69,7 @@
|
||||
/turf/open/floor/plasteel/white,
|
||||
/area/ruin/space/has_grav/powered/ancient_shuttle)
|
||||
"j" = (
|
||||
/obj/machinery/computer/prototype_cloning,
|
||||
/obj/machinery/computer/cloning/prototype,
|
||||
/obj/machinery/light{
|
||||
dir = 1
|
||||
},
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//// COOLDOWN SYSTEMS
|
||||
/*
|
||||
* We have 2 cooldown systems: timer cooldowns (divided between stoppable and regular) and world.time cooldowns.
|
||||
*
|
||||
* When to use each?
|
||||
*
|
||||
* * Adding a commonly-checked cooldown, like on a subsystem to check for processing
|
||||
* * * Use the world.time ones, as they are cheaper.
|
||||
*
|
||||
* * Adding a rarely-used one for special situations, such as giving an uncommon item a cooldown on a target.
|
||||
* * * Timer cooldown, as adding a new variable on each mob to track the cooldown of said uncommon item is going too far.
|
||||
*
|
||||
* * Triggering events at the end of a cooldown.
|
||||
* * * Timer cooldown, registering to its signal.
|
||||
*
|
||||
* * Being able to check how long left for the cooldown to end.
|
||||
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
|
||||
*
|
||||
* * Being able to stop the timer before it ends.
|
||||
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Cooldown system based on an datum-level associative lazylist using timers.
|
||||
*/
|
||||
|
||||
//INDEXES
|
||||
#define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet"
|
||||
|
||||
|
||||
//TIMER COOLDOWN MACROS
|
||||
|
||||
#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]"
|
||||
#define COMSIG_CD_RESET(cd_index) "cd_reset_[cd_index]"
|
||||
|
||||
#define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time))
|
||||
|
||||
#define TIMER_COOLDOWN_CHECK(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index)
|
||||
|
||||
#define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index)
|
||||
|
||||
/*
|
||||
* Stoppable timer cooldowns.
|
||||
* Use indexes the same as the regular tiemr cooldowns.
|
||||
* They make use of the TIMER_COOLDOWN_CHECK() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one.
|
||||
* A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked.
|
||||
*/
|
||||
|
||||
#define S_TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, /proc/end_cooldown, cd_source, cd_index), cd_time, TIMER_STOPPABLE))
|
||||
|
||||
#define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index)
|
||||
|
||||
#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_CHECK(cd_source, cd_index)))
|
||||
|
||||
|
||||
/*
|
||||
* Cooldown system based on storing world.time on a variable, plus the cooldown time.
|
||||
* Better performance over timer cooldowns, lower control. Same functionality.
|
||||
*/
|
||||
|
||||
#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0
|
||||
|
||||
#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + cd_time)
|
||||
|
||||
//Returns true if the cooldown has run its course, false otherwise
|
||||
#define COOLDOWN_FINISHED(cd_source, cd_index) (cd_source.cd_index < world.time)
|
||||
|
||||
#define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0
|
||||
|
||||
#define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time))
|
||||
@@ -224,6 +224,11 @@
|
||||
#define COMSIG_LIVING_RUN_BLOCK "living_do_run_block" //from base of mob/living/do_run_block(): (real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone)
|
||||
#define COMSIG_LIVING_GET_BLOCKING_ITEMS "get_blocking_items" //from base of mob/living/get_blocking_items(): (list/items)
|
||||
|
||||
#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 COMPONENT_PREVENT_PARRY_START 1
|
||||
|
||||
//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
|
||||
#define COMSIG_LIVING_STATUS_STUN "living_stun" //from base of mob/living/Stun() (amount, update, ignore)
|
||||
#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown" //from base of mob/living/Knockdown() (amount, update, ignore)
|
||||
|
||||
@@ -115,3 +115,7 @@
|
||||
//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
|
||||
#define PLANT_GENE_REMOVABLE (1<<0)
|
||||
#define PLANT_GENE_EXTRACTABLE (1<<1)
|
||||
|
||||
#define CLONEPOD_GET_MIND 1
|
||||
#define CLONEPOD_POLL_MIND 2
|
||||
#define CLONEPOD_NO_MIND 3
|
||||
@@ -8,12 +8,6 @@
|
||||
/// Levels
|
||||
#define SKILL_PROGRESSION_LEVEL 4
|
||||
|
||||
|
||||
/// Max value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MAX 100
|
||||
/// Min value of skill for numerical skills
|
||||
#define SKILL_NUMERICAL_MIN 0
|
||||
|
||||
// Standard values for job starting skills
|
||||
|
||||
#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX
|
||||
@@ -26,6 +20,13 @@
|
||||
|
||||
#define DEF_SKILL_GAIN 1
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
#define STD_USE_TOOL_MULT 1
|
||||
#define EASY_USE_TOOL_MULT 0.75
|
||||
#define TRIVIAL_USE_TOOL_MULT 0.5
|
||||
#define BARE_USE_TOOL_MULT 0.25
|
||||
|
||||
//multiplier of the difference of max_value and min_value. Mostly for balance purposes between numerical and level-based skills.
|
||||
#define STD_NUM_SKILL_ITEM_GAIN_MULTI 0.002
|
||||
|
||||
//An extra point for each few seconds of delay when using a tool. Before the multiplier.
|
||||
#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
if(totitemdamage)
|
||||
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
|
||||
if(!(SKILL_TRAIN_ATTACK_OBJ in I.used_skills[skill]))
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, I.skill_gain)
|
||||
|
||||
@@ -192,9 +192,10 @@
|
||||
if(.)
|
||||
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
|
||||
if(!(SKILL_TRAIN_ATTACK_MOB in I.used_skills[skill]))
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, I.skill_gain)
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
user.mind.auto_gain_experience(skill, I.skill_gain*S.item_skill_gain_multi)
|
||||
|
||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||
|
||||
@@ -102,9 +102,8 @@
|
||||
//stops TK grabs being equipped anywhere but into hands
|
||||
/obj/item/tk_grab/equipped(mob/user, slot)
|
||||
if(slot == SLOT_HANDS)
|
||||
return
|
||||
return ..()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/tk_grab/examine(user)
|
||||
if (focus)
|
||||
|
||||
@@ -25,4 +25,23 @@
|
||||
/datum/config_entry/string/medal_hub_address
|
||||
|
||||
/datum/config_entry/string/medal_hub_password
|
||||
protection = CONFIG_ENTRY_HIDDEN
|
||||
protection = CONFIG_ENTRY_HIDDEN
|
||||
|
||||
/datum/config_entry/keyed_list/cross_server_bunker_override
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_TEXT
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
/datum/config_entry/keyed_list/cross_server_bunker_override/ValidateAndSet(str_val)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/list/newv = list()
|
||||
for(var/I in config_entry_value)
|
||||
newv[replacetext(I, "+", " ")] = config_entry_value[I]
|
||||
config_entry_value = newv
|
||||
|
||||
/datum/config_entry/keyed_list/cross_server_bunker_override/ValidateListEntry(key_name, key_value)
|
||||
return key_value != "byond:\\address:port" && ..()
|
||||
|
||||
/datum/config_entry/flag/allow_cross_server_bunker_override
|
||||
protection = CONFIG_ENTRY_LOCKED
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
k// PARTS //
|
||||
// PARTS //
|
||||
/obj/item/weaponcrafting
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
|
||||
@@ -8,61 +8,33 @@ k// PARTS //
|
||||
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 6)
|
||||
icon_state = "riflestock"
|
||||
|
||||
/obj/item/weaponcrafting/durathread_string
|
||||
name = "durathread string"
|
||||
desc = "A long piece of durathread with some resemblance to cable coil."
|
||||
/obj/item/weaponcrafting/string
|
||||
name = "wound thread"
|
||||
desc = "A long piece of thread with some resemblance to cable coil."
|
||||
icon_state = "durastring"
|
||||
|
||||
////////////////////////////////
|
||||
// KAT IMPROVISED WEAPON PARTS//
|
||||
// IMPROVISED WEAPON PARTS//
|
||||
////////////////////////////////
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts
|
||||
name = "Eerie bunch of coloured dots."
|
||||
desc = "You feel the urge to report to Central that the parent type of guncrafting, which should never appear in this reality, has appeared. Whatever that means."
|
||||
name = "Debug Improvised Gun Part"
|
||||
desc = "A badly coded gun part. You should report coders if you see this."
|
||||
icon = 'icons/obj/guns/gun_parts.dmi'
|
||||
icon_state = "palette"
|
||||
|
||||
// BARRELS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
name = "rifle barrel"
|
||||
desc = "A pipe with a diameter just the right size to fire 7.62 rounds out of."
|
||||
icon_state = "barrel_rifle"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
name = "shotgun barrel"
|
||||
desc = "A twenty bore shotgun barrel."
|
||||
icon_state = "barrel_shotgun"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_pistol
|
||||
name = "pistol barrel"
|
||||
desc = "A pipe with a small diameter and some holes finely cut into it. It fits .32 ACP bullets. Probably."
|
||||
icon_state = "barrel_pistol"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
name = "bolt action receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle. It's generic enough to modify to create other rifles, potentially."
|
||||
name = "rifle receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_rifle"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver
|
||||
name = "pistol receiver"
|
||||
desc = "A receiver to connect house and connects all the parts to make an improvised pistol."
|
||||
icon_state = "receiver_pistol"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/laser_receiver
|
||||
name = "energy emitter assembly"
|
||||
desc = "A mixture of components haphazardly wired together to form an energy emitter."
|
||||
icon_state = "laser_assembly"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
name = "break-action assembly"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun. Parts of this are still useful if you want to make another type of shotgun, however."
|
||||
name = "shotgun reciever"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_shotgun"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -78,15 +50,3 @@ k// PARTS //
|
||||
name = "wooden firearm body"
|
||||
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
|
||||
icon_state = "wooden_body"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_grip
|
||||
name = "wooden pistol grip"
|
||||
desc = "A nice wooden grip hollowed out for pistol magazines."
|
||||
icon_state = "wooden_pistolgrip"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens
|
||||
name = "makeshift focusing lens"
|
||||
desc = "A properly made lens made with actual glassworking tools would perform much better, but this will have to do."
|
||||
icon_state = "focusing_lens"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
/datum/crafting_recipe/bone_bow
|
||||
name = "Bone Bow"
|
||||
result = /obj/item/gun/ballistic/bow/ashen
|
||||
time = 200
|
||||
time = 120 // 80+120 = 200
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 8,
|
||||
/obj/item/stack/sheet/sinew = 4)
|
||||
@@ -112,7 +112,7 @@
|
||||
/datum/crafting_recipe/bow_tablet
|
||||
name = "Sandstone Bow Making Manual"
|
||||
result = /obj/item/book/granter/crafting_recipe/bone_bow
|
||||
time = 600 //Scribing
|
||||
time = 200 //Scribing // don't care
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/rods = 1,
|
||||
/obj/item/stack/sheet/mineral/sandstone = 4)
|
||||
|
||||
@@ -192,8 +192,8 @@
|
||||
result = /obj/item/gun/ballistic/bow/pipe
|
||||
reqs = list(/obj/item/pipe = 5,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/weaponcrafting/durathread_string = 5)
|
||||
time = 450
|
||||
/obj/item/weaponcrafting/string = 5)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
@@ -248,10 +248,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun
|
||||
/datum/crafting_recipe/ishotgun // smaller and more versatile gun requires some better materials
|
||||
name = "Improvised Shotgun"
|
||||
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 1,
|
||||
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -262,10 +262,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/irifle
|
||||
/datum/crafting_recipe/irifle // larger and less versatile gun, but a bit easier to make
|
||||
name = "Improvised Rifle (7.62mm)"
|
||||
result = /obj/item/gun/ballistic/shotgun/boltaction/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 1,
|
||||
reqs = list(/obj/item/pipe = 2, // above
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -276,49 +276,6 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ipistol
|
||||
name = "Improvised Pistol (.32)"
|
||||
result = /obj/item/gun/ballistic/automatic/pistol/improvised/nomag
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_grip = 1,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_WIRECUTTER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ilaser
|
||||
name = "Improvised Energy Gun"
|
||||
result = /obj/item/gun/energy/e_gun/old/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 1,
|
||||
/obj/item/stock_parts/cell = 1,
|
||||
/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 5,
|
||||
/obj/item/stack/cable_coil = 10)
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ilaser/upgraded
|
||||
name = "Improvised Energy Gun Upgrade"
|
||||
result = /obj/item/gun/energy/e_gun/old/improvised/upgraded
|
||||
reqs = list(/obj/item/gun/energy/e_gun/old/improvised = 1,
|
||||
/obj/item/glasswork/glass_base/lens = 1,
|
||||
/obj/item/stock_parts/capacitor/quadratic = 2,
|
||||
/obj/item/stock_parts/micro_laser/ultra = 1,
|
||||
/obj/item/stock_parts/cell/bluespace = 1,
|
||||
/obj/item/stack/cable_coil = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
//////////////////
|
||||
///AMMO CRAFTING//
|
||||
//////////////////
|
||||
@@ -326,9 +283,9 @@
|
||||
/datum/crafting_recipe/arrow
|
||||
name = "Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/wood
|
||||
time = 30
|
||||
time = 5 // these only do 15 damage
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
|
||||
/obj/item/stack/sheet/durathread = 1,
|
||||
/obj/item/stack/sheet/cloth = 1,
|
||||
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
@@ -336,7 +293,7 @@
|
||||
/datum/crafting_recipe/bone_arrow
|
||||
name = "Bone Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/bone
|
||||
time = 30
|
||||
time = 5
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 1,
|
||||
/obj/item/stack/sheet/sinew = 1,
|
||||
@@ -348,7 +305,7 @@
|
||||
name = "Ashen Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/ash
|
||||
tools = list(TOOL_WELDER)
|
||||
time = 30
|
||||
time = 10 // 1.5 seconds minimum per actually worthwhile arrow excluding interface lag
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/ammo_casing/caseless/arrow/wood = 1)
|
||||
category = CAT_WEAPONRY
|
||||
@@ -442,92 +399,28 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
|
||||
/datum/crafting_recipe/m32acp
|
||||
name = ".32ACP Empty Magazine"
|
||||
result = /obj/item/ammo_box/magazine/m32acp/empty
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/stack/sheet/plasteel = 1,
|
||||
/obj/item/stack/packageWrap = 1)
|
||||
tools = list(TOOL_WELDER,TOOL_SCREWDRIVER)
|
||||
time = 5
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
|
||||
////////////////////
|
||||
// PARTS CRAFTING //
|
||||
////////////////////
|
||||
|
||||
// BARRELS
|
||||
|
||||
/datum/crafting_recipe/rifle_barrel
|
||||
name = "Improvised Rifle Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_barrel
|
||||
name = "Improvised Shotgun Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/pistol_barrel
|
||||
name = "Improvised Pistol Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_pistol
|
||||
reqs = list(/obj/item/pipe = 1,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/datum/crafting_recipe/rifle_receiver
|
||||
name = "Improvised Rifle Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15) // you can carry multiple shotguns
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 50
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_receiver
|
||||
name = "Improvised Shotgun Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Dual wielding has been removed, plasteel is a soft timesink to obtain for most to make mass production harder.
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/pistol_receiver
|
||||
name = "Improvised Pistol Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/pistol_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 5,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_SAW)
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/laser_receiver
|
||||
name = "Energy Weapon Assembly"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/laser_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stock_parts/capacitor = 2,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/assembly/prox_sensor = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WELDER) // Prox sensor and multitool for the circuit board, welder for extremely ghetto soldering.
|
||||
time = 150
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1) // requires access or hacking since shotgun is better
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -539,16 +432,6 @@
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/makeshift_lens
|
||||
name = "Makeshift Lens"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/makeshift_lens
|
||||
reqs = list(/obj/item/stack/sheet/metal = 1,
|
||||
/obj/item/stack/sheet/glass = 2)
|
||||
tools = list(TOOL_WELDER) // Glassmaking lets you make non-makeshift lenses.
|
||||
time = 50
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
///Lazy associative list of currently active cooldowns.
|
||||
var/list/cooldowns
|
||||
|
||||
#ifdef TESTING
|
||||
var/running_find_references
|
||||
var/last_find_references = 0
|
||||
@@ -201,3 +204,34 @@
|
||||
qdel(D)
|
||||
else
|
||||
return returned
|
||||
|
||||
/**
|
||||
* Callback called by a timer to end an associative-list-indexed cooldown.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - datum storing the cooldown
|
||||
* * index - string index storing the cooldown on the cooldowns associative list
|
||||
*
|
||||
* This sends a signal reporting the cooldown end.
|
||||
*/
|
||||
/proc/end_cooldown(datum/source, index)
|
||||
if(QDELETED(source))
|
||||
return
|
||||
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
|
||||
TIMER_COOLDOWN_END(source, index)
|
||||
|
||||
|
||||
/**
|
||||
* Proc used by stoppable timers to end a cooldown before the time has ran out.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - datum storing the cooldown
|
||||
* * index - string index storing the cooldown on the cooldowns associative list
|
||||
*
|
||||
* This sends a signal reporting the cooldown end, passing the time left as an argument.
|
||||
*/
|
||||
/proc/reset_cooldown(datum/source, index)
|
||||
if(QDELETED(source))
|
||||
return
|
||||
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
|
||||
TIMER_COOLDOWN_END(source, index)
|
||||
|
||||
@@ -678,7 +678,7 @@
|
||||
holder.update_transform()
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
if(features["body_size"] < danger)
|
||||
var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
var/slowdown = (1 - round(features["body_size"] / danger, 0.1)) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
|
||||
else if(old_size < danger)
|
||||
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride)
|
||||
|
||||
@@ -58,12 +58,10 @@
|
||||
var/datum/martial_art/boxing/style = new
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,TRUE)
|
||||
return
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -196,9 +196,8 @@
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@
|
||||
var/turf/ST = null
|
||||
var/falling = 0
|
||||
var/damage = damage_roll(A,D)
|
||||
|
||||
|
||||
for (var/obj/O in oview(1, A))
|
||||
if (O.density == 1)
|
||||
if (O == A)
|
||||
@@ -472,12 +472,10 @@
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_BELT)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_BELT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
. = list()
|
||||
.["playername"] = owner.name
|
||||
.["see_skill_mods"] = see_skill_mods
|
||||
.["admin"] = check_rights(R_DEBUG)
|
||||
.["admin"] = check_rights(R_DEBUG, FALSE)
|
||||
|
||||
/datum/skill_holder/ui_act(action, params)
|
||||
. = ..()
|
||||
|
||||
@@ -33,6 +33,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/base_multiplier = 1
|
||||
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
|
||||
var/competency_multiplier = 1
|
||||
/// Experience gain multiplier gained from using items.
|
||||
var/item_skill_gain_multi = 1
|
||||
/// Skill gain quantisation
|
||||
var/skill_gain_quantisation = 0.1
|
||||
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
|
||||
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
|
||||
/// Index of this skill in the UI
|
||||
@@ -108,6 +112,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
/// Min value of this skill
|
||||
var/min_value = 0
|
||||
|
||||
/datum/skill/numerical/New()
|
||||
..()
|
||||
skill_gain_quantisation = item_skill_gain_multi = item_skill_gain_multi * (max_value - min_value) * STD_NUM_SKILL_ITEM_GAIN_MULTI
|
||||
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
|
||||
@@ -91,10 +91,10 @@
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
value = S.sanitize_value(value)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
if(!isnull(value))
|
||||
LAZYINITLIST(skill_holder.skills)
|
||||
S.set_skill_value(skill_holder, value, src, silent)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -120,11 +120,9 @@
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill, FALSE)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
var/target_value = current + (value * affinity)
|
||||
if(maximum)
|
||||
target_value = min(target_value, maximum)
|
||||
if(target_value == maximum) //no more experience to gain, early return.
|
||||
return
|
||||
var/target_value = round(current + (value * affinity), S.skill_gain_quantisation)
|
||||
if(maximum && target_value >= maximum) //no more experience to gain, early return.
|
||||
return
|
||||
boost_skill_value_to(skill, target_value, silent, current)
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,6 +74,25 @@
|
||||
for(var/client/C in GLOB.clients)
|
||||
C.AnnouncePR(final_composed)
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough
|
||||
keyword = "auto_bunker_override"
|
||||
require_comms_key = TRUE
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough/Run(list/input)
|
||||
if(!CONFIG_GET(flag/allow_cross_server_bunker_override))
|
||||
return "Function Disabled"
|
||||
var/ckeytobypass = input["ckey"]
|
||||
var/is_new_ckey = !(ckey(ckeytobypass) in GLOB.bunker_passthrough)
|
||||
var/sender = input["source"] || "UNKNOWN"
|
||||
GLOB.bunker_passthrough |= ckey(ckeytobypass)
|
||||
GLOB.bunker_passthrough[ckey(ckeytobypass)] = world.realtime
|
||||
SSpersistence.SavePanicBunker() //we can do this every time, it's okay
|
||||
if(!is_new_ckey)
|
||||
log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
return "Success"
|
||||
|
||||
/datum/world_topic/ahelp_relay
|
||||
keyword = "Ahelp"
|
||||
require_comms_key = TRUE
|
||||
|
||||
@@ -436,7 +436,7 @@
|
||||
var/blood_id = get_blood_id()
|
||||
if(!(blood_id in GLOB.blood_reagent_types))
|
||||
return
|
||||
return list("color" = list(BLOOD_COLOR_HUMAN), "ANIMAL DNA" = "Y-")
|
||||
return list("color" = BLOOD_COLOR_HUMAN, "ANIMAL DNA" = "Y-")
|
||||
|
||||
/mob/living/carbon/get_blood_dna_list()
|
||||
var/blood_id = get_blood_id()
|
||||
@@ -444,15 +444,15 @@
|
||||
return
|
||||
var/list/blood_dna = list()
|
||||
if(dna)
|
||||
blood_dna["color"] = list(dna.species.exotic_blood_color) //so when combined, the list grows with the number of colors
|
||||
blood_dna["color"] = dna.species.exotic_blood_color //so when combined, the list grows with the number of colors
|
||||
blood_dna[dna.unique_enzymes] = dna.blood_type
|
||||
else
|
||||
blood_dna["color"] = list(BLOOD_COLOR_HUMAN)
|
||||
blood_dna["color"] = BLOOD_COLOR_HUMAN
|
||||
blood_dna["UNKNOWN DNA"] = "X*"
|
||||
return blood_dna
|
||||
|
||||
/mob/living/carbon/alien/get_blood_dna_list()
|
||||
return list("color" = list(BLOOD_COLOR_XENO), "UNKNOWN DNA" = "X*")
|
||||
return list("color" = BLOOD_COLOR_XENO, "UNKNOWN DNA" = "X*")
|
||||
|
||||
//to add a mob's dna info into an object's blood_DNA list.
|
||||
/atom/proc/transfer_mob_blood_dna(mob/living/L)
|
||||
@@ -461,25 +461,35 @@
|
||||
if(!new_blood_dna)
|
||||
return FALSE
|
||||
LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
|
||||
LAZYINITLIST(blood_DNA["color"])
|
||||
var/old_length = blood_DNA.len
|
||||
blood_DNA |= new_blood_dna
|
||||
blood_DNA["color"] += new_blood_dna["color"]
|
||||
var/changed = FALSE
|
||||
if(!blood_DNA["color"])
|
||||
blood_DNA["color"] = new_blood_dna["color"]
|
||||
changed = TRUE
|
||||
else
|
||||
var/old = blood_DNA["color"]
|
||||
blood_DNA["color"] = BlendRGB(blood_DNA["color"], new_blood_dna["color"])
|
||||
changed = old != blood_DNA["color"]
|
||||
if(blood_DNA.len == old_length)
|
||||
return FALSE
|
||||
return TRUE
|
||||
return changed
|
||||
|
||||
//to add blood dna info to the object's blood_DNA list
|
||||
/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases)
|
||||
LAZYINITLIST(blood_DNA)
|
||||
LAZYINITLIST(blood_dna["color"])
|
||||
|
||||
var/old_length = blood_DNA.len
|
||||
blood_DNA |= blood_dna
|
||||
if(blood_DNA.len > old_length)
|
||||
blood_DNA["color"] += blood_dna["color"]
|
||||
return TRUE
|
||||
. = TRUE
|
||||
//some new blood DNA was added
|
||||
if(!blood_dna["color"])
|
||||
return
|
||||
if(!blood_DNA["color"])
|
||||
blood_DNA["color"] = blood_dna["color"]
|
||||
else
|
||||
blood_DNA["color"] = BlendRGB(blood_DNA["color"], blood_dna["color"])
|
||||
|
||||
//to add blood from a mob onto something, and transfer their dna info
|
||||
/atom/proc/add_mob_blood(mob/living/M)
|
||||
@@ -548,27 +558,7 @@
|
||||
return TRUE
|
||||
|
||||
/atom/proc/blood_DNA_to_color()
|
||||
var/list/colors = list()//first we make a list of all bloodtypes present
|
||||
for(var/blood_color in blood_DNA["color"])
|
||||
if(colors[blood_color])
|
||||
colors[blood_color]++
|
||||
else
|
||||
colors[blood_color] = 1
|
||||
|
||||
var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up
|
||||
if(colors.len)
|
||||
var/sum = 0 //this is all shitcode, but it works; trust me
|
||||
final_rgb = colors[1]
|
||||
sum = colors[colors[1]]
|
||||
if(colors.len > 1)
|
||||
var/i = 2
|
||||
while(i <= colors.len)
|
||||
var/tmp = colors[colors[i]]
|
||||
final_rgb = BlendRGB(final_rgb, colors[i], tmp/(tmp+sum))
|
||||
sum += tmp
|
||||
i++
|
||||
|
||||
return final_rgb
|
||||
return (blood_DNA && blood_DNA["color"]) || BLOOD_COLOR_HUMAN
|
||||
|
||||
/atom/proc/clean_blood()
|
||||
. = blood_DNA? TRUE : FALSE
|
||||
|
||||
@@ -201,10 +201,13 @@ GLOBAL_LIST_EMPTY(objectives)
|
||||
return won || ..()
|
||||
|
||||
/datum/objective/assassinate/once/process()
|
||||
won = check_completion()
|
||||
won = check_midround_completion()
|
||||
if(won)
|
||||
STOP_PROCESSING(SSprocessing,src)
|
||||
|
||||
/datum/objective/assassinate/once/proc/check_midround_completion()
|
||||
return won || !considered_alive(target) //The target afking / logging off for a bit during the round doesn't complete it, but them being afk at roundend does.
|
||||
|
||||
/datum/objective/assassinate/internal
|
||||
var/stolen = 0 //Have we already eliminated this target?
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
var/efficiency
|
||||
|
||||
var/datum/mind/clonemind
|
||||
var/get_clone_mind = CLONEPOD_GET_MIND
|
||||
var/grab_ghost_when = CLONER_MATURE_CLONE
|
||||
|
||||
var/internal_radio = TRUE
|
||||
@@ -134,43 +135,44 @@
|
||||
return examine(user)
|
||||
|
||||
//Start growing a human clone in the pod!
|
||||
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas)
|
||||
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas)
|
||||
if(panel_open)
|
||||
return FALSE
|
||||
if(mess || attempting)
|
||||
return FALSE
|
||||
clonemind = locate(mindref) in SSticker.minds
|
||||
if(!istype(clonemind)) //not a mind
|
||||
return FALSE
|
||||
if(!QDELETED(clonemind.current))
|
||||
if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
|
||||
if(get_clone_mind == CLONEPOD_GET_MIND)
|
||||
clonemind = locate(mindref) in SSticker.minds
|
||||
if(!istype(clonemind)) //not a mind
|
||||
return FALSE
|
||||
if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
|
||||
if(!QDELETED(clonemind.current))
|
||||
if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
|
||||
return FALSE
|
||||
if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
|
||||
return FALSE
|
||||
if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker
|
||||
return FALSE
|
||||
if(clonemind.active) //somebody is using that mind
|
||||
if( ckey(clonemind.key)!=ckey )
|
||||
return FALSE
|
||||
else
|
||||
// get_ghost() will fail if they're unable to reenter their body
|
||||
var/mob/dead/observer/G = clonemind.get_ghost()
|
||||
if(!G)
|
||||
return FALSE
|
||||
if(G.suiciding) // The ghost came from a body that is suiciding.
|
||||
return FALSE
|
||||
if(clonemind.damnation_type) //Can't clone the damned.
|
||||
INVOKE_ASYNC(src, .proc/horrifyingsound)
|
||||
mess = TRUE
|
||||
update_icon()
|
||||
return FALSE
|
||||
if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker
|
||||
return FALSE
|
||||
if(clonemind.active) //somebody is using that mind
|
||||
if( ckey(clonemind.key)!=ckey )
|
||||
return FALSE
|
||||
else
|
||||
// get_ghost() will fail if they're unable to reenter their body
|
||||
var/mob/dead/observer/G = clonemind.get_ghost()
|
||||
if(!G)
|
||||
return FALSE
|
||||
if(G.suiciding) // The ghost came from a body that is suiciding.
|
||||
return FALSE
|
||||
if(clonemind.damnation_type) //Can't clone the damned.
|
||||
INVOKE_ASYNC(src, .proc/horrifyingsound)
|
||||
mess = TRUE
|
||||
update_icon()
|
||||
return FALSE
|
||||
current_insurance = insurance
|
||||
attempting = TRUE //One at a time!!
|
||||
countdown.start()
|
||||
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
|
||||
|
||||
H.hardset_dna(ui, mutation_index, H.real_name, null, mrace, features)
|
||||
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
|
||||
|
||||
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) //100% bad mutation. Can be cured with mutadone.
|
||||
|
||||
@@ -192,7 +194,14 @@
|
||||
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
|
||||
H.Unconscious(80)
|
||||
|
||||
clonemind.transfer_to(H)
|
||||
if(clonemind)
|
||||
clonemind.transfer_to(H)
|
||||
|
||||
else if(get_clone_mind == CLONEPOD_POLL_MIND)
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone? (Don't ERP without permission from the original)", null, null, null, 100, H, POLL_IGNORE_CLONE)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/C = pick(candidates)
|
||||
H.key = C.key
|
||||
|
||||
if(grab_ghost_when == CLONER_FRESH_CLONE)
|
||||
H.grab_ghost()
|
||||
@@ -549,6 +558,17 @@
|
||||
. += "cover-on"
|
||||
. += "panel"
|
||||
|
||||
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
|
||||
/obj/machinery/clonepod/experimental
|
||||
name = "experimental cloning pod"
|
||||
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
|
||||
icon = 'icons/obj/machines/cloning.dmi'
|
||||
icon_state = "pod_0"
|
||||
req_access = null
|
||||
circuit = /obj/item/circuitboard/machine/clonepod/experimental
|
||||
internal_radio = FALSE
|
||||
get_clone_mind = CLONEPOD_POLL_MIND
|
||||
|
||||
/*
|
||||
* Manual -- A big ol' manual.
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
circuit = /obj/item/circuitboard/computer/cloning
|
||||
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
|
||||
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
|
||||
var/clonepod_type = /obj/machinery/clonepod
|
||||
var/list/pods //Linked cloning pods
|
||||
var/temp = "Inactive"
|
||||
var/scantemp_ckey
|
||||
@@ -17,6 +18,7 @@
|
||||
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
|
||||
var/loading = 0 // Nice loading text
|
||||
var/autoprocess = 0
|
||||
var/use_records = TRUE // Old experimental cloner.
|
||||
var/list/records = list()
|
||||
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
@@ -36,29 +38,32 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
|
||||
if(pods)
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.occupant && pod.clonemind == mind)
|
||||
return null
|
||||
if(pod.is_operational() && !(pod.occupant || pod.mess))
|
||||
return pod
|
||||
if(!pods)
|
||||
return
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.occupant && pod.get_clone_mind == CLONEPOD_GET_MIND && pod.clonemind == mind)
|
||||
return null
|
||||
if(pod.is_operational() && !(pod.occupant || pod.mess))
|
||||
return pod
|
||||
|
||||
/obj/machinery/computer/cloning/proc/HasEfficientPod()
|
||||
if(pods)
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.is_operational() && pod.efficiency > 5)
|
||||
return TRUE
|
||||
if(!pods)
|
||||
return
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.is_operational() && pod.efficiency > 5)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
|
||||
if(pods)
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.occupant && pod.clonemind == mind)
|
||||
return pod
|
||||
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
|
||||
. = pod
|
||||
if(!pods)
|
||||
return
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/pod = P
|
||||
if(pod.occupant && pod.clonemind == mind)
|
||||
return pod
|
||||
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
|
||||
. = pod
|
||||
|
||||
/obj/machinery/computer/cloning/process()
|
||||
if(!(scanner && LAZYLEN(pods) && autoprocess))
|
||||
@@ -73,7 +78,7 @@
|
||||
if(pod.occupant)
|
||||
continue //how though?
|
||||
|
||||
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"]))
|
||||
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["blood_type"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"]))
|
||||
temp = "[R.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
|
||||
records -= R
|
||||
|
||||
@@ -103,12 +108,10 @@
|
||||
return null
|
||||
|
||||
/obj/machinery/computer/cloning/proc/findcloner()
|
||||
var/obj/machinery/clonepod/podf = null
|
||||
|
||||
var/obj/machinery/clonepod/podf
|
||||
for(var/direction in GLOB.cardinals)
|
||||
|
||||
podf = locate(/obj/machinery/clonepod, get_step(src, direction))
|
||||
if (!isnull(podf) && podf.is_operational())
|
||||
podf = locate(clonepod_type, get_step(src, direction))
|
||||
if(podf?.is_operational())
|
||||
AttachCloner(podf)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
|
||||
@@ -132,7 +135,7 @@
|
||||
else if(istype(W, /obj/item/multitool))
|
||||
var/obj/item/multitool/P = W
|
||||
|
||||
if(istype(P.buffer, /obj/machinery/clonepod))
|
||||
if(istype(P.buffer, clonepod_type))
|
||||
if(get_area(P.buffer) != get_area(src))
|
||||
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
|
||||
P.buffer = null
|
||||
@@ -157,13 +160,14 @@
|
||||
var/dat = ""
|
||||
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
|
||||
|
||||
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
|
||||
if(!autoprocess)
|
||||
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
|
||||
if(use_records)
|
||||
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
|
||||
if(!autoprocess)
|
||||
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
|
||||
else
|
||||
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
|
||||
else
|
||||
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Autoclone</span>"
|
||||
dat += "<span class='linkOff'>Autoclone</span>"
|
||||
dat += "<h3>Cloning Pod Status</h3>"
|
||||
dat += "<div class='statusDisplay'>[temp] </div>"
|
||||
|
||||
@@ -190,26 +194,29 @@
|
||||
else if(loading)
|
||||
dat += "[scanner_occupant] => Scanning..."
|
||||
else
|
||||
if(scanner_occupant.ckey != scantemp_ckey)
|
||||
scantemp = "Ready to Scan"
|
||||
scantemp_ckey = scanner_occupant.ckey
|
||||
if(use_records)
|
||||
if(scanner_occupant.ckey != scantemp_ckey)
|
||||
scantemp = "Ready to Scan"
|
||||
scantemp_ckey = scanner_occupant.ckey
|
||||
else
|
||||
scantemp = "Ready to Clone"
|
||||
dat += "[scanner_occupant] => [scantemp]"
|
||||
dat += "</div>"
|
||||
|
||||
if(scanner_occupant)
|
||||
dat += "<a href='byond://?src=[REF(src)];scan=1'>Start Scan</a>"
|
||||
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
|
||||
dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
|
||||
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Start Scan</span>"
|
||||
|
||||
// Database
|
||||
dat += "<h3>Database Functions</h3>"
|
||||
if (src.records.len && src.records.len > 0)
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
|
||||
else
|
||||
dat += "<span class='linkOff'>View Records (0)</span><br>"
|
||||
if (src.diskette)
|
||||
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
|
||||
dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
|
||||
if(use_records)
|
||||
// Database
|
||||
dat += "<h3>Database Functions</h3>"
|
||||
if (src.records.len && src.records.len > 0)
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
|
||||
else
|
||||
dat += "<span class='linkOff'>View Records (0)</span><br>"
|
||||
if (src.diskette)
|
||||
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
|
||||
|
||||
|
||||
|
||||
@@ -290,24 +297,19 @@
|
||||
autoprocess = FALSE
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
|
||||
scantemp = ""
|
||||
|
||||
loading = 1
|
||||
loading = TRUE
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
say("Initiating scan...")
|
||||
var/prev_locked = scanner.locked
|
||||
scanner.locked = TRUE
|
||||
spawn(20)
|
||||
src.scan_occupant(scanner.occupant)
|
||||
|
||||
loading = 0
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
scanner.locked = prev_locked
|
||||
|
||||
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
|
||||
. = TRUE
|
||||
|
||||
//No locking an open scanner.
|
||||
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
|
||||
@@ -317,8 +319,17 @@
|
||||
else
|
||||
scanner.locked = FALSE
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if(href_list["view_rec"])
|
||||
|
||||
else if (href_list["refresh"])
|
||||
src.updateUsrDialog()
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
|
||||
if(. || !use_records)
|
||||
return
|
||||
if(href_list["view_rec"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
src.active_record = find_record("id", href_list["view_rec"], records)
|
||||
if(active_record)
|
||||
@@ -330,6 +341,7 @@
|
||||
src.menu = 3
|
||||
else
|
||||
src.temp = "Record missing."
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["del_rec"])
|
||||
if ((!src.active_record) || (src.menu < 3))
|
||||
@@ -353,8 +365,9 @@
|
||||
else
|
||||
src.temp = "<font class='bad'>Access Denied.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["disk"]) //Load or eject.
|
||||
else if (href_list["disk"] && use_records) //Load or eject.
|
||||
switch(href_list["disk"])
|
||||
if("load")
|
||||
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
|
||||
@@ -392,10 +405,7 @@
|
||||
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
|
||||
src.temp = "Save successful."
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
else if (href_list["refresh"])
|
||||
src.updateUsrDialog()
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["clone"])
|
||||
var/datum/data/record/C = find_record("id", href_list["clone"], records)
|
||||
@@ -415,7 +425,7 @@
|
||||
else if(pod.occupant)
|
||||
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"]))
|
||||
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
|
||||
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
records.Remove(C)
|
||||
@@ -429,14 +439,28 @@
|
||||
else
|
||||
temp = "<font class='bad'>Data corruption.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
. = TRUE
|
||||
|
||||
else if (href_list["menu"])
|
||||
src.menu = text2num(href_list["menu"])
|
||||
else if (href_list["menu"] && use_records)
|
||||
menu = text2num(href_list["menu"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
|
||||
if(!scanner || !L)
|
||||
return
|
||||
src.add_fingerprint(usr)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
if(use_records)
|
||||
scan_occupant(L)
|
||||
else
|
||||
clone_occupant(L)
|
||||
|
||||
loading = FALSE
|
||||
src.updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
scanner.locked = prev_locked
|
||||
|
||||
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
|
||||
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
|
||||
@@ -455,30 +479,9 @@
|
||||
if(isbrain(mob_occupant))
|
||||
dna = B.stored_dna
|
||||
|
||||
if(!istype(dna))
|
||||
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(mob_occupant.suiciding || mob_occupant.hellbound)
|
||||
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
|
||||
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
|
||||
return
|
||||
if ((!mob_occupant.ckey) || (!mob_occupant.client))
|
||||
scantemp = "<font class='bad'>Mental interface failure.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if (find_record("ckey", mob_occupant.ckey, records))
|
||||
scantemp = "<font class='average'>Subject already in database.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(SSeconomy.full_ancap && !has_bank_account)
|
||||
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
if(!can_scan(dna, mob_occupant, FALSE, has_bank_account))
|
||||
return
|
||||
|
||||
var/datum/data/record/R = new()
|
||||
if(dna.species)
|
||||
// We store the instance rather than the path, because some
|
||||
@@ -529,3 +532,78 @@
|
||||
board.records = records
|
||||
scantemp = "Subject successfully scanned."
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
//Used by the experimental cloning computer.
|
||||
/obj/machinery/computer/cloning/proc/clone_occupant(occupant)
|
||||
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
|
||||
var/datum/dna/dna
|
||||
if(ishuman(mob_occupant))
|
||||
var/mob/living/carbon/C = mob_occupant
|
||||
dna = C.has_dna()
|
||||
if(isbrain(mob_occupant))
|
||||
var/mob/living/brain/B = mob_occupant
|
||||
dna = B.stored_dna
|
||||
|
||||
if(!can_scan(dna, mob_occupant, TRUE))
|
||||
return
|
||||
|
||||
var/clone_species
|
||||
if(dna.species)
|
||||
clone_species = dna.species
|
||||
else
|
||||
var/datum/species/rando_race = pick(GLOB.roundstart_races)
|
||||
clone_species = rando_race.type
|
||||
|
||||
var/obj/machinery/clonepod/pod = GetAvailablePod()
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!LAZYLEN(pods))
|
||||
temp = "<font class='bad'>No Clonepods detected.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!pod)
|
||||
temp = "<font class='bad'>No Clonepods available.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.occupant)
|
||||
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else
|
||||
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
|
||||
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
|
||||
if(!istype(dna))
|
||||
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(!experimental)
|
||||
if(mob_occupant.suiciding || mob_occupant.hellbound)
|
||||
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
|
||||
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
|
||||
return
|
||||
if (!experimental)
|
||||
if(!mob_occupant.ckey || !mob_occupant.client)
|
||||
scantemp = "<font class='bad'>Mental interface failure.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if (find_record("ckey", mob_occupant.ckey, records))
|
||||
scantemp = "<font class='average'>Subject already in database.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if(SSeconomy.full_ancap && !account)
|
||||
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
|
||||
/obj/machinery/computer/cloning/prototype
|
||||
name = "prototype cloning console"
|
||||
desc = "Used to operate an experimental cloner."
|
||||
icon_screen = "dna"
|
||||
icon_keyboard = "med_key"
|
||||
circuit = /obj/item/circuitboard/computer/cloning/prototype
|
||||
clonepod_type = /obj/machinery/clonepod/experimental
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
|
||||
/obj/machinery/clonepod/experimental
|
||||
name = "experimental cloning pod"
|
||||
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
|
||||
icon = 'icons/obj/machines/cloning.dmi'
|
||||
icon_state = "pod_0"
|
||||
req_access = null
|
||||
circuit = /obj/item/circuitboard/machine/clonepod/experimental
|
||||
internal_radio = FALSE
|
||||
|
||||
//Start growing a human clone in the pod!
|
||||
/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks)
|
||||
if(panel_open)
|
||||
return FALSE
|
||||
if(mess || attempting)
|
||||
return FALSE
|
||||
|
||||
attempting = TRUE //One at a time!!
|
||||
countdown.start()
|
||||
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
|
||||
|
||||
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
|
||||
|
||||
if(efficiency > 2)
|
||||
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
|
||||
H.dna.remove_mutation_group(unclean_mutations)
|
||||
if(efficiency > 5 && prob(20))
|
||||
H.easy_randmut(POSITIVE)
|
||||
if(efficiency < 3 && prob(50))
|
||||
var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
if(ismob(M))
|
||||
H = M
|
||||
|
||||
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
|
||||
occupant = H
|
||||
|
||||
if(!clonename) //to prevent null names
|
||||
clonename = "clone ([rand(1,999)])"
|
||||
H.real_name = clonename
|
||||
|
||||
icon_state = "pod_1"
|
||||
//Get the clone body ready
|
||||
maim_clone(H)
|
||||
ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
|
||||
ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
|
||||
ADD_TRAIT(H, TRAIT_MUTE, "cloning")
|
||||
ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
|
||||
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
|
||||
H.Unconscious(80)
|
||||
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/C = pick(candidates)
|
||||
H.key = C.key
|
||||
|
||||
if(grab_ghost_when == CLONER_FRESH_CLONE)
|
||||
H.grab_ghost()
|
||||
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
|
||||
|
||||
if(grab_ghost_when == CLONER_MATURE_CLONE)
|
||||
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
|
||||
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
|
||||
|
||||
if(H)
|
||||
H.faction |= factions
|
||||
|
||||
H.set_cloned_appearance()
|
||||
|
||||
H.suiciding = FALSE
|
||||
attempting = FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
|
||||
/obj/machinery/computer/prototype_cloning
|
||||
name = "prototype cloning console"
|
||||
desc = "Used to operate an experimental cloner."
|
||||
icon_screen = "dna"
|
||||
icon_keyboard = "med_key"
|
||||
circuit = /obj/item/circuitboard/computer/prototype_cloning
|
||||
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
|
||||
var/list/pods //Linked experimental cloning pods
|
||||
var/temp = "Inactive"
|
||||
var/scantemp = "Ready to Scan"
|
||||
var/loading = FALSE // Nice loading text
|
||||
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/Initialize()
|
||||
. = ..()
|
||||
updatemodules(TRUE)
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/Destroy()
|
||||
if(pods)
|
||||
for(var/P in pods)
|
||||
DetachCloner(P)
|
||||
pods = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null)
|
||||
if(pods)
|
||||
for(var/P in pods)
|
||||
var/obj/machinery/clonepod/experimental/pod = P
|
||||
if(pod.is_operational() && !(pod.occupant || pod.mess))
|
||||
return pod
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner)
|
||||
scanner = findscanner()
|
||||
if(findfirstcloner && !LAZYLEN(pods))
|
||||
findcloner()
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/findscanner()
|
||||
var/obj/machinery/dna_scannernew/scannerf = null
|
||||
|
||||
// Loop through every direction
|
||||
for(var/direction in GLOB.cardinals)
|
||||
// Try to find a scanner in that direction
|
||||
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction))
|
||||
// If found and operational, return the scanner
|
||||
if (!isnull(scannerf) && scannerf.is_operational())
|
||||
return scannerf
|
||||
|
||||
// If no scanner was found, it will return null
|
||||
return null
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/findcloner()
|
||||
var/obj/machinery/clonepod/experimental/podf = null
|
||||
for(var/direction in GLOB.cardinals)
|
||||
podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction))
|
||||
if (!isnull(podf) && podf.is_operational())
|
||||
AttachCloner(podf)
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod)
|
||||
if(!pod.connected)
|
||||
pod.connected = src
|
||||
LAZYADD(pods, pod)
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod)
|
||||
pod.connected = null
|
||||
LAZYREMOVE(pods, pod)
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/multitool))
|
||||
var/obj/item/multitool/P = W
|
||||
|
||||
if(istype(P.buffer, /obj/machinery/clonepod/experimental))
|
||||
if(get_area(P.buffer) != get_area(src))
|
||||
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
|
||||
P.buffer = null
|
||||
return
|
||||
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
|
||||
var/obj/machinery/clonepod/experimental/pod = P.buffer
|
||||
if(pod.connected)
|
||||
pod.connected.DetachCloner(pod)
|
||||
AttachCloner(pod)
|
||||
else
|
||||
P.buffer = src
|
||||
to_chat(user, "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>")
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(..())
|
||||
return
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/interact(mob/user)
|
||||
user.set_machine(src)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(..())
|
||||
return
|
||||
|
||||
updatemodules(TRUE)
|
||||
|
||||
var/dat = ""
|
||||
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
|
||||
|
||||
dat += "<h3>Cloning Pod Status</h3>"
|
||||
dat += "<div class='statusDisplay'>[temp] </div>"
|
||||
|
||||
if (isnull(src.scanner) || !LAZYLEN(pods))
|
||||
dat += "<h3>Modules</h3>"
|
||||
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
|
||||
if (isnull(src.scanner))
|
||||
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
|
||||
if (!LAZYLEN(pods))
|
||||
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
|
||||
|
||||
// Scan-n-Clone
|
||||
if (!isnull(src.scanner))
|
||||
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
|
||||
|
||||
dat += "<h3>Cloning</h3>"
|
||||
|
||||
dat += "<div class='statusDisplay'>"
|
||||
if(!scanner_occupant)
|
||||
dat += "Scanner Unoccupied"
|
||||
else if(loading)
|
||||
dat += "[scanner_occupant] => Scanning..."
|
||||
else
|
||||
scantemp = "Ready to Clone"
|
||||
dat += "[scanner_occupant] => [scantemp]"
|
||||
dat += "</div>"
|
||||
|
||||
if(scanner_occupant)
|
||||
dat += "<a href='byond://?src=[REF(src)];clone=1'>Clone</a>"
|
||||
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Clone</span>"
|
||||
|
||||
var/datum/browser/popup = new(user, "cloning", "Prototype Cloning System Control")
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(loading)
|
||||
return
|
||||
|
||||
else if ((href_list["clone"]) && !isnull(scanner) && scanner.is_operational())
|
||||
scantemp = ""
|
||||
|
||||
loading = TRUE
|
||||
updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
|
||||
say("Initiating scan...")
|
||||
|
||||
spawn(20)
|
||||
clone_occupant(scanner.occupant)
|
||||
loading = FALSE
|
||||
updateUsrDialog()
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
//No locking an open scanner.
|
||||
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
|
||||
if ((!scanner.locked) && (scanner.occupant))
|
||||
scanner.locked = TRUE
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else
|
||||
scanner.locked = FALSE
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
else if (href_list["refresh"])
|
||||
updateUsrDialog()
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/prototype_cloning/proc/clone_occupant(occupant)
|
||||
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
|
||||
var/datum/dna/dna
|
||||
if(ishuman(mob_occupant))
|
||||
var/mob/living/carbon/C = mob_occupant
|
||||
dna = C.has_dna()
|
||||
if(isbrain(mob_occupant))
|
||||
var/mob/living/brain/B = mob_occupant
|
||||
dna = B.stored_dna
|
||||
|
||||
if(!istype(dna))
|
||||
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
|
||||
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
|
||||
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
|
||||
return
|
||||
|
||||
var/clone_species
|
||||
if(dna.species)
|
||||
clone_species = dna.species
|
||||
else
|
||||
var/datum/species/rando_race = pick(GLOB.roundstart_races)
|
||||
clone_species = rando_race.type
|
||||
|
||||
var/obj/machinery/clonepod/pod = GetAvailablePod()
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!LAZYLEN(pods))
|
||||
temp = "<font class='bad'>No Clonepods detected.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(!pod)
|
||||
temp = "<font class='bad'>No Clonepods available.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else if(pod.occupant)
|
||||
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
else
|
||||
pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
|
||||
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
@@ -666,28 +666,18 @@
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 50,
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 10,
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 10,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 3,
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 3,
|
||||
/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 10,
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 13,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 13,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 12,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/weapon_parts
|
||||
name = "random weapon parts spawner 25%"
|
||||
name = "random weapon parts spawner 20%"
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 75,
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
|
||||
loot = list("" = 80,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 2,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 5,
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/ammo
|
||||
@@ -695,8 +685,6 @@
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 25,
|
||||
/obj/item/ammo_box/c32mm = 15,
|
||||
/obj/item/ammo_box/r32mm = 15,
|
||||
/obj/item/ammo_box/magazine/wt550m9 = 1,
|
||||
/obj/item/ammo_casing/shotgun/buckshot = 7,
|
||||
/obj/item/ammo_casing/shotgun/rubbershot = 7,
|
||||
@@ -709,8 +697,6 @@
|
||||
lootcount = 1
|
||||
spawn_on_turf = FALSE
|
||||
loot = list("" = 50,
|
||||
/obj/item/ammo_box/c32mm = 7,
|
||||
/obj/item/ammo_box/r32mm = 7,
|
||||
/obj/item/ammo_box/magazine/wt550m9 = 2,
|
||||
/obj/item/ammo_casing/shotgun/buckshot = 10,
|
||||
/obj/item/ammo_casing/shotgun/rubbershot = 10,
|
||||
|
||||
@@ -68,6 +68,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
var/click_delay = CLICK_CD_MELEE
|
||||
|
||||
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
|
||||
var/current_equipped_slot
|
||||
pass_flags = PASSTABLE
|
||||
pressure_resistance = 4
|
||||
var/obj/item/master = null
|
||||
@@ -179,6 +180,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
if(damtype == "brute")
|
||||
hitsound = "swing_hit"
|
||||
|
||||
if(used_skills)
|
||||
for(var/path in used_skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
LAZYADD(used_skills[path], S.skill_traits)
|
||||
|
||||
/obj/item/Destroy()
|
||||
item_flags &= ~DROPDEL //prevent reqdels
|
||||
if(ismob(loc))
|
||||
@@ -315,6 +321,10 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
|
||||
if(current_equipped_slot in user.check_obscured_slots())
|
||||
to_chat(src, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
|
||||
return FALSE
|
||||
|
||||
if(resistance_flags & ON_FIRE)
|
||||
var/mob/living/carbon/C = user
|
||||
@@ -336,7 +346,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
C.update_damage_overlays()
|
||||
return
|
||||
|
||||
if(acid_level > 20 && !ismob(loc))// so we can still remove the clothes on us that have acid.
|
||||
if(acid_level > 20 && ismob(loc))// so we can still remove the clothes on us that have acid.
|
||||
var/mob/living/carbon/C = user
|
||||
if(istype(C))
|
||||
if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF))))
|
||||
@@ -379,6 +389,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
|
||||
if(current_equipped_slot in user.check_obscured_slots())
|
||||
to_chat(src, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
|
||||
return FALSE
|
||||
|
||||
|
||||
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
|
||||
|
||||
@@ -423,6 +438,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
|
||||
/obj/item/proc/dropped(mob/user)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
current_equipped_slot = null
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.Remove(user)
|
||||
@@ -470,7 +486,9 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
// for items that can be placed in multiple slots
|
||||
// note this isn't called during the initial dressing of a player
|
||||
/obj/item/proc/equipped(mob/user, slot)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
. = SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot)
|
||||
current_equipped_slot = slot
|
||||
if(!(. & COMPONENT_NO_GRANT_ACTIONS))
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
@@ -835,7 +853,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
|
||||
// Called when a mob tries to use the item as a tool.
|
||||
// Handles most checks.
|
||||
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = 1, max_level = INFINITY)
|
||||
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = STD_USE_TOOL_MULT)
|
||||
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
|
||||
// Run the start check here so we wouldn't have to call it manually.
|
||||
if(!delay && !tool_start_check(user, amount))
|
||||
@@ -880,7 +898,8 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
|
||||
for(var/skill in used_skills)
|
||||
if(!(SKILL_TRAINING_TOOL in used_skills[skill]))
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
user.mind.auto_gain_experience(skill, gain*skill_gain_mult*S.item_skill_gain_multi)
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -794,6 +794,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
|
||||
reagents.clear_reagents()
|
||||
|
||||
/obj/item/clothing/mask/vape/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(slot == SLOT_WEAR_MASK)
|
||||
if(!screw)
|
||||
to_chat(user, "<span class='notice'>You start puffing on the vape.</span>")
|
||||
|
||||
@@ -116,9 +116,9 @@
|
||||
build_path = /obj/machinery/computer/cloning
|
||||
var/list/records = list()
|
||||
|
||||
/obj/item/circuitboard/computer/prototype_cloning
|
||||
/obj/item/circuitboard/computer/cloning/prototype
|
||||
name = "Prototype Cloning (Computer Board)"
|
||||
build_path = /obj/machinery/computer/prototype_cloning
|
||||
build_path = /obj/machinery/computer/cloning/prototype
|
||||
|
||||
/obj/item/circuitboard/computer/arcade/battle
|
||||
name = "Arcade Battle (Computer Board)"
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
to_chat(user, "<span class='notice'>You add [A] to the [initial(name)] assembly.</span>")
|
||||
|
||||
else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
|
||||
if (I.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC))
|
||||
if (I.use_tool(src, user, 0, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
|
||||
det_time = 50 // In case the cable_coil was removed and readded.
|
||||
stage_change(WIRED)
|
||||
to_chat(user, "<span class='notice'>You rig the [initial(name)] assembly.</span>")
|
||||
|
||||
@@ -355,6 +355,7 @@
|
||||
emaggedhitdamage = 0
|
||||
|
||||
/obj/item/borg/lollipop/equipped()
|
||||
. = ..()
|
||||
check_amount()
|
||||
|
||||
/obj/item/borg/lollipop/dropped(mob/user)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
/datum/block_parry_data/shield
|
||||
block_damage_multiplier = 0.25
|
||||
block_stamina_efficiency = 2.5
|
||||
block_stamina_cost_per_second = 3.5
|
||||
block_stamina_cost_per_second = 2.5
|
||||
block_slowdown = 0
|
||||
block_lock_attacking = FALSE
|
||||
block_lock_sprinting = TRUE
|
||||
@@ -386,7 +386,7 @@ obj/item/shield/riot/bullet_proof
|
||||
max_integrity = 100
|
||||
obj_integrity = 100
|
||||
can_shatter = FALSE
|
||||
item_flags = SLOWS_WHILE_IN_HAND
|
||||
item_flags = SLOWS_WHILE_IN_HAND | ITEM_CAN_BLOCK
|
||||
var/recharge_timerid
|
||||
var/recharge_delay = 15 SECONDS
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
|
||||
if (get_amount() < 1 || CC.get_amount() < 5)
|
||||
to_chat(user, "<span class='warning>You need five lengths of coil and one sheet of glass to make wired glass!</span>")
|
||||
return
|
||||
CC.use_tool(src, user, 0, 5, max_level = JOB_SKILL_BASIC)
|
||||
CC.use_tool(src, user, 0, 5, skill_gain_mult = TRIVIAL_USE_TOOL_MULT)
|
||||
use(1)
|
||||
to_chat(user, "<span class='notice'>You attach wire to the [name].</span>")
|
||||
var/obj/item/stack/light_w/new_tile = new(user.loc)
|
||||
|
||||
@@ -240,9 +240,8 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
|
||||
new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_floor = TRUE),\
|
||||
)),
|
||||
null, \
|
||||
new/datum/stack_recipe("wooden firearm body", /obj/item/weaponcrafting/improvised_parts/wooden_body, 10, time = 40), \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
|
||||
new/datum/stack_recipe("pistol grip", /obj/item/weaponcrafting/improvised_parts/wooden_grip, 5, time = 40), \
|
||||
new/datum/stack_recipe("wooden firearm body", /obj/item/weaponcrafting/improvised_parts/wooden_body, 10, time = 20), \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 20), \
|
||||
new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \
|
||||
new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 30), \
|
||||
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
|
||||
@@ -382,6 +381,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
|
||||
new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4), \
|
||||
new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4), \
|
||||
null, \
|
||||
new/datum/stack_recipe("string", /obj/item/weaponcrafting/string, 1, time = 10), \
|
||||
new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6), \
|
||||
new/datum/stack_recipe("rag", /obj/item/reagent_containers/rag, 1), \
|
||||
new/datum/stack_recipe("towel", /obj/item/reagent_containers/rag/towel, 3), \
|
||||
@@ -429,7 +429,6 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
|
||||
new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \
|
||||
new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \
|
||||
new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \
|
||||
new/datum/stack_recipe("durathread string", /obj/item/weaponcrafting/durathread_string, 1, time = 40), \
|
||||
))
|
||||
|
||||
/obj/item/stack/sheet/durathread
|
||||
|
||||
@@ -207,18 +207,18 @@
|
||||
cig_position++
|
||||
|
||||
/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
if(!ismob(M))
|
||||
return
|
||||
if(M != user || !istype(M))
|
||||
return ..()
|
||||
var/obj/item/clothing/mask/cigarette/cig = locate(/obj/item/clothing/mask/cigarette) in contents
|
||||
if(cig)
|
||||
if(M == user && contents.len > 0 && !user.wear_mask)
|
||||
if(!user.wear_mask && !(SLOT_WEAR_MASK in M.check_obscured_slots()))
|
||||
var/obj/item/clothing/mask/cigarette/W = cig
|
||||
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, W, M)
|
||||
M.equip_to_slot_if_possible(W, SLOT_WEAR_MASK)
|
||||
contents -= W
|
||||
to_chat(user, "<span class='notice'>You take \a [W] out of the pack.</span>")
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>There are no [icon_type]s left in the pack.</span>")
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/obj/item/hatchet/saw
|
||||
name = "handsaw"
|
||||
desc = "A very sharp handsaw, it's compact."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "saw"
|
||||
item_state = "sawhandle_greyscale"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
tool_behaviour = TOOL_SAW
|
||||
force = 10
|
||||
throwforce = 8
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
custom_materials = list(/datum/material/iron = 5000)
|
||||
attack_verb = list("sawed", "sliced", "cut")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
sharpness = IS_SHARP
|
||||
var/random_color = TRUE //code taken from screwdrivers.dm; cool handles are cool.
|
||||
var/static/list/saw_colors = list(
|
||||
"blue" = rgb(24, 97, 213),
|
||||
"red" = rgb(255, 0, 0),
|
||||
"pink" = rgb(213, 24, 141),
|
||||
"brown" = rgb(160, 82, 18),
|
||||
"green" = rgb(14, 127, 27),
|
||||
"cyan" = rgb(24, 162, 213),
|
||||
"yellow" = rgb(255, 165, 0)
|
||||
)
|
||||
|
||||
/obj/item/hatchet/saw/Initialize()
|
||||
. = ..()
|
||||
if(random_color)
|
||||
icon_state = "sawhandle_greyscale"
|
||||
var/our_color = pick(saw_colors)
|
||||
add_atom_colour(saw_colors[our_color], FIXED_COLOUR_PRIORITY)
|
||||
update_icon()
|
||||
if(prob(75))
|
||||
pixel_y = rand(-8, 8)
|
||||
|
||||
/obj/item/hatchet/saw/update_overlays()
|
||||
. = ..()
|
||||
if(!random_color) //icon override
|
||||
return
|
||||
var/mutable_appearance/base_overlay = mutable_appearance(icon, "sawblade")
|
||||
base_overlay.appearance_flags = RESET_COLOR
|
||||
. += base_overlay
|
||||
|
||||
// END
|
||||
@@ -450,8 +450,7 @@
|
||||
sharpness = IS_BLUNT
|
||||
|
||||
/obj/item/dualsaber/toy/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
|
||||
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=0, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
|
||||
|
||||
/obj/item/dualsaber/toy/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
return BLOCK_NONE
|
||||
@@ -469,9 +468,8 @@
|
||||
slowdown_wielded = 0
|
||||
sharpness = IS_BLUNT
|
||||
|
||||
/obj/item/dualsaber/toy/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
|
||||
/obj/item/dualsaber/hypereutactic/toy/ComponentInitialize()
|
||||
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=0, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
|
||||
|
||||
/obj/item/dualsaber/hypereutactic/toy/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
return BLOCK_NONE
|
||||
|
||||
@@ -108,8 +108,7 @@
|
||||
|
||||
//Life, Stat, Hud Updates, and Say
|
||||
/mob/living/simple_animal/revenant/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
. = ..()
|
||||
if(stasis)
|
||||
return
|
||||
if(revealed && essence <= 0)
|
||||
|
||||
@@ -189,6 +189,8 @@
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>")
|
||||
user.dropItemToGround(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
///Next tick to reset the total message counter
|
||||
var/total_count_reset = 0
|
||||
var/ircreplyamount = 0
|
||||
/// last time they tried to do an autobunker auth
|
||||
var/autobunker_last_try = 0
|
||||
|
||||
/////////
|
||||
//OTHER//
|
||||
|
||||
@@ -2322,14 +2322,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/min = CONFIG_GET(number/body_size_min)
|
||||
var/max = CONFIG_GET(number/body_size_max)
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
var/new_body_size = input(user, "Choose your desired sprite size:\n([min*100]%-[max*100]%), Warning: May make your character look distorted[danger > min ? ", and an exponential slowdown will occur for those smaller than [danger*100]%!" : "!"]", "Character Preference", features["body_size"]*100) as num|null
|
||||
var/new_body_size = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted[danger > min ? "! Additionally, a proportional movement speed penalty will be applied to characters smaller than [danger*100]%." : "!"]", "Character Preference", features["body_size"]*100) as num|null
|
||||
if (new_body_size)
|
||||
new_body_size = clamp(new_body_size * 0.01, min, max)
|
||||
var/dorfy
|
||||
if(danger > new_body_size)
|
||||
dorfy = alert(user, "The chosen size appears to be smaller than the threshold of [danger*100]%, which will lead to an added exponential slowdown. Are you sure about that?", "Dwarfism Alert", "Yes", "Move it to the threshold", "No")
|
||||
if(!dorfy || dorfy == "Move it above the threshold")
|
||||
if((new_body_size + 0.01) < danger) // Adding 0.01 as a dumb fix to prevent the warning message from appearing when exactly at threshold... Not sure why that happens in the first place.
|
||||
dorfy = alert(user, "You have chosen a size below the slowdown threshold of [danger*100]%. For balancing purposes, the further you go below this percentage, the slower your character will be. Do you wish to keep this size?", "Speed Penalty Alert", "Yes", "Move it to the threshold", "No")
|
||||
if(dorfy == "Move it to the threshold")
|
||||
new_body_size = danger
|
||||
if(!dorfy) //Aborts if this var is somehow empty
|
||||
return
|
||||
if(dorfy != "No")
|
||||
features["body_size"] = new_body_size
|
||||
if("tongue")
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/client/verb/bunker_auto_authorize()
|
||||
set name = "Auto Authorize Panic Bunker"
|
||||
set desc = "Authorizes your account in the panic bunker of any servers connected to this function."
|
||||
set category = "OOC"
|
||||
|
||||
if(autobunker_last_try + 5 SECONDS > world.time)
|
||||
to_chat(src, "<span class='danger'>Function on cooldown, try again in 5 seconds.</span>")
|
||||
return
|
||||
autobunker_last_try = world.time
|
||||
|
||||
world.send_cross_server_bunker_overrides(key, src)
|
||||
|
||||
/world/proc/send_cross_server_bunker_overrides(key, client/C)
|
||||
var/comms_key = CONFIG_GET(string/comms_key)
|
||||
if(!comms_key)
|
||||
return
|
||||
var/list/message = list()
|
||||
message["ckey"] = key
|
||||
message["source"] = "[CONFIG_GET(string/cross_comms_name)]"
|
||||
message["key"] = comms_key
|
||||
message["auto_bunker_override"] = TRUE
|
||||
var/list/servers = CONFIG_GET(keyed_list/cross_server_bunker_override)
|
||||
if(!length(servers))
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: No servers are configured to receive from this one.</span>")
|
||||
return
|
||||
log_admin("[key] ([key_name(C)]) has initiated an autobunker authentication with linked servers.")
|
||||
for(var/name in servers)
|
||||
var/returned = world.Export("[servers[name]]?[list2params(message)]")
|
||||
switch(returned)
|
||||
if("Bad Key")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBuNKER: [name] failed to authenticate with this server.</span>")
|
||||
if("Function Disabled")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: [name] has autobunker receive disabled.</span>")
|
||||
if("Success")
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: Successfully authenticated with [name]. Panic bunker bypass granted to [key].</span>.")
|
||||
else
|
||||
to_chat(C, "<span class='boldwarning'>AUTOBUNKER: Unknown error ([name]).</span>")
|
||||
@@ -23,14 +23,15 @@
|
||||
if(iscarbon(target) && proximity)
|
||||
var/mob/living/carbon/C = target
|
||||
var/mob/living/carbon/U = user
|
||||
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, TRUE, TRUE)
|
||||
var/success = C.equip_to_slot_if_possible(new /obj/item/clothing/gloves/color/yellow/sprayon, ITEM_SLOT_GLOVES, TRUE, TRUE, clothing_check = TRUE)
|
||||
if(success)
|
||||
if(C == user)
|
||||
C.visible_message("<span class='notice'>[U] sprays their hands with glittery rubber!</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>[U] sprays glittery rubber on the hands of [C]!</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>The rubber fails to stick to [C]'s hands!</span>")
|
||||
user.visible_message("<span class='warning'>The rubber fails to stick to [C]'s hands!</span>",
|
||||
"<span class='warning'>The rubber fails to stick to [C]'s [(SLOT_GLOVES in C.check_obscured_slots()) ? "unexposed" : ""] hands!</span>")
|
||||
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
RemoveHelmet()
|
||||
..()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/RemoveHelmet()
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/RemoveHelmet(message = TRUE)
|
||||
if(!helmet)
|
||||
return
|
||||
suittoggled = FALSE
|
||||
@@ -174,16 +174,18 @@
|
||||
helmet.attack_self(H)
|
||||
H.transferItemToLoc(helmet, src, TRUE)
|
||||
H.update_inv_wear_suit()
|
||||
to_chat(H, "<span class='notice'>The helmet on the hardsuit disengages.</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='notice'>The helmet on the hardsuit disengages.</span>")
|
||||
playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
else
|
||||
helmet.forceMove(src)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/dropped(mob/user)
|
||||
..()
|
||||
RemoveHelmet()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/ToggleHelmet()
|
||||
/obj/item/clothing/suit/space/hardsuit/proc/ToggleHelmet(message = TRUE)
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(!helmettype)
|
||||
return
|
||||
@@ -192,15 +194,19 @@
|
||||
if(!suittoggled)
|
||||
if(ishuman(src.loc))
|
||||
if(H.wear_suit != src)
|
||||
to_chat(H, "<span class='warning'>You must be wearing [src] to engage the helmet!</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='warning'>You must be wearing [src] to engage the helmet!</span>")
|
||||
return
|
||||
if(H.head)
|
||||
to_chat(H, "<span class='warning'>You're already wearing something on your head!</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='warning'>You're already wearing something on your head!</span>")
|
||||
return
|
||||
else if(H.equip_to_slot_if_possible(helmet,SLOT_HEAD,0,0,1))
|
||||
to_chat(H, "<span class='notice'>You engage the helmet on the hardsuit.</span>")
|
||||
if(message)
|
||||
to_chat(H, "<span class='notice'>You engage the helmet on the hardsuit.</span>")
|
||||
suittoggled = TRUE
|
||||
H.update_inv_wear_suit()
|
||||
playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
return TRUE
|
||||
else
|
||||
RemoveHelmet()
|
||||
return RemoveHelmet(message)
|
||||
|
||||
@@ -46,4 +46,4 @@
|
||||
icon_state = "lewdcap"
|
||||
item_state = "lewdcap"
|
||||
can_adjust = FALSE
|
||||
mutantrace_variation = USE_TAUR_CLIP_MASK
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
icon_state = "cmoturtle"
|
||||
item_state = "w_suit"
|
||||
alt_covers_chest = TRUE
|
||||
mutantrace_variation = USE_TAUR_CLIP_MASK
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK
|
||||
|
||||
/obj/item/clothing/under/rank/medical/geneticist
|
||||
desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it."
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab/chicken
|
||||
name = "chicken meat"
|
||||
desc = "A slab of raw chicken. Remember to wash your hands!"
|
||||
icon_state = "chickenbreast"
|
||||
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/chicken
|
||||
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/chicken
|
||||
tastes = list("chicken" = 1)
|
||||
@@ -341,8 +342,14 @@
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/chicken
|
||||
name = "chicken steak" //Can you have chicken steaks? Maybe this should be renamed once it gets new sprites.
|
||||
icon_state = "chickenbreast_cooked"
|
||||
tastes = list("chicken" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/fish
|
||||
name = "fish fillet"
|
||||
icon_state = "grilled_carp_slice"
|
||||
tastes = list("charred sushi" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/plain
|
||||
foodtype = MEAT
|
||||
|
||||
@@ -361,6 +368,7 @@
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/bear
|
||||
name = "bear steak"
|
||||
icon_state = "bearcook"
|
||||
tastes = list("meat" = 1, "salmon" = 1)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/xeno
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin/carpotoxin = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
|
||||
bitesize = 6
|
||||
filling_color = "#FA8072"
|
||||
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/fish
|
||||
tastes = list("fish" = 1)
|
||||
foodtype = MEAT
|
||||
|
||||
|
||||
@@ -136,6 +136,17 @@
|
||||
tastes = list("fries" = 3, "cheese" = 1)
|
||||
foodtype = VEGETABLES | GRAIN
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/chilicheesefries
|
||||
name = "chili cheese fries"
|
||||
desc = "Fries smothered in cheese -and- chilli."
|
||||
icon_state = "chilicheesefries"
|
||||
trash = /obj/item/trash/plate
|
||||
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 1)
|
||||
filling_color = "#FFD700"
|
||||
tastes = list("fries" = 3, "cheese" = 1)
|
||||
foodtype = VEGETABLES | GRAIN
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/badrecipe
|
||||
name = "burned mess"
|
||||
desc = "Someone should be demoted from cook for this."
|
||||
@@ -537,6 +548,15 @@
|
||||
tastes = list("butter" = 1)
|
||||
foodtype = DAIRY
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/butter/margarine
|
||||
name = "stick of margarine"
|
||||
desc = "A stick of lightly salted vegetable oil."
|
||||
icon_state = "marge"
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/cornoil = 2, /datum/reagent/consumable/sodiumchloride = 1)
|
||||
filling_color = "#FFD700"
|
||||
tastes = list("butter" = 1)
|
||||
foodtype = JUNKFOOD
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/onionrings
|
||||
name = "onion rings"
|
||||
desc = "Onion slices coated in batter."
|
||||
|
||||
@@ -21,6 +21,17 @@
|
||||
tastes = list("toast" = 1)
|
||||
foodtype = GRAIN
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/baconlettucetomato
|
||||
name = "blt sandwich"
|
||||
desc = "The classic bacon, lettuce tomato sandwich."
|
||||
icon = 'icons/obj/food/burgerbread.dmi'
|
||||
icon_state = "blt"
|
||||
trash = /obj/item/trash/plate
|
||||
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 2)
|
||||
tastes = list("bacon" = 1, "lettuce" = 1, "tomato" = 1, "mayo" = 1)
|
||||
foodtype = GRAIN | MEAT | VEGETABLES
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grilledcheese
|
||||
name = "grilled cheese sandwich"
|
||||
desc = "Goes great with Tomato soup!"
|
||||
@@ -136,8 +147,9 @@
|
||||
/obj/item/reagent_containers/food/snacks/tuna_sandwich
|
||||
name = "tuna sandwich"
|
||||
desc = "Both a salad and a sandwich in one."
|
||||
icon = 'icons/obj/food/burgerbread.dmi'
|
||||
icon_state = "tunasandwich"
|
||||
trash = /obj/item/trash/plate
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 12, /datum/reagent/consumable/nutriment/vitamin = 4)
|
||||
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
|
||||
tastes = list("tuna" = 4, "mayonnaise" = 2, "bread" = 2)
|
||||
foodtype = GRAIN | MEAT
|
||||
|
||||
@@ -179,3 +179,14 @@
|
||||
id = /datum/reagent/consumable/bbqsauce
|
||||
results = list(/datum/reagent/consumable/bbqsauce = 5)
|
||||
required_reagents = list(/datum/reagent/ash = 1, /datum/reagent/consumable/tomatojuice = 1, /datum/reagent/medicine/salglu_solution = 3, /datum/reagent/consumable/blackpepper = 1)
|
||||
|
||||
/datum/chemical_reaction/margarine
|
||||
name = "Margarine"
|
||||
id = "margarine"
|
||||
required_reagents = list(/datum/reagent/consumable/cornoil = 5, /datum/reagent/consumable/soymilk = 5, /datum/reagent/consumable/sodiumchloride = 1)
|
||||
mix_message = "The ingredients solidify into a stick of margarine."
|
||||
|
||||
/datum/chemical_reaction/margarine/on_reaction(datum/reagents/holder, multiplier)
|
||||
var/location = get_turf(holder.my_atom)
|
||||
for(var/i = 1, i <= multiplier, i++)
|
||||
new /obj/item/reagent_containers/food/snacks/butter/margarine(location)
|
||||
@@ -22,6 +22,15 @@
|
||||
result = /obj/item/reagent_containers/food/snacks/baconegg
|
||||
subcategory = CAT_EGG
|
||||
|
||||
/datum/crafting_recipe/food/wrap
|
||||
name = "Egg Wrap"
|
||||
reqs = list(/datum/reagent/consumable/soysauce = 10,
|
||||
/obj/item/reagent_containers/food/snacks/friedegg = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/cabbage = 1,
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/eggwrap
|
||||
subcategory = CAT_EGG
|
||||
|
||||
/datum/crafting_recipe/food/omelette
|
||||
name = "Omelette"
|
||||
reqs = list(
|
||||
|
||||
@@ -14,15 +14,6 @@
|
||||
result = /obj/item/reagent_containers/food/snacks/chawanmushi
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/wrap
|
||||
name = "Egg Wrap"
|
||||
reqs = list(/datum/reagent/consumable/soysauce = 10,
|
||||
/obj/item/reagent_containers/food/snacks/friedegg = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/cabbage = 1,
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/eggwrap
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/khachapuri
|
||||
name = "Khachapuri"
|
||||
reqs = list(
|
||||
@@ -93,6 +84,16 @@
|
||||
result = /obj/item/reagent_containers/food/snacks/cheesyfries
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/chilicheesefries
|
||||
name = "Chilli cheese fries"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/food/snacks/fries = 1,
|
||||
/obj/item/reagent_containers/food/snacks/cheesewedge = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/chili = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/chilicheesefries
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/eggplantparm
|
||||
name ="Eggplant parmigiana"
|
||||
reqs = list(
|
||||
|
||||
@@ -25,6 +25,17 @@
|
||||
result = /obj/item/reagent_containers/food/snacks/grilledcheese
|
||||
subcategory = CAT_SANDWICH
|
||||
|
||||
/datum/crafting_recipe/food/baconlettucetomato
|
||||
name = "BLT sandwich"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/food/snacks/meat/bacon = 2,
|
||||
/obj/item/reagent_containers/food/snacks/grown/cabbage = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/tomato = 1,
|
||||
/datum/reagent/consumable/mayonnaise = 5
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/baconlettucetomato
|
||||
subcategory = CAT_SANDWICH
|
||||
|
||||
/datum/crafting_recipe/food/slimesandwich
|
||||
name = "Jelly sandwich"
|
||||
reqs = list(
|
||||
@@ -99,7 +110,7 @@
|
||||
/obj/item/reagent_containers/food/snacks/breadslice/plain = 2,
|
||||
/obj/item/reagent_containers/food/snacks/tuna = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/onion = 1,
|
||||
/obj/item/reagent_containers/food/condiment/mayonnaise = 5
|
||||
/datum/reagent/consumable/mayonnaise = 5
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/tuna_sandwich
|
||||
subcategory = CAT_SANDWICH
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
|
||||
icon_grow = "bee_balm-grow"
|
||||
icon_dead = "bee_balm-dead"
|
||||
mutatelist = list(/obj/item/seeds/poppy/geranium, /obj/item/seeds/bee_balm/honey) //Lower odds of becoming honey
|
||||
mutatelist = list(/obj/item/seeds/poppy/geranium, /obj/item/seeds/bee_balm/honey_balm) //Lower odds of becoming honey
|
||||
reagents_add = list(/datum/reagent/medicine/spaceacillin = 0.1, /datum/reagent/space_cleaner/sterilizine = 0.05)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/bee_balm
|
||||
@@ -291,11 +291,11 @@
|
||||
foodtype = GROSS
|
||||
|
||||
// Beebalm
|
||||
/obj/item/seeds/bee_balm/honey
|
||||
/obj/item/seeds/bee_balm/honey_balm
|
||||
name = "pack of Honey Balm seeds"
|
||||
desc = "These seeds grow into Honey Balms."
|
||||
icon_state = "seed-bee_balmalt"
|
||||
species = "seed-bee_balm_alt"
|
||||
icon_state = "seed-honey_balm"
|
||||
species = "honey_balm"
|
||||
plantname = "Honey Balm Pods"
|
||||
product = /obj/item/reagent_containers/food/snacks/grown/bee_balm/honey
|
||||
endurance = 1
|
||||
@@ -304,16 +304,16 @@
|
||||
potency = 1
|
||||
growthstages = 3
|
||||
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
|
||||
icon_grow = "bee_balmalt-grow"
|
||||
icon_dead = "bee_balmalt-dead"
|
||||
icon_grow = "honey_balm-grow"
|
||||
icon_dead = "honey_balm-dead"
|
||||
reagents_add = list(/datum/reagent/consumable/honey = 0.1, /datum/reagent/lye = 0.3) //To make wax
|
||||
rarity = 30
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/bee_balm/honey
|
||||
seed = /obj/item/seeds/bee_balm/honey
|
||||
seed = /obj/item/seeds/bee_balm/honey_balm
|
||||
name = "honey balm"
|
||||
desc = "A large honey filled pod of a flower."
|
||||
icon_state = "bee_balmalt"
|
||||
icon_state = "honey_balm"
|
||||
filling_color = "#FF6347"
|
||||
bitesize_mod = 8
|
||||
tastes = list("wax" = 1)
|
||||
|
||||
@@ -392,7 +392,7 @@
|
||||
|
||||
/datum/plant_gene/trait/battery/on_attackby(obj/item/reagent_containers/food/snacks/grown/G, obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/stack/cable_coil))
|
||||
if(I.use_tool(src, user, 0, 5, max_level = JOB_SKILL_EXPERT))
|
||||
if(I.use_tool(src, user, 0, 5, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
|
||||
to_chat(user, "<span class='notice'>You add some cable to [G] and slide it inside the battery encasing.</span>")
|
||||
var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc)
|
||||
pocell.icon_state = G.icon_state
|
||||
|
||||
@@ -25,6 +25,17 @@
|
||||
var/mob/living/L = user.mob
|
||||
L.keybind_stop_active_blocking()
|
||||
|
||||
/datum/keybinding/living/active_block_toggle
|
||||
name = "active_block_toggle"
|
||||
full_name = "Block (Toggle)"
|
||||
category = CATEGORY_COMBAT
|
||||
description = "Toggles active blocking system using currenet in hand object, or any found object if applicable."
|
||||
|
||||
/datum/keybinding/living/active_block_toggle/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.keybind_toggle_active_blocking()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/active_parry
|
||||
hotkey_keys = list("Insert", "G")
|
||||
name = "active_parry"
|
||||
|
||||
@@ -390,7 +390,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
|
||||
to_chat(user, "<span class='warning'>There already is a string attached to this coin!</span>")
|
||||
return
|
||||
|
||||
if (W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC))
|
||||
if (W.use_tool(src, user, 0, 1, skill_gain_mult = BARE_USE_TOOL_MULT))
|
||||
add_overlay("coin_string_overlay")
|
||||
string_attached = 1
|
||||
to_chat(user, "<span class='notice'>You attach a string to the coin.</span>")
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/mob/living/carbon/alien/humanoid/doUnEquip(obj/item/I)
|
||||
. = ..()
|
||||
if(!. || !I)
|
||||
return
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
Die()
|
||||
|
||||
/obj/item/clothing/mask/facehugger/equipped(mob/M)
|
||||
. = ..()
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target)
|
||||
@@ -254,7 +255,7 @@
|
||||
return FALSE
|
||||
if(AmBloodsucker(M))
|
||||
return FALSE
|
||||
|
||||
|
||||
if(ismonkey(M))
|
||||
return 1
|
||||
|
||||
|
||||
@@ -227,19 +227,21 @@
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
|
||||
return
|
||||
if(href_list["toggle_helmet"])
|
||||
var/hardsuit_head = head && istype(head, /obj/item/clothing/head/helmet/space/hardsuit)
|
||||
if(!istype(head, /obj/item/clothing/head/helmet/space/hardsuit))
|
||||
return
|
||||
var/obj/item/clothing/head/helmet/space/hardsuit/hardsuit_head = head
|
||||
visible_message("<span class='danger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
|
||||
"<span class='userdanger'>[usr] tries to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>", \
|
||||
target = usr, target_message = "<span class='danger'>You try to [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
|
||||
if(!do_mob(usr, src, POCKET_STRIP_DELAY))
|
||||
if(!do_mob(usr, src, hardsuit_head ? head.strip_delay : POCKET_STRIP_DELAY))
|
||||
return
|
||||
visible_message("<span class='danger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
"<span class='userdanger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
target = usr, target_message = "<span class='danger'>You [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
|
||||
if(!istype(wear_suit, /obj/item/clothing/suit/space/hardsuit))
|
||||
if(!istype(wear_suit, /obj/item/clothing/suit/space/hardsuit) || (hardsuit_head ? (!head || head != hardsuit_head) : head))
|
||||
return
|
||||
var/obj/item/clothing/suit/space/hardsuit/hardsuit = wear_suit //This should be an hardsuit given all our checks
|
||||
hardsuit.ToggleHelmet()
|
||||
if(hardsuit.ToggleHelmet(FALSE))
|
||||
visible_message("<span class='danger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
"<span class='userdanger'>[usr] [hardsuit_head ? "retract" : "extend"] [src]'s helmet</span>", \
|
||||
target = usr, target_message = "<span class='danger'>You [hardsuit_head ? "retract" : "extend"] [src]'s helmet.</span>")
|
||||
return
|
||||
if(href_list["item"])
|
||||
var/slot = text2num(href_list["item"])
|
||||
|
||||
@@ -85,8 +85,11 @@
|
||||
FP.entered_dirs |= dir
|
||||
FP.bloodiness = S.bloody_shoes[S.blood_state]
|
||||
if(S.last_bloodtype)
|
||||
FP.blood_DNA += list(S.last_blood_DNA = S.last_bloodtype)
|
||||
FP.blood_DNA["color"] += S.last_blood_color
|
||||
FP.blood_DNA[S.last_blood_DNA] = S.last_bloodtype
|
||||
if(!FP.blood_DNA["color"])
|
||||
FP.blood_DNA["color"] = S.last_blood_color
|
||||
else
|
||||
FP.blood_DNA["color"] = BlendRGB(FP.blood_DNA["color"], S.last_blood_color)
|
||||
FP.update_icon()
|
||||
update_inv_shoes()
|
||||
//End bloody footprints
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
changeNext_move(data.block_end_click_cd_add)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/start_active_blocking(obj/item/I)
|
||||
/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I)
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
return FALSE
|
||||
if(!(I in held_items))
|
||||
return FALSE
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(!istype(data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
|
||||
CRASH("start_active_blocking called with an item with no valid data: [I] --> [I.block_parry_data]!")
|
||||
CRASH("ACTIVE_BLOCK_START called with an item with no valid data: [I] --> [I.block_parry_data]!")
|
||||
combat_flags |= COMBAT_FLAG_ACTIVE_BLOCKING
|
||||
active_block_item = I
|
||||
if(data.block_lock_attacking)
|
||||
@@ -83,9 +83,15 @@
|
||||
return FALSE
|
||||
// QOL: Instead of trying to just block with held item, grab first available item.
|
||||
var/obj/item/I = find_active_block_item()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
|
||||
var/list/other_items = list()
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_BLOCK_START, I, other_items) & COMPONENT_PREVENT_BLOCK_START)
|
||||
to_chat(src, "<span class='warning'>Something is preventing you from blocking!</span>")
|
||||
return
|
||||
if(!I)
|
||||
if(!length(other_items))
|
||||
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
|
||||
return
|
||||
I = other_items[1]
|
||||
if(!I.can_active_block())
|
||||
to_chat(src, "<span class='warning'>[I] is either not capable of being used to actively block, or is not currently in a state that can! (Try wielding it if it's twohanded, for example.)</span>")
|
||||
return
|
||||
@@ -104,7 +110,7 @@
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW)
|
||||
return
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
start_active_blocking(I)
|
||||
ACTIVE_BLOCK_START(I)
|
||||
|
||||
/**
|
||||
* Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE
|
||||
@@ -115,7 +121,8 @@
|
||||
for(var/obj/item/I in held_items - held)
|
||||
if(I.can_active_block())
|
||||
return I
|
||||
return held
|
||||
else
|
||||
return held
|
||||
|
||||
/**
|
||||
* Proc called by keybindings to stop active blocking.
|
||||
|
||||
@@ -24,25 +24,39 @@
|
||||
// yanderedev else if time
|
||||
var/obj/item/using_item = get_active_held_item()
|
||||
var/datum/block_parry_data/data
|
||||
var/datum/tool
|
||||
var/method
|
||||
if(using_item?.can_active_parry())
|
||||
data = using_item.block_parry_data
|
||||
method = ITEM_PARRY
|
||||
tool = using_item
|
||||
else if(mind?.martial_art?.can_martial_parry)
|
||||
data = mind.martial_art.block_parry_data
|
||||
method = MARTIAL_PARRY
|
||||
tool = mind.martial_art
|
||||
else if(combat_flags & COMBAT_FLAG_UNARMED_PARRY)
|
||||
data = block_parry_data
|
||||
method = UNARMED_PARRY
|
||||
tool = src
|
||||
else
|
||||
// QOL: If none of the above work, try to find another item.
|
||||
var/obj/item/backup = find_backup_parry_item()
|
||||
if(!backup)
|
||||
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
|
||||
return FALSE
|
||||
data = backup.block_parry_data
|
||||
using_item = backup
|
||||
if(backup)
|
||||
tool = backup
|
||||
data = backup.block_parry_data
|
||||
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)
|
||||
to_chat(src, "<span class='warning'>Something is preventing you from parrying!</span>")
|
||||
return
|
||||
if(!using_item && !method && length(other_items))
|
||||
using_item = other_items[1]
|
||||
method = ITEM_PARRY
|
||||
data = using_item.block_parry_data
|
||||
if(!method)
|
||||
to_chat(src, "<span class='warning'>You have nothing to parry with!</span>")
|
||||
return FALSE
|
||||
//QOL: Try to enable combat mode if it isn't already
|
||||
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
|
||||
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
|
||||
|
||||
@@ -315,7 +315,7 @@
|
||||
if (getFireLoss() > 0 || getToxLoss() > 0)
|
||||
if(src == user)
|
||||
to_chat(user, "<span class='notice'>You start fixing yourself...</span>")
|
||||
if(!W.use_tool(src, user, 50, 1, max_level = JOB_SKILL_TRAINED))
|
||||
if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
|
||||
to_chat(user, "<span class='warning'>You need more cable to repair [src]!</span>")
|
||||
return
|
||||
adjustFireLoss(-10)
|
||||
|
||||
@@ -227,7 +227,7 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
if(istype(W))
|
||||
if(equip_to_slot_if_possible(W, slot, FALSE, FALSE, FALSE, TRUE))
|
||||
if(equip_to_slot_if_possible(W, slot, FALSE, FALSE, FALSE, FALSE, TRUE))
|
||||
return TRUE
|
||||
|
||||
if(!W)
|
||||
|
||||
@@ -186,9 +186,8 @@
|
||||
GLOBAL_LIST_EMPTY(employmentCabinets)
|
||||
|
||||
/obj/structure/filingcabinet/employment
|
||||
var/cooldown = 0
|
||||
icon_state = "employmentcabinet"
|
||||
var/virgin = 1
|
||||
var/virgin = TRUE
|
||||
|
||||
/obj/structure/filingcabinet/employment/Initialize()
|
||||
. = ..()
|
||||
@@ -213,13 +212,12 @@ GLOBAL_LIST_EMPTY(employmentCabinets)
|
||||
new /obj/item/paper/contract/employment(src, employee)
|
||||
|
||||
/obj/structure/filingcabinet/employment/interact(mob/user)
|
||||
if(!cooldown)
|
||||
if(virgin)
|
||||
fillCurrent()
|
||||
virgin = 0
|
||||
cooldown = 1
|
||||
sleep(100) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win.
|
||||
cooldown = 0
|
||||
else
|
||||
if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_EMPLOYMENT_CABINET))
|
||||
to_chat(user, "<span class='warning'>[src] is jammed, give it a few seconds.</span>")
|
||||
..()
|
||||
return ..()
|
||||
|
||||
TIMER_COOLDOWN_START(src, COOLDOWN_EMPLOYMENT_CABINET, 10 SECONDS) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win.
|
||||
if(virgin)
|
||||
fillCurrent()
|
||||
virgin = FALSE
|
||||
return ..()
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
if(W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_TRAINED))
|
||||
if(W.use_tool(src, user, 0, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT))
|
||||
icon_state = "[fixture_type]-construct-stage2"
|
||||
stage = 2
|
||||
user.visible_message("[user.name] adds wires to [src].", \
|
||||
|
||||
@@ -51,17 +51,3 @@
|
||||
desc = "A .50AE bullet casing."
|
||||
caliber = ".50"
|
||||
projectile_type = /obj/item/projectile/bullet/a50AE
|
||||
|
||||
// .32 ACP (Improvised Pistol)
|
||||
|
||||
/obj/item/ammo_casing/c32acp
|
||||
name = ".32 bullet casing"
|
||||
desc = "A .32 bullet casing."
|
||||
caliber = "c32acp"
|
||||
projectile_type = /obj/item/projectile/bullet/c32acp
|
||||
|
||||
/obj/item/ammo_casing/r32acp
|
||||
name = ".32 rubber bullet casing"
|
||||
desc = "A .32 rubber bullet casing."
|
||||
caliber = "c32acp"
|
||||
projectile_type = /obj/item/projectile/bullet/r32acp
|
||||
|
||||
@@ -12,15 +12,6 @@
|
||||
e_cost = 200
|
||||
select_name = "kill"
|
||||
|
||||
/obj/item/ammo_casing/energy/lasergun/improvised
|
||||
projectile_type = /obj/item/projectile/beam/weak/improvised
|
||||
e_cost = 200
|
||||
select_name = "kill"
|
||||
|
||||
/obj/item/ammo_casing/energy/lasergun/improvised/upgraded
|
||||
projectile_type = /obj/item/projectile/beam/weak
|
||||
e_cost = 100
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/hos
|
||||
e_cost = 100
|
||||
|
||||
|
||||
@@ -55,18 +55,6 @@
|
||||
desc = "Designed to quickly reload revolvers. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with."
|
||||
ammo_type = /obj/item/ammo_casing/c38/match
|
||||
|
||||
/obj/item/ammo_box/c32mm
|
||||
name = "ammo box (.32 acp)"
|
||||
desc = "Lethal .32 acp bullets, there's forty in the box."
|
||||
ammo_type = /obj/item/ammo_casing/c32acp
|
||||
max_ammo = 40
|
||||
|
||||
/obj/item/ammo_box/r32mm
|
||||
name = "ammo box (rubber .32 acp)"
|
||||
desc = "Non-lethal .32 acp bullets, there's forty in the box."
|
||||
ammo_type = /obj/item/ammo_casing/r32acp
|
||||
max_ammo = 40
|
||||
|
||||
/obj/item/ammo_box/c9mm
|
||||
name = "ammo box (9mm)"
|
||||
icon_state = "9mmbox"
|
||||
|
||||
@@ -66,15 +66,3 @@
|
||||
caliber = ".50"
|
||||
max_ammo = 7
|
||||
multiple_sprites = 1
|
||||
|
||||
/obj/item/ammo_box/magazine/m32acp
|
||||
name = "pistol magazine (.32)"
|
||||
desc = "A crudely construction pistol magazine that holds .32 ACP rounds. It looks like it can only fit eight bullets."
|
||||
icon_state = "32acp"
|
||||
ammo_type = /obj/item/ammo_casing/c32acp
|
||||
caliber = "c32acp"
|
||||
max_ammo = 8
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/m32acp/empty
|
||||
start_empty = 1
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/obj/item/gun/ballistic/bow/pipe
|
||||
name = "pipe bow"
|
||||
desc = "Some sort of pipe made projectile weapon made of a durathread string and lots of bending. Used to fire arrows."
|
||||
desc = "Some sort of pipe-based projectile weapon made of string and lots of bending. Used to fire arrows."
|
||||
icon_state = "pipebow"
|
||||
item_state = "pipebow"
|
||||
force = 0
|
||||
force = 2
|
||||
|
||||
@@ -156,19 +156,3 @@
|
||||
name = "Syndicate Anti Tank Pistol"
|
||||
desc = "A massively impractical and silly monstrosity of a pistol that fires .50 calliber rounds. The recoil is likely to dislocate a variety of joints without proper bracing."
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
|
||||
////////////Improvised Pistol////////////
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/improvised
|
||||
name = "Improvised Pistol"
|
||||
desc = "An improvised pocket-sized pistol that fires .32 calibre rounds. It looks incredibly flimsy."
|
||||
icon_state = "ipistol"
|
||||
item_state = "pistol"
|
||||
mag_type = /obj/item/ammo_box/magazine/m32acp
|
||||
fire_delay = 7.5
|
||||
can_suppress = FALSE
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
spread = 15 // Keep the spread between 15 and 20. This hardlocks it into being a mid-range pistol, the magazine size means you're allowed to miss. Fills the mid-range niche that slugs/rifle and buckshot doesn't fill.
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/improvised/nomag
|
||||
spawnwithmagazine = FALSE // For crafting as you shouldn't get eight bullets for free otherwise people will reaper reload.
|
||||
|
||||
@@ -319,11 +319,11 @@
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
name = "improvised shotgun"
|
||||
desc = "A shoddy break-action breechloaded shotgun. Its lacklustre construction will probably result in it hurting people less than a normal shotgun."
|
||||
desc = "A shoddy break-action breechloaded shotgun. Its lacklustre construction shows in its lesser effectiveness."
|
||||
icon_state = "ishotgun"
|
||||
item_state = "shotgun"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
weapon_weight = WEAPON_MEDIUM // prevents shooting 2 at once, but doesn't require 2 hands
|
||||
force = 10
|
||||
slot_flags = null
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised
|
||||
@@ -331,12 +331,11 @@
|
||||
unique_reskin = null
|
||||
projectile_damage_multiplier = 0.9
|
||||
var/slung = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params)
|
||||
..()
|
||||
if(istype(A, /obj/item/stack/cable_coil) && !sawn_off)
|
||||
if(A.use_tool(src, user, 0, 10, max_level = JOB_SKILL_BASIC))
|
||||
if(A.use_tool(src, user, 0, 10, skill_gain_mult = EASY_USE_TOOL_MULT))
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
to_chat(user, "<span class='notice'>You tie the lengths of cable to the shotgun, making a sling.</span>")
|
||||
slung = TRUE
|
||||
@@ -358,7 +357,7 @@
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/improvised/sawn
|
||||
name = "sawn-off improvised shotgun"
|
||||
desc = "The barrel and stock have been sawn and filed down; it can fit in backpacks. You still need two hands to fire this, if you value unbroken wrists."
|
||||
desc = "The barrel and stock have been sawn and filed down; it can fit in backpacks. You wont want to shoot two of these at once if you value your wrists."
|
||||
icon_state = "ishotgun"
|
||||
item_state = "gun"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/improvised/attackby(obj/item/A, mob/user, params)
|
||||
..()
|
||||
if(istype(A, /obj/item/stack/cable_coil) && !sawn_off)
|
||||
if(A.use_tool(src, user, 0, 10, max_level = JOB_SKILL_BASIC))
|
||||
if(A.use_tool(src, user, 0, 10, skill_gain_mult = EASY_USE_TOOL_MULT))
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
to_chat(user, "<span class='notice'>You tie the lengths of cable to the rifle, making a sling.</span>")
|
||||
slung = TRUE
|
||||
|
||||
@@ -240,20 +240,3 @@
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
|
||||
////////////////
|
||||
// IMPROVISED //
|
||||
////////////////
|
||||
|
||||
/obj/item/gun/energy/e_gun/old/improvised
|
||||
name = "improvised energy rifle"
|
||||
desc = "A crude imitation of an energy gun. It works, however the beams are poorly focused and most of the energy is wasted before it reaches the target. Welp, it still burns things."
|
||||
icon_state = "improvised"
|
||||
ammo_x_offset = 1
|
||||
shaded_charge = 1
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/lasergun/improvised)
|
||||
|
||||
/obj/item/gun/energy/e_gun/old/improvised/upgraded
|
||||
name = "makeshift energy rifle"
|
||||
desc = "The new lens and upgraded parts gives this a higher capacity and more energy output, however, the shoddy construction still leaves it inferior to Nanotrasen's own energy weapons."
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/lasergun/improvised/upgraded)
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
/obj/item/projectile/beam/weak
|
||||
damage = 15
|
||||
|
||||
/obj/item/projectile/beam/weak/improvised
|
||||
damage = 10
|
||||
|
||||
/obj/item/projectile/beam/weak/penetrator
|
||||
armour_penetration = 50
|
||||
|
||||
|
||||
@@ -48,15 +48,3 @@
|
||||
L.Sleeping(300)
|
||||
else
|
||||
L.adjustStaminaLoss(25)
|
||||
|
||||
// .32 ACP (Improvised Pistol)
|
||||
|
||||
/obj/item/projectile/bullet/c32acp
|
||||
name = ".32 bullet"
|
||||
damage = 13
|
||||
|
||||
/obj/item/projectile/bullet/r32acp
|
||||
name = ".32 rubber bullet"
|
||||
damage = 3
|
||||
eyeblur = 1
|
||||
stamina = 20
|
||||
|
||||
@@ -258,9 +258,9 @@
|
||||
var/amount = text2num(params["amount"])
|
||||
if(amount == null)
|
||||
amount = text2num(input(usr,
|
||||
"Max 10. Buffer content will be split evenly.",
|
||||
"Max 20. Buffer content will be split evenly.",
|
||||
"How many to make?", 1))
|
||||
amount = clamp(round(amount), 0, 10)
|
||||
amount = clamp(round(amount), 0, 20)
|
||||
if (amount <= 0)
|
||||
return FALSE
|
||||
// Get units per item
|
||||
|
||||
@@ -132,8 +132,8 @@
|
||||
"<span class='userdanger'>You're covered in boiling oil!</span>")
|
||||
M.emote("scream")
|
||||
playsound(M, 'sound/machines/fryer/deep_fryer_emerge.ogg', 25, TRUE)
|
||||
var/oil_damage = (holder.chem_temp / fry_temperature) * 0.33 //Damage taken per unit
|
||||
M.adjustFireLoss(min(35, oil_damage * reac_volume)) //Damage caps at 35
|
||||
var/oil_damage = max((holder.chem_temp / fry_temperature) * 0.33,1) //Damage taken per unit
|
||||
M.adjustFireLoss(oil_damage * max(reac_volume,20)) //Damage caps at 20
|
||||
else
|
||||
..()
|
||||
return TRUE
|
||||
@@ -866,4 +866,4 @@
|
||||
taste_mult = 2
|
||||
taste_description = "fizzy sweetness"
|
||||
value = REAGENT_VALUE_COMMON
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +71,9 @@
|
||||
if(data["blood_DNA"])
|
||||
B.blood_DNA[data["blood_DNA"]] = data["blood_type"]
|
||||
if(!B.blood_DNA["color"])
|
||||
B.blood_DNA["color"] = list(data["bloodcolor"])
|
||||
B.blood_DNA["color"] = data["bloodcolor"]
|
||||
else
|
||||
B.blood_DNA["color"] = BlendRGB(B.blood_DNA["color"], data["bloodcolor"])
|
||||
if(B.reagents)
|
||||
B.reagents.add_reagent(type, reac_volume)
|
||||
B.update_icon()
|
||||
|
||||
@@ -30,14 +30,6 @@
|
||||
build_path = /obj/item/ammo_box/c38
|
||||
category = list("initial", "Security")
|
||||
|
||||
/datum/design/r32acp
|
||||
name = "Rubber Pistol Bullet (.32)"
|
||||
id = "r32acp"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/iron = 250)
|
||||
build_path = /obj/item/ammo_casing/r32acp
|
||||
category = list("initial", "Security")
|
||||
|
||||
/////////////////
|
||||
///Hacked Gear //
|
||||
/////////////////
|
||||
@@ -206,22 +198,3 @@
|
||||
build_path = /obj/item/clothing/head/foilhat
|
||||
category = list("hacked", "Misc")
|
||||
|
||||
/datum/design/c32acp
|
||||
name = "Pistol Bullet (.32)"
|
||||
id = "c32acp"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/iron = 500)
|
||||
build_path = /obj/item/ammo_casing/c32acp
|
||||
category = list("hacked", "Security")
|
||||
|
||||
/////////////////
|
||||
// Magazines //
|
||||
/////////////////
|
||||
|
||||
/datum/design/m32acp
|
||||
name = "Empty .32 Magazine"
|
||||
id = "m32acp"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/iron = 10000)
|
||||
build_path = /obj/item/ammo_box/magazine/m32acp/empty
|
||||
category = list("hacked", "Security")
|
||||
|
||||
@@ -289,11 +289,3 @@
|
||||
materials = list(/datum/material/iron = 6500, /datum/material/glass = 50)
|
||||
build_path = /obj/item/weaponcrafting/improvised_parts/trigger_assembly
|
||||
category = list("initial", "Misc")
|
||||
|
||||
/datum/design/focusing_lens
|
||||
name = "Makeshift Lens"
|
||||
id = "makeshift_lens"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/iron = 2000, /datum/material/glass = 4000)
|
||||
build_path = /obj/item/weaponcrafting/improvised_parts/makeshift_lens
|
||||
category = list("initial", "Misc")
|
||||
|
||||
@@ -158,11 +158,3 @@
|
||||
materials = list(/datum/material/iron = 150, /datum/material/glass = 150)
|
||||
build_path = /obj/item/geiger_counter
|
||||
category = list("initial", "Tools")
|
||||
|
||||
/datum/design/saw
|
||||
name = "Hand Saw"
|
||||
id = "handsaw"
|
||||
build_type = AUTOLATHE
|
||||
materials = list(/datum/material/iron = 500)
|
||||
build_path = /obj/item/hatchet/saw
|
||||
category = list("initial", "Tools")
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
"<span class='notice'>You extend [holder] from your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.</span>",
|
||||
"<span class='italics'>You hear a short mechanical noise.</span>")
|
||||
playsound(get_turf(owner), 'sound/mecha/mechmove03.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/cyberimp/arm/ui_action_click()
|
||||
if(crit_fail || (organ_flags & ORGAN_FAILING) || (!holder && !contents.len))
|
||||
@@ -273,12 +274,29 @@
|
||||
desc = "A deployable riot shield to help deal with civil unrest."
|
||||
contents = newlist(/obj/item/shield/riot/implant)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/shield/Extend(obj/item/I)
|
||||
/obj/item/organ/cyberimp/arm/shield/Extend(obj/item/I, silent = FALSE)
|
||||
if(I.obj_integrity == 0) //that's how the shield recharge works
|
||||
to_chat(owner, "<span class='warning'>[I] is still too unstable to extend. Give it some time!</span>")
|
||||
if(!silent)
|
||||
to_chat(owner, "<span class='warning'>[I] is still too unstable to extend. Give it some time!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/cyberimp/arm/shield/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE)
|
||||
. = ..()
|
||||
if(.)
|
||||
RegisterSignal(M, COMSIG_LIVING_ACTIVE_BLOCK_START, .proc/on_signal)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/shield/Remove(special = FALSE)
|
||||
UnregisterSignal(owner, COMSIG_LIVING_ACTIVE_BLOCK_START)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/cyberimp/arm/shield/proc/on_signal(datum/source, obj/item/blocking_item, list/other_items)
|
||||
if(!blocking_item) //if they don't have something
|
||||
var/obj/item/shield/S = locate() in contents
|
||||
if(!Extend(S, TRUE))
|
||||
return
|
||||
other_items += S
|
||||
|
||||
/obj/item/organ/cyberimp/arm/shield/emag_act()
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
|
||||
@@ -50,6 +50,87 @@
|
||||
-->
|
||||
<div class="commit sansserif">
|
||||
|
||||
<h2 class="date">08 July 2020</h2>
|
||||
<h3 class="author">DeltaFire15 updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">The kill-once objective now works properly.</li>
|
||||
</ul>
|
||||
<h3 class="author">EmeraldSundisk updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">CogStation now has an apothecary</li>
|
||||
<li class="rscdel">Removes an outdated note on sleepers</li>
|
||||
<li class="tweak">Readjusts CogStation's chemistry lab</li>
|
||||
<li class="tweak">Slight area designation adjustments for Robotics</li>
|
||||
<li class="bugfix">The arrivals plaque should be readable now</li>
|
||||
</ul>
|
||||
<h3 class="author">Owai-Seek updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Margarine, Chili Cheese Fries.</li>
|
||||
<li class="tweak">Egg Wraps are now categorized under egg foods.</li>
|
||||
<li class="bugfix">Tuna Sandwich crafting/sprite is now visible.</li>
|
||||
<li class="imageadd">Icons for chicken, cooked chicken, steak, grilled carp, corndogs</li>
|
||||
<li class="imageadd">Icons for chili cheese fries, margarine, BLT sandwich</li>
|
||||
<li class="imageadd">(Unused) icons for raw meatballs, and lard</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">07 July 2020</h2>
|
||||
<h3 class="author">KasparoVy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">Fixes misaligned south-facing silver legwraps sprite.</li>
|
||||
</ul>
|
||||
<h3 class="author">Owai-Seek updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">Bee Balm is now visible.</li>
|
||||
</ul>
|
||||
<h3 class="author">Weblure updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">Fixed the slowdown formula for small character sprites; you guys don't use custom sprite sizes so just ignore these changes.</li>
|
||||
<li class="bugfix">Fixed the "Move it to the threshold" button; it now does what it says.</li>
|
||||
<li class="tweak">Reworded some text to be clearer.</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">05 July 2020</h2>
|
||||
<h3 class="author">Ghommie updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">You can now actually gain wiring experience from using cable coils.</li>
|
||||
<li class="bugfix">Opening the View Skill Panel shouldn't trigger messages about insufficient admin priviledges anymore.</li>
|
||||
</ul>
|
||||
<h3 class="author">Yakumo Chen, kappa-sama updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscdel">Removes improvised handguns</li>
|
||||
<li class="rscdel">removed handsaws, improvised gun barrels (you can use atmos pipes again)</li>
|
||||
<li class="balance">Guncrafting is less time and resource intensive</li>
|
||||
<li class="tweak">Item names in guncrafting are user-friendly.</li>
|
||||
</ul>
|
||||
<h3 class="author">kappa-sama updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">cloth string to replace durathread string</li>
|
||||
<li class="rscdel">durathread string</li>
|
||||
<li class="balance">All bows and arrows have had crafting times significantly reduced, coming out at up to 6 times faster crafting speeds. Improvised bows no longer require durathread; instead, they use cloth materials.</li>
|
||||
</ul>
|
||||
<h3 class="author">silicons updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">active blocking now has a toggle keybind</li>
|
||||
<li class="rscadd">auto bunker override verb has been added</li>
|
||||
<li class="balance">shields take 2.5 stam instead of 3.5 stam per second to maintain block</li>
|
||||
<li class="rscadd">Cybernetic implant shields will auto-extend and be used to block if the user has no item to block with</li>
|
||||
</ul>
|
||||
<h3 class="author">timothyteakettle updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">cooking oil is now far less lethal, requiring a higher volume of the reagent to deal more damage</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">04 July 2020</h2>
|
||||
<h3 class="author">Sonic121x updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">crushed Soldry sodacan</li>
|
||||
<li class="rscadd">digitigrade version of chief medical officer's turtleneck and captain's female formal outfit.</li>
|
||||
</ul>
|
||||
<h3 class="author">silicons updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="refactor">blood_DNA["color"] is now a single variable instead of a list</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">03 July 2020</h2>
|
||||
<h3 class="author">Arturlang updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
|
||||
@@ -26232,3 +26232,61 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
|
||||
- tweak: Witchhunter hat no longer obscures mask ears ,eyes, face and mouth
|
||||
timothyteakettle:
|
||||
- bugfix: bloodpacks initialise correctly now
|
||||
2020-07-04:
|
||||
Sonic121x:
|
||||
- rscadd: crushed Soldry sodacan
|
||||
- rscadd: digitigrade version of chief medical officer's turtleneck and captain's
|
||||
female formal outfit.
|
||||
silicons:
|
||||
- refactor: blood_DNA["color"] is now a single variable instead of a list
|
||||
2020-07-05:
|
||||
Ghommie:
|
||||
- bugfix: You can now actually gain wiring experience from using cable coils.
|
||||
- bugfix: Opening the View Skill Panel shouldn't trigger messages about insufficient
|
||||
admin priviledges anymore.
|
||||
Yakumo Chen, kappa-sama:
|
||||
- rscdel: Removes improvised handguns
|
||||
- rscdel: removed handsaws, improvised gun barrels (you can use atmos pipes again)
|
||||
- balance: Guncrafting is less time and resource intensive
|
||||
- tweak: Item names in guncrafting are user-friendly.
|
||||
kappa-sama:
|
||||
- rscadd: cloth string to replace durathread string
|
||||
- rscdel: durathread string
|
||||
- balance: All bows and arrows have had crafting times significantly reduced, coming
|
||||
out at up to 6 times faster crafting speeds. Improvised bows no longer require
|
||||
durathread; instead, they use cloth materials.
|
||||
silicons:
|
||||
- tweak: active blocking now has a toggle keybind
|
||||
- rscadd: auto bunker override verb has been added
|
||||
- balance: shields take 2.5 stam instead of 3.5 stam per second to maintain block
|
||||
- rscadd: Cybernetic implant shields will auto-extend and be used to block if the
|
||||
user has no item to block with
|
||||
timothyteakettle:
|
||||
- tweak: cooking oil is now far less lethal, requiring a higher volume of the reagent
|
||||
to deal more damage
|
||||
2020-07-07:
|
||||
KasparoVy:
|
||||
- tweak: Fixes misaligned south-facing silver legwraps sprite.
|
||||
Owai-Seek:
|
||||
- bugfix: Bee Balm is now visible.
|
||||
Weblure:
|
||||
- bugfix: Fixed the slowdown formula for small character sprites; you guys don't
|
||||
use custom sprite sizes so just ignore these changes.
|
||||
- bugfix: Fixed the "Move it to the threshold" button; it now does what it says.
|
||||
- tweak: Reworded some text to be clearer.
|
||||
2020-07-08:
|
||||
DeltaFire15:
|
||||
- bugfix: The kill-once objective now works properly.
|
||||
EmeraldSundisk:
|
||||
- rscadd: CogStation now has an apothecary
|
||||
- rscdel: Removes an outdated note on sleepers
|
||||
- tweak: Readjusts CogStation's chemistry lab
|
||||
- tweak: Slight area designation adjustments for Robotics
|
||||
- bugfix: The arrivals plaque should be readable now
|
||||
Owai-Seek:
|
||||
- rscadd: Margarine, Chili Cheese Fries.
|
||||
- tweak: Egg Wraps are now categorized under egg foods.
|
||||
- bugfix: Tuna Sandwich crafting/sprite is now visible.
|
||||
- imageadd: Icons for chicken, cooked chicken, steak, grilled carp, corndogs
|
||||
- imageadd: Icons for chili cheese fries, margarine, BLT sandwich
|
||||
- imageadd: (Unused) icons for raw meatballs, and lard
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 261 KiB After Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@@ -63,7 +63,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
|
||||
startHunger = M.nutrition
|
||||
if(pollStarted == FALSE)
|
||||
pollStarted = TRUE
|
||||
candies = pollGhostCandidates("Do you want and agree to play as a clone of [M], respect their character and not engage in ERP without permission from the original?", ignore_category = POLL_IGNORE_CLONE)
|
||||
candies = pollGhostCandidates("Do you want to play as [M]'s defective clone? (Don't ERP without permission from the original)", ignore_category = POLL_IGNORE_CLONE)
|
||||
log_reagent("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.")
|
||||
if(20 to INFINITY)
|
||||
if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there!
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "code\__DEFINES\configuration.dm"
|
||||
#include "code\__DEFINES\construction.dm"
|
||||
#include "code\__DEFINES\contracts.dm"
|
||||
#include "code\__DEFINES\cooldowns.dm"
|
||||
#include "code\__DEFINES\cult.dm"
|
||||
#include "code\__DEFINES\diseases.dm"
|
||||
#include "code\__DEFINES\DNA.dm"
|
||||
@@ -743,7 +744,6 @@
|
||||
#include "code\game\machinery\dna_scanner.dm"
|
||||
#include "code\game\machinery\doppler_array.dm"
|
||||
#include "code\game\machinery\droneDispenser.dm"
|
||||
#include "code\game\machinery\exp_cloner.dm"
|
||||
#include "code\game\machinery\firealarm.dm"
|
||||
#include "code\game\machinery\flasher.dm"
|
||||
#include "code\game\machinery\gulag_item_reclaimer.dm"
|
||||
@@ -1150,7 +1150,6 @@
|
||||
#include "code\game\objects\items\tanks\tanks.dm"
|
||||
#include "code\game\objects\items\tanks\watertank.dm"
|
||||
#include "code\game\objects\items\tools\crowbar.dm"
|
||||
#include "code\game\objects\items\tools\saw.dm"
|
||||
#include "code\game\objects\items\tools\screwdriver.dm"
|
||||
#include "code\game\objects\items\tools\weldingtool.dm"
|
||||
#include "code\game\objects\items\tools\wirecutters.dm"
|
||||
@@ -1805,6 +1804,7 @@
|
||||
#include "code\modules\client\preferences_toggles.dm"
|
||||
#include "code\modules\client\preferences_vr.dm"
|
||||
#include "code\modules\client\verbs\aooc.dm"
|
||||
#include "code\modules\client\verbs\autobunker.dm"
|
||||
#include "code\modules\client\verbs\etips.dm"
|
||||
#include "code\modules\client\verbs\looc.dm"
|
||||
#include "code\modules\client\verbs\minimap.dm"
|
||||
@@ -2415,7 +2415,6 @@
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\death.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\humanoid.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\humanoid_defense.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\inventory.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\life.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\queen.dm"
|
||||
#include "code\modules\mob\living\carbon\alien\humanoid\update_icons.dm"
|
||||
|
||||