diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm
index 3e26d117b2d..b9b4225a414 100644
--- a/code/__HELPERS/turfs.dm
+++ b/code/__HELPERS/turfs.dm
@@ -7,4 +7,7 @@
return mloc
/proc/iswall(turf/T)
- return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall) || istype(T, /turf/simulated/shuttle/wall))
\ No newline at end of file
+ return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall) || istype(T, /turf/simulated/shuttle/wall))
+
+/proc/isfloor(turf/T)
+ return (istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor) || istype(T, /turf/simulated/shuttle/floor))
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 49252eaac64..866e2c1b9fa 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -855,7 +855,7 @@ About the new airlock wires panel:
return
src.add_fingerprint(user)
- if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
+ if(!repairing && (istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
var/obj/item/weapon/weldingtool/W = C
if(W.remove_fuel(0,user))
if(!src.welded)
@@ -869,7 +869,7 @@ About the new airlock wires panel:
else if(istype(C, /obj/item/weapon/screwdriver))
if (src.p_open)
if (stat & BROKEN)
- usr << "The airlock control panel is too damaged to be closed!"
+ usr << "The panel is broken and cannot be closed."
else
src.p_open = 0
else
@@ -884,7 +884,7 @@ About the new airlock wires panel:
else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE
var/obj/item/weapon/pai_cable/cable = C
cable.plugin(src, user)
- else if(istype(C, /obj/item/weapon/crowbar))
+ else if(!repairing && istype(C, /obj/item/weapon/crowbar))
var/beingcrowbarred = null
if(istype(C, /obj/item/weapon/crowbar) )
beingcrowbarred = 1 //derp, Agouri
@@ -1121,7 +1121,7 @@ About the new airlock wires panel:
update_icon()
/obj/machinery/door/airlock/proc/hasPower()
- return ((src.secondsMainPowerLost==0 || src.secondsBackupPowerLost==0) && !(stat & NOPOWER))
+ return ((src.secondsMainPowerLost==0 || src.secondsBackupPowerLost==0) && !(stat & NOPOWER|BROKEN))
/obj/machinery/door/airlock/proc/prison_open()
src.unlock()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index c3ab77d74a1..306af92f375 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -2,6 +2,8 @@
#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
+#define DOOR_REPAIR_AMOUNT 50 //amount of health regained per stack amount used
+
/obj/machinery/door
name = "Door"
desc = "It opens and closes."
@@ -29,6 +31,7 @@
var/emitter_resistance = 10 // Amount of emitter hits doors whistand
var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon
var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon
+ var/obj/item/stack/sheet/metal/repairing
//Multi-tile doors
dir = EAST
@@ -162,7 +165,6 @@
tforce = AM:throwforce
playsound(src.loc, hitsound, 100, 1)
take_damage(tforce)
- //..() //Does this really need to be here twice? The parent proc doesn't even do anything yet. - Nodrak
return
/obj/machinery/door/attack_ai(mob/user as mob)
@@ -185,27 +187,69 @@
user = null
if(!src.requiresID())
user = null
+
if(istype(I, /obj/item/stack/sheet/metal))
if(stat & BROKEN)
- user << "\blue [src.name] is damaged beyond repair and must be reconstructed!"
+ user << "It looks like \the [src] is pretty busted. It's going to need more than just patching up now."
return
if(health >= maxhealth)
- user << "\blue Nothing to fix!"
+ user << "Nothing to fix!"
return
+ if(!density)
+ user << "\The [src] must be closed before you can repair it."
+ return
+
+ //figure out how much metal we need
+ var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT
+ amount_needed = (round(amount_needed) == amount_needed)? amount_needed : round(amount_needed) + 1 //Why does BYOND not have a ceiling proc?
+
var/obj/item/stack/sheet/metal/metalstack = I
- var/health_per_sheet = 50
- var/initialhealth = health
- src.health = min(maxhealth, health + 100, health + (metalstack.amount * health_per_sheet))
- user.visible_message("\The [user] patches some dents on \the [src] with \the [metalstack].")
- metalstack.use(round((health - initialhealth)/health_per_sheet))
+ var/transfer
+ if (repairing)
+ transfer = metalstack.transfer_to(repairing, amount_needed - repairing.amount)
+ if (!transfer)
+ user << "You must weld or remove \the [repairing] from \the [src] before you can add anything else."
+ else
+ repairing = metalstack.split(amount_needed)
+ if (repairing)
+ repairing.loc = src
+ transfer = repairing.amount
+
+ if (transfer)
+ user << "You fit [transfer] [metalstack.singular_name]\s to damaged and broken parts on \the [src]."
+
return
- if(src.density && ((operable() && istype(I, /obj/item/weapon/card/emag)) || istype(I, /obj/item/weapon/melee/energy/blade)))
+ if(repairing && istype(I, /obj/item/weapon/weldingtool))
+ if(!density)
+ user << "\The [src] must be closed before you can repair it."
+ return
+
+ var/obj/item/weapon/weldingtool/welder = I
+ if(welder.remove_fuel(0,user))
+ user << "You start to fix dents and weld \the [repairing] into place."
+ playsound(src, 'sound/items/Welder.ogg', 100, 1)
+ if(do_after(user, 5 * repairing.amount) && welder && welder.isOn())
+ user << "You finish repairing the damage to \the [src]."
+ health = between(health, health + repairing.amount*DOOR_REPAIR_AMOUNT, maxhealth)
+ update_icon()
+ del(repairing)
+ return
+
+ if(repairing && istype(I, /obj/item/weapon/crowbar))
+ user << "You remove \the [repairing]."
+ playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
+ repairing.loc = user.loc
+ repairing = null
+ return
+
+ if(src.density && (operable() && istype(I, /obj/item/weapon/card/emag)))
flick("door_spark", src)
sleep(6)
open()
operating = -1
return 1
+
//psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them.
if(src.density && istype(I, /obj/item/weapon) && user.a_intent == "hurt" && !istype(I, /obj/item/weapon/card))
var/obj/item/weapon/W = I
@@ -213,16 +257,18 @@
if(W.force < min_force)
user.visible_message("\red \The [user] hits \the [src] with \the [W] with no visible effect." )
else
- user.visible_message("\red \The [user] forcefully slams \the [src] with \the [W]!" )
+ user.visible_message("\red \The [user] forcefully strikes \the [src] with \the [W]!" )
playsound(src.loc, hitsound, 100, 1)
take_damage(W.force)
return
+
if(src.allowed(user) && operable())
if(src.density)
open()
else
close()
return
+
if(src.density && !(stat & (NOPOWER|BROKEN)))
flick("door_deny", src)
return
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index ee0aa22a708..71fb87f9ad0 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -28,6 +28,7 @@
icon_state = "sheet-glass"
matter = null
created_window = /obj/structure/window/basic
+ stacktype = /obj/item/stack/sheet/glass
/obj/item/stack/sheet/glass/attack_self(mob/user as mob)
construct_window(user)
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index f3b8face4eb..fccce08dc22 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -140,6 +140,7 @@ obj/item/stack/sheet/mineral/iron/New()
name = "plastic sheets"
icon_state = "sheet-plastic"
perunit = 2000
+ stacktype = /obj/item/stack/sheet/mineral/plastic
/obj/item/stack/sheet/mineral/gold
name = "gold"
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 3a3fe552fc7..a5336c07978 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -92,6 +92,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
icon_state = "sheet-metal"
throwforce = 14.0
flags = FPRINT | TABLEPASS | CONDUCT
+ stacktype = /obj/item/stack/sheet/metal
/obj/item/stack/sheet/metal/New(var/loc, var/amount=null)
recipes = metal_recipes
@@ -152,6 +153,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
desc = "One can only guess that this is a bunch of wood."
singular_name = "wood plank"
icon_state = "sheet-wood"
+ stacktype = /obj/item/stack/sheet/wood
/obj/item/stack/sheet/wood/New(var/loc, var/amount=null)
recipes = wood_recipes
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index e14c7f2b1e6..2ab4f72bd28 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -16,9 +16,12 @@
var/singular_name
var/amount = 1
var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount
+ var/stacktype //determines whether different stack types can merge
/obj/item/stack/New(var/loc, var/amount=null)
..()
+ if (!stacktype)
+ stacktype = type
if (amount)
src.amount = amount
return
@@ -93,6 +96,43 @@
onclose(user, "stack")
return
+/obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
+ var/required = quantity*recipe.req_amount
+ var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount)
+
+ if (!can_use(required))
+ if (produced>1)
+ user << "\red You haven't got enough [src] to build \the [produced] [recipe.title]\s!"
+ else
+ user << "\red You haven't got enough [src] to build \the [recipe.title]!"
+ return
+
+ if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc))
+ user << "\red There is another [recipe.title] here!"
+ return
+
+ if (recipe.on_floor && !isfloor(user.loc))
+ user << "\red \The [recipe.title] must be constructed on the floor!"
+ return
+
+ if (recipe.time)
+ user << "\blue Building [recipe.title] ..."
+ if (!do_after(user, recipe.time))
+ return
+
+ if (use(required))
+ var/atom/O = new recipe.result_type(user.loc)
+ O.set_dir(user.dir)
+ O.add_fingerprint(user)
+
+ if (istype(O, /obj/item/stack))
+ var/obj/item/stack/S = O
+ S.amount = produced
+
+ if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
+ for (var/obj/item/I in O)
+ del(I)
+
/obj/item/stack/Topic(href, href_list)
..()
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
@@ -108,64 +148,37 @@
if (href_list["sublist"])
var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])]
recipes_list = srl.recipes
+
var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])]
var/multiplier = text2num(href_list["multiplier"])
if (!multiplier || (multiplier <= 0)) //href exploit protection
return
- if (src.amount < R.req_amount*multiplier)
- if (R.req_amount*multiplier>1)
- usr << "\red You haven't got enough [src] to build \the [R.req_amount*multiplier] [R.title]\s!"
- else
- usr << "\red You haven't got enough [src] to build \the [R.title]!"
- return
- if (R.one_per_turf && (locate(R.result_type) in usr.loc))
- usr << "\red There is another [R.title] here!"
- return
- if (R.on_floor && !istype(usr.loc, /turf/simulated/floor))
- usr << "\red \The [R.title] must be constructed on the floor!"
- return
- if (R.time)
- usr << "\blue Building [R.title] ..."
- if (!do_after(usr, R.time))
- return
- if (src.amount < R.req_amount*multiplier)
- return
- var/atom/O = new R.result_type( usr.loc )
- O.set_dir(usr.dir)
- if (R.max_res_amount>1)
- var/obj/item/stack/new_item = O
- new_item.amount = R.res_amount*multiplier
- //new_item.add_to_stacks(usr)
- src.amount-=R.req_amount*multiplier
- if (src.amount<=0)
- var/oldsrc = src
- src = null //dont kill proc after del()
- usr.before_take_item(oldsrc)
- del(oldsrc)
- if (istype(O,/obj/item) && istype(usr,/mob/living/carbon))
- usr.put_in_hands(O)
- O.add_fingerprint(usr)
- //BubbleWrap - so newly formed boxes are empty
- if ( istype(O, /obj/item/weapon/storage) )
- for (var/obj/item/I in O)
- del(I)
- //BubbleWrap END
+
+ src.produce_recipe(R, multiplier, usr)
+
if (src && usr.machine==src) //do not reopen closed window
spawn( 0 )
src.interact(usr)
return
return
-/obj/item/stack/proc/use(var/used)
+//Return 1 if an immediate subsequent call to use() would succeed.
+//Ensures that code dealing with stacks uses the same logic
+/obj/item/stack/proc/can_use(var/used)
if (amount < used)
return 0
+ return 1
+
+/obj/item/stack/proc/use(var/used)
+ if (!can_use(used))
+ return 0
amount -= used
if (amount <= 0)
- var/oldsrc = src
- src = null //dont kill proc after del()
- if(usr)
- usr.before_take_item(oldsrc)
- del(oldsrc)
+ spawn(0) //delete the empty stack once the current context yields
+ if (amount <= 0) //check again in case someone transferred stuff to us
+ if(usr)
+ usr.before_take_item(src)
+ del(src)
return 1
/obj/item/stack/proc/add(var/extra)
@@ -175,62 +188,95 @@
amount += extra
return 1
+/*
+ The transfer and split procs work differently than use() and add().
+ Whereas those procs take no action if the desired amount cannot be added or removed these procs will try to transfer whatever they can.
+ They also remove an equal amount from the source stack.
+*/
+
+//attempts to transfer amount to S, and returns the amount actually transferred
+/obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null)
+ if (!amount)
+ return 0
+ if (stacktype != S.stacktype)
+ return 0
+ if (isnull(tamount))
+ tamount = src.amount
+
+ var/transfer = max(min(tamount, src.amount, (S.max_amount - S.amount)), 0)
+
+ var/orig_amount = src.amount
+ if (transfer && src.use(transfer))
+ S.add(transfer)
+ if (prob(transfer/orig_amount * 100))
+ S.copy_evidences(src)
+ return transfer
+ return 0
+
+//creates a new stack with the specified amount
+/obj/item/stack/proc/split(var/tamount)
+ if (!amount)
+ return null
+
+ var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0)
+
+ var/orig_amount = src.amount
+ if (transfer && src.use(transfer))
+ var/obj/item/stack/newstack = new src.type(loc, transfer)
+ if (prob(transfer/orig_amount * 100))
+ newstack.copy_evidences(src)
+ return newstack
+ return null
+
/obj/item/stack/proc/get_amount()
return amount
/obj/item/stack/proc/add_to_stacks(mob/usr as mob)
- var/obj/item/stack/oldsrc = src
- src = null
for (var/obj/item/stack/item in usr.loc)
- if (item==oldsrc)
+ if (item==src)
continue
- if (!istype(item, oldsrc.type))
- continue
- if (item.amount>=item.max_amount)
- continue
- oldsrc.attackby(item, usr)
- usr << "You add new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
- if(!oldsrc)
+ var/transfer = src.transfer_to(item)
+ if (transfer)
+ usr << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
+ if(!amount)
break
/obj/item/stack/attack_hand(mob/user as mob)
if (user.get_inactive_hand() == src)
- var/obj/item/stack/F = new src.type(user, 1)
- F.copy_evidences(src)
- user.put_in_hands(F)
- src.add_fingerprint(user)
- F.add_fingerprint(user)
- use(1)
- if (src && usr.machine==src)
- spawn(0) src.interact(usr)
+ var/obj/item/stack/F = src.split(1)
+ if (F)
+ user.put_in_hands(F)
+ src.add_fingerprint(user)
+ F.add_fingerprint(user)
+ spawn(0)
+ if (src && usr.machine==src)
+ src.interact(usr)
else
..()
return
/obj/item/stack/attackby(obj/item/W as obj, mob/user as mob)
..()
- if (istype(W, src.type))
+ if (istype(W, /obj/item/stack))
var/obj/item/stack/S = W
- if (S.amount >= max_amount)
- return 1
- var/to_transfer as num
+
if (user.get_inactive_hand()==src)
- to_transfer = 1
+ src.transfer_to(S, 1)
else
- to_transfer = min(src.amount, S.max_amount-S.amount)
- S.add(to_transfer)
- if (S && usr.machine==S)
- spawn(0) S.interact(usr)
- src.use(to_transfer)
- if (src && usr.machine==src)
- spawn(0) src.interact(usr)
+ src.transfer_to(S)
+
+ spawn(0) //give the stacks a chance to delete themselves if necessary
+ if (S && usr.machine==S)
+ S.interact(usr)
+ if (src && usr.machine==src)
+ src.interact(usr)
else return ..()
/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj)
- src.blood_DNA = from.blood_DNA
- src.fingerprints = from.fingerprints
- src.fingerprintshidden = from.fingerprintshidden
- src.fingerprintslast = from.fingerprintslast
+ src.blood_DNA |= from.blood_DNA
+ src.fingerprints |= from.fingerprints
+ src.fingerprintshidden |= from.fingerprintshidden
+ src.fingerprintslast = from.fingerprintslast
//TODO bloody overlay
/*
@@ -239,8 +285,8 @@
/datum/stack_recipe
var/title = "ERROR"
var/result_type
- var/req_amount = 1
- var/res_amount = 1
+ var/req_amount = 1 //amount of material needed for this recipe
+ var/res_amount = 1 //amount of stuff that is produced in one batch (e.g. 4 for floor tiles)
var/max_res_amount = 1
var/time = 0
var/one_per_turf = 0
diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm
index fb79d5307f6..ff7d010b149 100644
--- a/code/game/objects/items/weapons/RCD.dm
+++ b/code/game/objects/items/weapons/RCD.dm
@@ -1,6 +1,6 @@
//Contains the rapid construction device.
/obj/item/weapon/rcd
- name = "rapid construction device (RCD)"
+ name = "rapid construction device"
desc = "A device used to rapidly build walls and floors."
icon = 'icons/obj/items.dmi'
icon_state = "rcd"
@@ -23,6 +23,9 @@
var/canRwall = 0
var/disabled = 0
+/obj/item/weapon/rcd/attack()
+ return 0
+
/obj/item/weapon/rcd/examine()
..()
if(src.type == /obj/item/weapon/rcd && loc == usr)
@@ -96,7 +99,7 @@
else if(deconstruct && istype(T,/turf/simulated/wall))
build_delay = deconstruct ? 50 : 40
build_cost = 5
- build_type = (canRwall && istype(T,/turf/simulated/wall/r_wall)) ? "wall" : null
+ build_type = (!canRwall && istype(T,/turf/simulated/wall/r_wall)) ? null : "wall"
build_turf = /turf/simulated/floor
else if(istype(T,/turf/simulated/floor))
build_delay = deconstruct ? 50 : 20
@@ -124,6 +127,8 @@
return 0
working = 0
+ if(build_delay && (!user.Adjacent(T) || user.get_active_hand() != src || user.stat || user.restrained()))
+ return 0
if(build_turf)
T.ChangeTurf(build_turf)
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index c206c42c827..74149103b32 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -470,6 +470,8 @@
place_poster(W,user)
return
+ else if(istype(W,/obj/item/weapon/rcd)) //I bitterly resent having to write this. ~Z
+ return
else
return attack_hand(user)
return
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index ee06abd127b..601d889b903 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -49,7 +49,7 @@
//Set species_restricted list
switch(target_species)
if("Human", "Skrell") //humanoid bodytypes
- species_restricted = list("exclude","Unathi","Tajara","Diona","Vox")
+ species_restricted = list("exclude","Unathi","Tajara","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
else
species_restricted = list(target_species)
@@ -68,9 +68,9 @@
//Set species_restricted list
switch(target_species)
if("Skrell")
- species_restricted = list("exclude","Unathi","Tajara","Diona","Vox")
+ species_restricted = list("exclude","Unathi","Tajara","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
if("Human")
- species_restricted = list("exclude","Skrell","Unathi","Tajara","Diona","Vox")
+ species_restricted = list("exclude","Skrell","Unathi","Tajara","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
else
species_restricted = list(target_species)
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index 535ab47f813..2ffe521d19f 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -15,7 +15,7 @@
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
- species_restricted = list("exclude","Diona","Vox")
+ species_restricted = list("exclude","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
var/obj/machinery/camera/camera
var/list/camera_networks
@@ -62,7 +62,7 @@
cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.9
- species_restricted = list("exclude","Diona","Vox")
+ species_restricted = list("exclude","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
var/list/supporting_limbs //If not-null, automatically splints breaks. Checked when removing the suit.
diff --git a/code/modules/clothing/spacesuits/void/merc.dm b/code/modules/clothing/spacesuits/void/merc.dm
index 849b4761ad6..907ad044fdf 100644
--- a/code/modules/clothing/spacesuits/void/merc.dm
+++ b/code/modules/clothing/spacesuits/void/merc.dm
@@ -7,7 +7,7 @@
item_color = "syndie"
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 60)
siemens_coefficient = 0.6
- species_restricted = list("exclude","Unathi","Tajara","Skrell","Vox")
+ species_restricted = list("exclude","Unathi","Tajara","Skrell","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
camera_networks = list("NUKE")
light_overlay = "helmet_light_green" //todo: species-specific light overlays
@@ -21,4 +21,4 @@
armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 60)
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs)
siemens_coefficient = 0.6
- species_restricted = list("exclude","Unathi","Tajara","Skrell","Vox")
\ No newline at end of file
+ species_restricted = list("exclude","Unathi","Tajara","Skrell","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
\ No newline at end of file
diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm
index 60b5e0c6c79..a1e6ab27142 100644
--- a/code/modules/clothing/spacesuits/void/void.dm
+++ b/code/modules/clothing/spacesuits/void/void.dm
@@ -10,7 +10,7 @@
max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE
//Species-specific stuff.
- species_restricted = list("exclude","Unathi","Tajara","Skrell","Diona","Vox")
+ species_restricted = list("exclude","Unathi","Tajara","Skrell","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
sprite_sheets_refit = list(
"Unathi" = 'icons/mob/species/unathi/helmet.dmi',
"Tajara" = 'icons/mob/species/tajaran/helmet.dmi',
@@ -35,7 +35,7 @@
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE
- species_restricted = list("exclude","Unathi","Tajara","Diona","Vox")
+ species_restricted = list("exclude","Unathi","Tajara","Diona","Vox", "Xenomorph", "Xenomorph Drone", "Xenomorph Hunter", "Xenomorph Sentinel", "Xenomorph Queen")
sprite_sheets_refit = list(
"Unathi" = 'icons/mob/species/unathi/suit.dmi',
"Tajara" = 'icons/mob/species/tajaran/suit.dmi',
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 67488df9ebc..68831c2446b 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -79,7 +79,7 @@
if(sleeping)
adjustHalLoss(-3)
if (mind)
- if((mind.active && client != null) || immune_to_ssd)
+ if(mind.active && client != null)
sleeping = max(sleeping-1, 0)
blinded = 1
stat = UNCONSCIOUS
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index c921c88afd0..f36de5ded9c 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -14,6 +14,7 @@
prosthetic_name = "cyberbrain"
prosthetic_icon = "brain-prosthetic"
organ_tag = "brain"
+ organ_type = /datum/organ/internal/brain
var/mob/living/carbon/brain/brainmob = null
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index ef5856026c1..42de4297527 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -200,8 +200,11 @@
if (istype(src,/mob/living/carbon/human) && src:w_uniform)
var/mob/living/carbon/human/H = src
H.w_uniform.add_fingerprint(M)
-
- if(lying || src.sleeping)
+
+ if(player_logged)
+ M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \
+ "You shake [src], but they do not respond... Maybe they have S.S.D?")
+ else if(lying || src.sleeping)
src.sleeping = max(0,src.sleeping-5)
if(src.sleeping == 0)
src.resting = 0
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 805c7be1284..e9a754e78d8 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -57,7 +57,10 @@
if(species && species.has_organ["brain"])
var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"]
- brainloss = min(sponge.damage,maxHealth*2)
+ if(sponge)
+ brainloss = min(sponge.damage,maxHealth*2)
+ else
+ brainloss = 200
else
brainloss = 0
return brainloss
diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm
index 30ac38248f4..9996efc8b69 100644
--- a/code/modules/mob/living/carbon/human/human_powers.dm
+++ b/code/modules/mob/living/carbon/human/human_powers.dm
@@ -98,14 +98,14 @@
T.Weaken(5)
//Only official cool kids get the grab and no self-prone.
- if(src.mind && src.mind.special_role)
+ if(src.mind && !src.mind.special_role)
src.Weaken(5)
return
var/use_hand = "left"
if(l_hand)
if(r_hand)
- src << "\red You need to have one hand free to grab someone."
+ src << "You need to have one hand free to grab someone."
return
else
use_hand = "right"
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 03dae189d9c..808025cf5fd 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -995,6 +995,10 @@
proc/handle_regular_status_updates()
if(status_flags & GODMODE) return 0
+
+ //SSD check, if a logged player is awake put them back to sleep!
+ if(player_logged && sleeping < 2)
+ sleeping = 2
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
blinded = 1
@@ -1050,7 +1054,10 @@
handle_dreams()
adjustHalLoss(-3)
if (mind)
- if((mind.active && client != null) || immune_to_ssd) //This also checks whether a client is connected, if not, sleep is not reduced.
+ //Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of stoxin or similar.
+ if(player_logged)
+ sleeping = max(sleeping-1, 2)
+ else
sleeping = max(sleeping-1, 0)
blinded = 1
stat = UNCONSCIOUS
@@ -1753,6 +1760,9 @@
return slurring
/mob/living/carbon/human/handle_stunned()
+ if(species.flags & NO_PAIN)
+ stunned = 0
+ return 0
if(..())
speech_problem_flag = 1
return stunned
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index defd0de8c7c..119e6245501 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -202,9 +202,9 @@
return
// Called when using the shredding behavior.
-/datum/species/proc/can_shred(var/mob/living/carbon/human/H)
+/datum/species/proc/can_shred(var/mob/living/carbon/human/H, var/ignore_intent)
- if(H.a_intent != "hurt")
+ if(ignore_intent && H.a_intent != "hurt")
return 0
for(var/datum/unarmed_attack/attack in unarmed_attacks)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index b243dcb1591..a82aefe9f56 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -686,7 +686,7 @@
can_break_cuffs = 1
else if(istype(CM,/mob/living/carbon/human))
var/mob/living/carbon/human/H = CM
- if(H.species.can_shred(H))
+ if(H.species.can_shred(H,1))
can_break_cuffs = 1
if(can_break_cuffs) //Don't want to do a lot of logic gating here.
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index b43da76953d..52f0630a39c 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -4,6 +4,8 @@
//Mind updates
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
mind.active = 1 //indicates that the mind is currently synced with a client
+ //If they're SSD, remove it so they can wake back up.
+ player_logged = 0
//Round specific stuff like hud updates
if(ticker && ticker.mode)
diff --git a/code/modules/mob/living/logout.dm b/code/modules/mob/living/logout.dm
index 8fdcdb0ec46..1f2551b6b85 100644
--- a/code/modules/mob/living/logout.dm
+++ b/code/modules/mob/living/logout.dm
@@ -1,7 +1,8 @@
/mob/living/Logout()
..()
if (mind)
- if(!key) //key and mind have become seperated.
+ if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts.
mind.active = 0 //This is to stop say, a mind.transfer_to call on a corpse causing a ghost to re-enter its body.
- if(!immune_to_ssd && sleeping < 2 && mind.active)
- sleeping = 2 //This causes instant sleep, but does not prolong it. See life.dm for furthering SSD.
+ //This tags a player as SSD. See appropriate life.dm files for furthering SSD effects such as falling asleep.
+ if(mind.active)
+ player_logged = 1
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 3f755bbb906..05c19538224 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -896,6 +896,12 @@ var/list/robot_verbs_default = list(
add_fingerprint(user)
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ if(H.species.can_shred(H))
+ attack_generic(H, rand(30,50), "slashed")
+ return
+
if(opened && !wiresexposed && (!istype(user, /mob/living/silicon)))
var/datum/robot_component/cell_component = components["power cell"]
if(cell)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index a22bcfd02d9..c20e8e058b1 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -11,7 +11,6 @@
var/ioncheck[1]
var/obj/item/device/radio/common_radio
- immune_to_ssd = 1
var/list/hud_list[9]
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 15e0db47fc8..296d58d0786 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -214,8 +214,9 @@
var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak
var/stance_damage = 0 //Whether this mob's ability to stand has been affected
-
- var/immune_to_ssd = 0
+
+ //SSD var, changed it up some so people can have special things happen for different mobs when SSD.
+ var/player_logged = 0
var/turf/listed_turf = null //the current turf being examined in the stat panel
var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
diff --git a/maps/exodus-1.dmm b/maps/exodus-1.dmm
index 19ae35a15de..d877dfb0509 100644
--- a/maps/exodus-1.dmm
+++ b/maps/exodus-1.dmm
@@ -5870,6 +5870,7 @@
"ciT" = (/obj/structure/closet/secure_closet/medical2,/obj/machinery/light_switch{pixel_x = 22; pixel_y = 0},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery2)
"ciU" = (/turf/simulated/wall,/area/medical/surgery2)
"ciV" = (/obj/machinery/camera{c_tag = "Virology Access Fore"; dir = 4; network = list("SS13","Research")},/turf/simulated/floor,/area/medical/virologyaccess)
+"ciW" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/sensor{name = "Powernet Sensor - Atmospherics Subgrid"; name_tag = "Atmospherics Subgrid"},/obj/structure/cable/cyan{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/atmos)
"ciX" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor,/area/medical/surgeryprep)
"ciY" = (/obj/structure/toilet{dir = 1},/obj/machinery/light/small{dir = 4},/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/patient_wing)
"ciZ" = (/obj/machinery/shower{dir = 1},/obj/machinery/light/small{dir = 8},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/patient_wing)
@@ -6799,7 +6800,6 @@
"cBC" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/obj/machinery/light,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/atmos)
"cBD" = (/obj/machinery/portable_atmospherics/canister/air,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/atmos)
"cBE" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/atmos)
-"cBF" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/power/sensor{name = "Powernet Sensor - Atmospherics Subgrid"; name_tag = "Atmospherics Subgrid"},/obj/structure/cable/cyan{d2 = 4; icon_state = "0-4"},/obj/structure/cable/cyan,/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 4},/area/atmos)
"cBG" = (/obj/machinery/power/terminal{icon_state = "term"; dir = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/atmos)
"cBH" = (/obj/machinery/atmospherics/pipe/manifold/visible/yellow,/turf/simulated/floor/plating,/area/engine/engine_room)
"cBI" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor,/area/engine/engine_hallway)
@@ -7401,7 +7401,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacptcpucpucpucpucpucyocpucpucpucyocpucpucpucpucpucrRcpucpucrWcGmcxpcuecuecxpcykcxpcIBcIAcIDcuecqVcuecxAcxBcIEcwwcoQcxDcoQcxEcxFcoXcoXcxGcoXcxHcnOcxIcxIcxJcwFcwGcnRbPxcvMcvNcxKcxLcxMcxNcxOcxNcxPcvNcxQcxRcrGaaaaaaaaaaaaaaaaaacqvcxScxTcxUcxVcxWcxXcxYcxZcuTcyacuScybcuTcyccuVcqvcqvcqvaaaaaacdOcplcpmcplcydcpocppcrNcrNcyecyfcrNcygcomcomcomcdOaaaaaacrPaaactXctXctXctXctXaafcudaafctXctXctXctXctXaafcrPaaaaaaaaaaaaaaaaaaaaaaaacyhaaaaaaaaacyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaaaaaaaaacptcpucqScqPcqPcxwcxycqPcxwcqPcxxcxwcqPcqPcqPcqPcxvcqPcrXcxucqQcvpcpucpucyvcwscywcxtcyycyzcpucsbcpucxqcxqcxrcyGcoQcxDcyHcnOcyIcoXcyJcoXcyKcyLcnOcnRcnRcnRcnRcnRcnRbPxcvMcvNcyMcyNcxLcyOcxLcxNcyPcvNcyQcyRcrGaaaaaaaaaaaaaaaaaacqvcuVcySctFctFcyTcyUcyVcyWctMctDctNcyXctMctDcyYcqvaaaaaaaaaaaacdOcplcplcplcxfcyZczacrNcrNcrNcyfcrNczbcrNczccrNczdaafaafcrPaafcvkcvicvicvicvicvhcudcubcsTcsTcsTcsTcvjaafcrPaaaaaaaaaaaaaaaaaaaaaaaacyhcyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafaaaaaaaaacptcpucymcpucpucpucyocpucpucpucyocpucpucpucpucpucrRcpucywcpucyncvpcpucpucylcykcuhcyjcoCctdcoCcoCcpucyiczBcxCcyGcoQcxDcoQcnOczDczEczFczGczHcoXcnOczIczJczJczKczLczMczNczOcvNcxNczPczQcxNczRczSczTcvNczUczVcrGaaaaaaaaaaaaaaaaaacqvczWcuMczXcuVczYczZcAactFcAbcAccsPcyXczWcAdcAecqvaaaaaaaaaaaackEcdOcAfcAgcAgcAhcAicAjcAkcAlcAmcAncAocApcAqcokcAraaaaaacrPaafcwjcwjcwjcwjcwjaaacudaafcwjcwjcwjcwjcwjaaacrPaaacyhaaaaaacyhaaaaaacyhcyhcyhcyhcyhcyhcyhaaaaaacyhaaaaaacyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaacyxcpucymcpucqKcqMcyucqMcuacqMcyucqMcuacqMcqMcqMcyqcytcyqcyscyrcuhcyBcyCcACcADcAEcAFcoCcBFcnzcoCcoCcoCcoCcoCcAIcAJcAKcAJcnOcnOcnOcnOcnOcnOcnOcnOcALczJczJcAMcANcAObPxcAPcvNcAQcARcAScATcAUcAVcAWcvNcAXcAYcrGaaaaaaaaaaaaaaaaaacqvcuQcAZcAectFcBacBbcBcctFcBdcBecBfcBgcBhcBicBjcqvaafaafaaaaaaaaaaaabquaaacdOcBlcBmcBncBocBpcBmcBqcBrcBpcBmcBscdOaaaaaabZSaaaaafaaaaafaaaaafaaacudaaaaafaaaaafaafaafaafcrPaaacyhcyhcyhcyhaaacyhcyhcyhcyhcyhcyhcyhcyhcyhaaacyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaacyxcpucymcpucqKcqMcyucqMcuacqMcyucqMcuacqMcqMcqMcyqcytcyqcyscyrcuhcyBcyCcACcADcAEcAFcoCciWcnzcoCcoCcoCcoCcoCcAIcAJcAKcAJcnOcnOcnOcnOcnOcnOcnOcnOcALczJczJcAMcANcAObPxcAPcvNcAQcARcAScATcAUcAVcAWcvNcAXcAYcrGaaaaaaaaaaaaaaaaaacqvcuQcAZcAectFcBacBbcBcctFcBdcBecBfcBgcBhcBicBjcqvaafaafaaaaaaaaaaaabquaaacdOcBlcBmcBncBocBpcBmcBqcBrcBpcBmcBscdOaaaaaabZSaaaaafaaaaafaaaaafaaacudaaaaafaaaaafaafaafaafcrPaaacyhcyhcyhcyhaaacyhcyhcyhcyhcyhcyhcyhcyhcyhaaacyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaIvaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabZSaaaaaaaaaaaaaamaaaaaaaaacyDcpucymcpucywcwscymcpucywcwscymcpucywcwscpucpucyvcpucywcwscyEczfczhczecBBcBCcBDcBEcoCcyFcBGcvqcBIcBJcBKcBLcBMcBKcBNcBKcBOcBPcBQcBRcBScBScBTcBUcBVcBWcBWcBXcBYcAObPxcBZcvNcvNcCacCbcCccCbcCacCdcvNcrGcCecrGaaaaaaaaaaaaaaaaaacqvctFcCfcuVctFcCgcChcCictFcCjcCkcqycgvcCmcCncCocrHaaaaaaaaaaaaaaaaaacgwaafcdOcCqcCrcCscomcCtcCucCvcomcCwcCxcCycdOaaaaaacrPaaactXctXctXctXctXaafcudaafctXctXctXctXctXaafcrPaaacyhcyhcyhcyhaaacyhcyhcyhcyhcyhcyhcyhcyhcyhaaacyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrPaafaafaafaafaamaafaafaafcyDczwczAczyczgczsczqczpczkcznczmczlczoczscpuczwczvczuczrczncztcoCcoCcoCcCzcCzcCzcCzcCzcvrcCzcCBcCCcCDcCEcCFcCEcCEcCGcCEcCEcCHcCEcCDcCIcCJcCKcCLciCcCNcCOcCPcCQcAObPwcCRcCScCTcCacCUcAVcCVcCacCWaafcCXcCYcCXaaaaaaaaaaaaaaaaaacqvcCZctDcuQcDacDbcuQcDccDdcDeaafaaachxchFchEcDgaaaaaaaaaaacaaaaaaaaaaaaaaacdOcDhcplcplcomcDicplcplcomcDicplcplcdOaafaafcrPaafcvkcvicvicvicvicvhcudcubcsTcsTcsTcsTcvjaafcrPaaacyhcyhcyhcyhaaacyhcyhcyhcyhcyhcyhcyhcyhcyhaaacyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactYctYctYctYctYctYctYctYctYctYctYctYctYctYctYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrPcpFaaaaaaaaaaamaaaaaaaaacAzcAvcAwcAxcAycABcAAcAHcAycABcAAcAHcAycABcBucBucBvcAHcAycABcBtcoCaaacDvcDwcDxcDycDzcDAcAucDCcDDcDDcDEcDFcDGcDHcDIcDJcDHcDIcDGcDKcDLcDMcDKcCBcCBcAOcDNcDOcDPcDQcAObNUcDRcDScDTcCacCbcDUcCbcCacCWaafaaaaafaaaaaaaaaaaaaaaaaaaaacqvcCZcDVcDWcDXcDXcDWcsPcDYcqvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacdOcDZcplcplcomcEacplcplcomcEacplcplcdOaaaaaacrPaafcwjcwjcwjcwjcwjaaacudaaacwjcwjcwjcwjcwjaaacrPaaacyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhcyhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa