diff --git a/_maps/RandomZLevels/away_mission/stargate.dmm b/_maps/RandomZLevels/away_mission/stargate.dmm index a2dff503..65663d91 100644 --- a/_maps/RandomZLevels/away_mission/stargate.dmm +++ b/_maps/RandomZLevels/away_mission/stargate.dmm @@ -2,14 +2,14 @@ "ab" = (/turf/closed/mineral/random/labormineral/jungle,/area/awaymission/stargate/building/mountain) "ac" = (/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "ad" = (/obj/structure/table/wood,/obj/item/reagent_containers/food/drinks/trophy,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"ae" = (/obj/item/flashlight/lantern{icon_state = "lantern-on"},/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"ae" = (/obj/item/flashlight/lantern{icon_state = "lantern-on"},/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "af" = (/obj/structure/flora/ausbushes/ywflowers,/mob/living/simple_animal/chicken,/turf/open/floor/grass,/area/awaymission/stargate) "ag" = (/obj/structure/flora/rock/jungle,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) -"ah" = (/obj/item/storage/firstaid/regular,/turf/open/floor/wood,/area/awaymission/stargate/building) +"ah" = (/obj/item/storage/firstaid/regular,/obj/structure/table/wood,/turf/open/floor/wood,/area/awaymission/stargate/building) "ai" = (/obj/structure/rack/shelf,/obj/item/clothing/suit/armor/riot/knight/yellow,/obj/item/shield/riot/tower,/obj/item/clothing/head/helmet/knight/yellow,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "aj" = (/turf/closed/indestructible/necropolis,/area/awaymission/stargate/building/flesh) "ak" = (/turf/open/indestructible/necropolis/air,/area/awaymission/stargate/building/flesh) -"al" = (/obj/structure/destructible/cult/talisman,/obj/item/dragons_blood,/turf/open/indestructible/necropolis/air,/area/awaymission/stargate/building/flesh) +"al" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "am" = (/mob/living/simple_animal/hostile/carrion,/turf/open/indestructible/necropolis/air,/area/awaymission/stargate/building/flesh) "an" = (/obj/structure/table/wood,/obj/item/nullrod/egyptian,/turf/open/floor/wood,/area/awaymission/stargate/building) "ao" = (/obj/item/bedsheet/cult,/obj/effect/mob_spawn/human/villager,/turf/open/floor/wood,/area/awaymission/stargate/building) @@ -20,46 +20,136 @@ "at" = (/obj/item/bedsheet/black,/obj/effect/mob_spawn/human/villager,/turf/open/floor/wood,/area/awaymission/stargate/building) "au" = (/obj/item/bedsheet/red,/obj/effect/mob_spawn/human/villager,/turf/open/floor/wood,/area/awaymission/stargate/building) "av" = (/obj/machinery/aug_manipulator,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) -"aw" = (/mob/living/simple_animal/hostile/netherworld/migo,/turf/open/floor/plasteel/cult,/area/awaymission/stargate/building) -"ax" = (/obj/structure/rack/shelf,/obj/item/ammo_box/magazine/wt550m9/wtrubber,/obj/item/ammo_box/magazine/wt550m9/wtrubber,/obj/item/ammo_box/magazine/wt550m9/wtrubber,/obj/item/ammo_box/magazine/wt550m9/wtrubber,/obj/item/ammo_box/magazine/wt550m9/wtrubber,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"ay" = (/obj/structure/rack/shelf,/obj/item/ammo_box/magazine/wt550m9,/obj/item/ammo_box/magazine/wt550m9,/obj/item/ammo_box/magazine/wt550m9,/obj/item/ammo_box/magazine/wt550m9,/obj/item/ammo_box/magazine/wt550m9,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"az" = (/obj/structure/rack/shelf,/obj/item/ammo_box/magazine/wt550m9/wtic,/obj/item/ammo_box/magazine/wt550m9/wtic,/obj/item/ammo_box/magazine/wt550m9/wtic,/obj/item/ammo_box/magazine/wt550m9/wtic,/obj/item/ammo_box/magazine/wt550m9/wtic,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aw" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) +"ay" = (/obj/structure/rack/shelf,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"az" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "aA" = (/obj/item/clothing/mask/gas,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "aB" = (/obj/item/clothing/shoes/sneakers/black,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "aC" = (/obj/structure/closet/supplypod/centcompod,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "aD" = (/obj/item/clothing/gloves/color/fyellow/old,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "aE" = (/obj/item/clothing/under/color/grey,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "aF" = (/obj/item/twohanded/spear,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"aG" = (/obj/item/gun/ballistic/shotgun/riot,/obj/item/gun/ballistic/shotgun/riot{pixel_x = 3; pixel_y = -3},/obj/structure/rack/shelf,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"aH" = (/obj/effect/landmark/awaystart,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aH" = (/obj/structure/table/wood,/obj/machinery/microwave,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aI" = (/obj/structure/closet/secure_closet/freezer/meat,/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aJ" = (/obj/structure/table/wood,/obj/item/kitchen/knife,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aK" = (/obj/structure/table/wood,/obj/machinery/reagentgrinder,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aL" = (/obj/structure/sink{dir = 8; pixel_x = -12; pixel_y = 2},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aM" = (/obj/machinery/door/airlock/wood,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aN" = (/obj/structure/dresser,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "aO" = (/obj/structure/closet/crate/wooden,/obj/item/stack/sheet/cloth/thirty,/obj/item/stack/sheet/cloth/thirty,/turf/open/floor/wood,/area/awaymission/stargate/building) +"aP" = (/obj/structure/closet/crate/wooden,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aQ" = (/obj/machinery/light{dir = 8},/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aR" = (/obj/structure/bed,/obj/item/bedsheet/brown,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aS" = (/obj/structure/rack/shelf,/obj/item/gun/ballistic/shotgun/riot,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"aT" = (/turf/open/floor/cobble/corner{dir = 1; icon_state = "cobble_corner"},/area/awaymission/stargate) +"aU" = (/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"aV" = (/turf/open/floor/cobble/corner,/area/awaymission/stargate) "aW" = (/obj/structure/flora/rock,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"aX" = (/turf/open/floor/cobble,/area/awaymission/stargate) +"aY" = (/turf/open/floor/cobble/side{dir = 4; icon_state = "cobble_side"},/area/awaymission/stargate) +"aZ" = (/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) +"ba" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/cobble,/area/awaymission/stargate) +"bb" = (/turf/open/floor/cobble/corner{dir = 8; icon_state = "cobble_corner"},/area/awaymission/stargate) "bc" = (/obj/structure/table/reinforced,/obj/item/clothing/mask/gas/clown_hat,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"bd" = (/turf/open/floor/cobble/side,/area/awaymission/stargate) +"be" = (/turf/open/floor/cobble/corner{dir = 4; icon_state = "cobble_corner"},/area/awaymission/stargate) +"bf" = (/obj/structure/barricade/wooden,/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) +"bg" = (/obj/structure/barricade/wooden,/turf/open/floor/cobble,/area/awaymission/stargate) +"bh" = (/obj/structure/barricade/wooden,/turf/open/floor/cobble/side{dir = 4; icon_state = "cobble_side"},/area/awaymission/stargate) "bi" = (/obj/structure/flora/grass/jungle,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) +"bj" = (/mob/living/simple_animal/butterfly,/turf/open/floor/cobble,/area/awaymission/stargate) +"bk" = (/obj/effect/landmark/awaystart,/turf/open/floor/cobble,/area/awaymission/stargate) +"bl" = (/mob/living/simple_animal/butterfly,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"bm" = (/obj/item/lighter,/turf/open/floor/cobble,/area/awaymission/stargate) +"bn" = (/obj/item/grown/log/tree,/turf/open/floor/cobble,/area/awaymission/stargate) +"bo" = (/mob/living/simple_animal/butterfly,/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) +"bp" = (/obj/structure/bonfire,/turf/open/floor/cobble,/area/awaymission/stargate) +"bq" = (/obj/structure/barricade/sandbags,/obj/structure/barricade/sandbags,/turf/open/floor/cobble,/area/awaymission/stargate) +"br" = (/obj/structure/barricade/sandbags,/turf/open/floor/cobble,/area/awaymission/stargate) +"bs" = (/obj/structure/fence{dir = 4},/turf/open/floor/plating/dirt,/area/awaymission/stargate/building/mountain) +"bt" = (/obj/structure/fence/door,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"bu" = (/obj/structure/fence{dir = 4},/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"bv" = (/obj/structure/falsewall/abductor,/turf/open/space/basic,/area/awaymission/stargate/building) +"bw" = (/obj/machinery/door/airlock/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"bx" = (/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"by" = (/turf/closed/wall/mineral/abductor,/area/awaymission/stargate/building) +"bz" = (/obj/structure/barricade/sandbags,/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) "bA" = (/obj/effect/decal/cleanable/blood/gibs/human/body,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"bB" = (/obj/structure/barricade/sandbags,/turf/open/floor/cobble/side{dir = 4; icon_state = "cobble_side"},/area/awaymission/stargate) "bC" = (/obj/machinery/hydroponics/soil,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) +"bD" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) +"bE" = (/obj/machinery/gateway{dir = 9},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bF" = (/obj/structure/fence{dir = 4},/turf/open/floor/cobble/side{dir = 8; icon_state = "cobble_side"},/area/awaymission/stargate) +"bG" = (/obj/structure/fence/door,/turf/open/floor/cobble,/area/awaymission/stargate) +"bH" = (/obj/structure/fence{dir = 4},/turf/open/floor/cobble,/area/awaymission/stargate) +"bI" = (/obj/structure/fence{dir = 4},/turf/open/floor/cobble/side{dir = 4; icon_state = "cobble_side"},/area/awaymission/stargate) +"bJ" = (/obj/machinery/gateway{dir = 1},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bK" = (/obj/machinery/gateway{dir = 5},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "bL" = (/obj/structure/table/wood/fancy/blackred,/obj/machinery/chem_dispenser/drinks,/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) +"bM" = (/obj/machinery/gateway{dir = 8},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bN" = (/obj/machinery/gateway/centeraway,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bO" = (/obj/machinery/gateway{dir = 4},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "bP" = (/obj/structure/chair/sofa{dir = 4},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "bQ" = (/obj/effect/decal/remains/robot,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "bR" = (/obj/structure/flora/ausbushes/brflowers,/obj/structure/flora/ausbushes/ywflowers,/turf/open/floor/grass,/area/awaymission/stargate) "bS" = (/obj/structure/flora/junglebush/large,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) +"bT" = (/obj/machinery/gateway{dir = 10},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bU" = (/obj/structure/door_assembly/door_assembly_abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"bV" = (/obj/machinery/gateway,/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bW" = (/obj/machinery/gateway{dir = 6},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bX" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) +"bY" = (/obj/structure/barricade/wooden/crude,/obj/machinery/door/airlock/wood,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"bZ" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"ca" = (/obj/structure/barricade/sandbags,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"cb" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/cobble,/area/awaymission/stargate) +"cc" = (/turf/open/floor/concrete,/area/awaymission/stargate) +"cd" = (/turf/open/floor/concrete/smooth,/area/awaymission/stargate) +"ce" = (/mob/living/simple_animal/hostile/carrion,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"cf" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/cobble,/area/awaymission/stargate) +"cg" = (/obj/effect/decal/cleanable/blood/gibs/human,/turf/open/floor/cobble,/area/awaymission/stargate) +"ch" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"ci" = (/obj/structure/barricade/wooden,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) "cj" = (/obj/machinery/door/airlock/wood/glass,/obj/structure/barricade/wooden/crude,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"cp" = (/mob/living/simple_animal/hostile/hs13mimic,/turf/open/floor/grass,/area/awaymission/stargate) +"ck" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"cl" = (/obj/effect/decal/remains/human,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"cm" = (/obj/effect/decal/cleanable/blood/gibs,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"cn" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"co" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/cobble/corner,/area/awaymission/stargate) +"cp" = (/obj/structure/barricade/sandbags,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"cq" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/cobble,/area/awaymission/stargate) +"cr" = (/obj/effect/decal/cleanable/blood/gibs/torso,/turf/open/floor/cobble,/area/awaymission/stargate) "cs" = (/turf/open/floor/wood,/area/awaymission/stargate/building) +"ct" = (/obj/effect/decal/cleanable/blood/gibs,/turf/open/floor/cobble,/area/awaymission/stargate) +"cu" = (/obj/effect/decal/remains/human,/turf/open/floor/cobble,/area/awaymission/stargate) +"cv" = (/obj/structure/closet/crate,/obj/item/stack/ore/bananium,/obj/item/stack/ore/bananium,/obj/item/stack/ore/bananium,/obj/item/stack/ore/bananium,/obj/item/stack/ore/bananium,/obj/item/stack/ore/bananium,/turf/open/floor/mineral/titanium/yellow,/area/awaymission/stargate/building) +"cw" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/cobble,/area/awaymission/stargate) "cx" = (/obj/structure/table/reinforced,/obj/item/robot_module/clown,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"cy" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"cz" = (/turf/open/floor/mineral/diamond,/area/awaymission/stargate/building) +"cB" = (/obj/structure/statue/bananium/clown,/turf/open/floor/cobble/side{dir = 4; icon_state = "cobble_side"},/area/awaymission/stargate) +"cD" = (/obj/structure/barricade/sandbags,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"cE" = (/obj/structure/barricade/wooden,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"cF" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"cG" = (/obj/effect/decal/remains/human,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"cH" = (/obj/effect/decal/remains/xeno,/turf/open/floor/cobble/side,/area/awaymission/stargate) "cI" = (/obj/structure/flora/tree/palm,/obj/structure/flora/ausbushes/ywflowers,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) +"cJ" = (/obj/effect/decal/cleanable/blood/gibs/torso,/turf/open/floor/cobble/side,/area/awaymission/stargate) +"cK" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/cobble/side,/area/awaymission/stargate) "db" = (/obj/structure/table/wood,/obj/item/flashlight/lantern{icon_state = "lantern-on"},/turf/open/floor/wood,/area/awaymission/stargate/building) -"di" = (/obj/structure/barricade/wooden,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) "dt" = (/turf/closed/wall/mineral/bananium,/area/awaymission/stargate/building) "dz" = (/obj/machinery/conveyor{dir = 8; id = "mining_internal"},/turf/open/floor/wood,/area/awaymission/stargate/building) -"dO" = (/obj/item/gun/ballistic/shotgun/riot,/obj/item/gun/ballistic/shotgun/riot,/obj/structure/rack/shelf,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"dO" = (/obj/item/gun/ballistic/shotgun/riot,/obj/structure/rack/shelf,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "dQ" = (/obj/structure/flora/junglebush/c,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "dT" = (/obj/machinery/vending/hydronutrients,/turf/open/floor/wood,/area/awaymission/stargate/building) "ea" = (/obj/machinery/computer/rdconsole/core,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"ec" = (/obj/structure/reagent_dispensers/keg/semen,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "ee" = (/obj/structure/chair/wood{dir = 1},/turf/open/floor/wood,/area/awaymission/stargate/building) "el" = (/obj/structure/flora/rock/jungle,/turf/open/floor/grass,/area/awaymission/stargate) +"es" = (/obj/machinery/light{dir = 4},/obj/structure/flora/junglebush,/turf/open/floor/grass,/area/awaymission/stargate/building) "et" = (/obj/effect/decal/cleanable/blood/gibs/up,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"eI" = (/obj/structure/barricade/sandbags,/turf/open/indestructible/cobble/side{dir = 4},/area/awaymission/stargate) +"eC" = (/obj/structure/statue/sandstone/abs,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"eG" = (/obj/structure/table/wood/fancy/black,/obj/item/stack/sheet/mineral/diamond{amount = 2},/turf/open/floor/mineral/diamond,/area/awaymission/stargate/building) +"eI" = (/obj/machinery/light,/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) "eJ" = (/obj/structure/closet/secure_closet/freezer/meat,/turf/open/floor/wood,/area/awaymission/stargate/building) "eL" = (/obj/structure/kitchenspike,/turf/open/floor/wood,/area/awaymission/stargate/building) "eM" = (/obj/effect/decal/cleanable/blood/gibs/human,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) @@ -67,53 +157,59 @@ "eZ" = (/obj/machinery/light{dir = 4},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "fm" = (/obj/structure/table/plasmaglass,/obj/item/ashtray,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "fB" = (/obj/structure/table/wood,/obj/item/kitchen/rollingpin,/turf/open/floor/wood,/area/awaymission/stargate/building) -"fH" = (/obj/structure/fence{dir = 4},/turf/open/indestructible/cobble/side{dir = 4},/area/awaymission/stargate) -"fJ" = (/obj/effect/decal/cleanable/blood,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) +"fC" = (/obj/machinery/abductor/gland_dispenser,/turf/open/floor/plating/abductor{initial_gas_mix = "o2=14;n2=23;TEMP=300"},/area/awaymission/stargate/building) "fN" = (/obj/machinery/door/airlock/wood,/turf/open/floor/wood,/area/awaymission/stargate/building) "fO" = (/obj/structure/flora/junglebush/b,/turf/open/floor/grass,/area/awaymission/stargate) "fU" = (/obj/structure/table/wood,/obj/item/reagent_containers/glass/bottle/charcoal,/obj/item/reagent_containers/glass/bottle/charcoal,/turf/open/floor/wood,/area/awaymission/stargate/building) -"gc" = (/mob/living/simple_animal/butterfly,/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) -"gn" = (/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"fY" = (/obj/structure/chair/stool/alien,/obj/effect/decal/cleanable/greenglow,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"gB" = (/mob/living/simple_animal/hostile/retaliate/clown/lube,/turf/open/floor/cobble,/area/awaymission/stargate) "gC" = (/obj/structure/flora/grass/jungle/b,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "gI" = (/obj/structure/mineral_door/woodrustic,/turf/open/floor/wood,/area/awaymission/stargate/building) +"gJ" = (/mob/living/simple_animal/hostile/netherworld/migo,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "hc" = (/obj/structure/chair/sofa/left{dir = 1},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "he" = (/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"hm" = (/obj/effect/decal/cleanable/blood/old,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "hs" = (/turf/closed/wall/mineral/cult/artificer,/area/awaymission/stargate/building) "ht" = (/obj/structure/flora/rock/pile/largejungle,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) +"hw" = (/obj/structure/flora/junglebush/c,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "hC" = (/obj/structure/flora/junglebush/b,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) +"hG" = (/mob/living/simple_animal/hostile/retaliate/clown/mutant,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "hK" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"hM" = (/obj/effect/turf_decal/loading_area{dir = 4; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "hQ" = (/obj/structure/flora/junglebush,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "ik" = (/obj/machinery/shower{dir = 8; pixel_y = -4},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "il" = (/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) "iA" = (/obj/machinery/conveyor{dir = 10; id = "mining_internal"},/turf/open/floor/wood,/area/awaymission/stargate/building) +"iK" = (/obj/effect/decal/cleanable/semen,/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate/building) "iX" = (/obj/structure/flora/grass/jungle/b,/mob/living/simple_animal/butterfly,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) +"ja" = (/obj/machinery/light{dir = 1; light_color = "#cee5d2"},/obj/structure/table/wood/fancy/black,/obj/item/nullrod/claymore/chainsaw_sword,/turf/open/floor/mineral/diamond,/area/awaymission/stargate/building) "je" = (/obj/structure/bed,/obj/item/bedsheet,/turf/open/floor/wood,/area/awaymission/stargate/building) "jf" = (/obj/structure/closet/crate/wooden,/obj/item/twohanded/fireaxe/boneaxe,/turf/open/floor/wood,/area/awaymission/stargate/building) +"jz" = (/obj/structure/flora/grass/jungle,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/grass,/area/awaymission/stargate/building) "jD" = (/turf/open/floor/carpet,/area/awaymission/stargate/building) "jF" = (/obj/structure/table/wood/fancy/black,/obj/item/clothing/head/nemes,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "jH" = (/obj/structure/flora/ausbushes/reedbush,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) -"jR" = (/obj/machinery/rnd/production/protolathe,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"jR" = (/obj/machinery/rnd/production/protolathe/department/science,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "jX" = (/obj/structure/closet/crate/wooden,/obj/item/stack/sheet/glass/fifty,/obj/item/stack/sheet/glass/fifty,/turf/open/floor/wood,/area/awaymission/stargate/building) "jZ" = (/obj/structure/flora/grass/jungle,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "ke" = (/obj/structure/flora/tree/desertdead,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"kh" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/indestructible/cobble/corner,/area/awaymission/stargate) "ki" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "kp" = (/obj/machinery/light,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"ky" = (/obj/machinery/pool/filter{pixel_y = 24},/turf/open/pool,/area/awaymission/stargate/building) "kM" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "kQ" = (/obj/machinery/autolathe,/turf/open/floor/wood,/area/awaymission/stargate/building) "lg" = (/obj/structure/table/optable,/obj/effect/decal/cleanable/blood,/turf/open/floor/wood,/area/awaymission/stargate/building) +"lj" = (/obj/structure/flora/junglebush/c,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "ln" = (/obj/structure/closet/crate/wooden,/obj/item/stack/sheet/mineral/wood/fifty,/obj/item/stack/sheet/mineral/wood/fifty,/turf/open/floor/wood,/area/awaymission/stargate/building) -"lt" = (/obj/machinery/chem_heater,/turf/open/floor/wood,/area/awaymission/stargate/building) +"lt" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/mineral/diamond,/area/awaymission/stargate/building) +"lQ" = (/obj/effect/decal/cleanable/greenglow,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "ma" = (/obj/structure/reagent_dispensers/water_cooler,/turf/open/floor/wood,/area/awaymission/stargate/building) "mb" = (/obj/structure/rack/shelf,/obj/item/storage/box/lethalshot,/obj/item/storage/box/lethalshot,/obj/item/storage/box/lethalshot,/obj/item/storage/box/lethalshot,/obj/item/storage/box/lethalshot,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "md" = (/obj/structure/table/wood,/obj/item/reagent_containers/food/drinks/bottle/wine,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "me" = (/obj/structure/table/wood,/obj/item/storage/fancy/candle_box,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"mk" = (/obj/effect/decal/remains/human,/turf/open/indestructible/cobble,/area/awaymission/stargate) "mt" = (/obj/machinery/door/airlock/wood/glass,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"mv" = (/obj/machinery/chem_dispenser,/turf/open/floor/wood,/area/awaymission/stargate/building) +"mv" = (/obj/effect/decal/remains/human,/turf/open/floor/mineral/diamond,/area/awaymission/stargate/building) "mx" = (/obj/structure/table/wood,/obj/item/storage/box/drinkingglasses,/obj/item/storage/box/drinkingglasses,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"mB" = (/obj/machinery/gateway{dir = 6},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"mB" = (/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) "mD" = (/mob/living/simple_animal/butterfly,/turf/open/water/jungle,/area/awaymission/stargate) "mF" = (/obj/machinery/conveyor_switch/oneway{id = "mining_internal"; name = "mining conveyor"},/turf/open/floor/wood,/area/awaymission/stargate/building) "mJ" = (/obj/structure/flora/tree/palm,/turf/open/floor/grass,/area/awaymission/stargate) @@ -123,61 +219,69 @@ "nh" = (/obj/effect/decal/cleanable/blood/gibs,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "nm" = (/obj/structure/bonfire,/turf/open/floor/wood,/area/awaymission/stargate/building) "nn" = (/obj/structure/table/wood/fancy/blackred,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) -"np" = (/obj/effect/decal/cleanable/blood,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"ny" = (/turf/open/indestructible/cobble/side{dir = 4},/area/awaymission/stargate) +"nC" = (/obj/structure/pool/ladder{pixel_x = -3},/turf/open/pool,/area/awaymission/stargate/building) +"nG" = (/obj/machinery/light{dir = 8; light_color = "#e8eaff"},/obj/structure/flora/junglebush,/turf/open/floor/grass,/area/awaymission/stargate/building) +"nK" = (/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate/building) "nL" = (/obj/structure/table/reinforced,/obj/item/storage/backpack/duffelbag/med/surgery,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"nQ" = (/obj/structure/flora/junglebush/b,/turf/open/floor/grass,/area/awaymission/stargate/building) "nR" = (/obj/structure/table/wood/fancy/black,/obj/item/reagent_containers/food/drinks/trophy,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "nX" = (/obj/machinery/light{dir = 8; light_color = "#e8eaff"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "nY" = (/obj/structure/flora/rock/pile/largejungle,/turf/open/floor/grass,/area/awaymission/stargate) "of" = (/obj/effect/spawner/structure/window,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"oh" = (/obj/machinery/smartfridge/chemistry,/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) +"oh" = (/obj/structure/table/wood/fancy/black,/obj/item/stack/sheet/mineral/gold{amount = 25},/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) "ox" = (/obj/structure/chair/sofa/left{dir = 4},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"oy" = (/obj/effect/decal/cleanable/semen,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "oz" = (/obj/structure/chair/sofa{dir = 8},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"oC" = (/obj/machinery/abductor/gland_dispenser,/turf/open/floor/plating/abductor{initial_gas_mix = "o2=14;n2=23;TEMP=300"},/area/awaymission/stargate/building) "oQ" = (/mob/living/simple_animal/chicken,/turf/open/floor/grass,/area/awaymission/stargate) -"oS" = (/obj/machinery/gateway/centeraway,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"oS" = (/obj/effect/rune/apocalypse,/obj/structure/spawner/nether,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "oX" = (/obj/machinery/light{dir = 8},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "pd" = (/obj/machinery/light{dir = 4},/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "pm" = (/obj/structure/table/wood,/obj/item/lighter,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "pu" = (/turf/closed/wall/mineral/cult,/area/awaymission/stargate/building) -"pA" = (/mob/living/simple_animal/butterfly,/turf/open/indestructible/cobble,/area/awaymission/stargate) +"pI" = (/obj/machinery/door/airlock/wood,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "pV" = (/obj/structure/flora/junglebush/large,/turf/open/floor/grass,/area/awaymission/stargate) +"pY" = (/obj/structure/table/wood/fancy,/obj/item/dildo/flared/gigantic,/turf/open/floor/grass,/area/awaymission/stargate/building) "qf" = (/obj/structure/flora/rock/jungle,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) -"qw" = (/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate/building/mountain) +"qr" = (/obj/structure/flora/tree/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) +"qw" = (/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) +"qB" = (/obj/effect/decal/cleanable/blood/gibs/up,/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) "qC" = (/obj/machinery/light{dir = 4},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "qD" = (/obj/structure/flora/ausbushes/brflowers,/turf/open/floor/grass,/area/awaymission/stargate) "qK" = (/obj/structure/falsewall/sandstone,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"qP" = (/obj/structure/fence{dir = 4},/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) -"qS" = (/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"qR" = (/mob/living/simple_animal/hostile/jungle/mook,/obj/structure/flora/grass/jungle/b,/turf/open/floor/grass,/area/awaymission/stargate/building) +"qS" = (/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "qU" = (/obj/structure/sink/puddle,/turf/open/floor/grass,/area/awaymission/stargate) -"rg" = (/obj/effect/decal/cleanable/blood,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) +"rb" = (/obj/structure/flora/junglebush/b,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "rh" = (/obj/effect/decal/cleanable/blood,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"rm" = (/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"rn" = (/obj/structure/table/optable/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "rt" = (/obj/machinery/light{dir = 8},/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "ry" = (/obj/structure/flora/junglebush/large,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "rC" = (/obj/structure/flora/ausbushes/brflowers,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) -"rD" = (/obj/effect/decal/cleanable/blood/gibs/human,/turf/open/indestructible/cobble,/area/awaymission/stargate) +"rL" = (/obj/structure/table/wood/fancy,/obj/item/reagent_containers/food/drinks/trophy{pixel_y = 8},/turf/open/floor/grass,/area/awaymission/stargate/building) +"rS" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "rU" = (/obj/structure/table/wood/fancy/blackred,/obj/machinery/reagentgrinder,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) "rX" = (/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "sn" = (/obj/machinery/door/airlock/wood/glass,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"su" = (/obj/structure/barricade/wooden,/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) -"sy" = (/obj/structure/fence/door,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"sC" = (/turf/open/indestructible/cobble/corner{dir = 4},/area/awaymission/stargate) +"sr" = (/turf/open/floor/grass/fairy/red,/area/awaymission/stargate/building) "sE" = (/obj/structure/flora/ausbushes/palebush,/turf/open/floor/grass,/area/awaymission/stargate) "sL" = (/turf/closed/wall/mineral/wood/nonmetal,/area/awaymission/stargate/building) "sM" = (/obj/structure/flora/ausbushes/ywflowers,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) +"sR" = (/obj/structure/flora/junglebush/b,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/grass,/area/awaymission/stargate/building) "sW" = (/obj/structure/flora/tree/palm,/obj/structure/flora/grass/jungle/b,/turf/open/floor/grass,/area/awaymission/stargate) -"sY" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/indestructible/cobble,/area/awaymission/stargate) "tc" = (/obj/structure/flora/junglebush,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) -"th" = (/obj/structure/barricade/sandbags,/obj/structure/barricade/sandbags,/turf/open/indestructible/cobble,/area/awaymission/stargate) "tj" = (/obj/structure/falsewall/sandstone,/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) "tz" = (/obj/structure/table/wood,/obj/item/twohanded/bonespear,/turf/open/floor/wood,/area/awaymission/stargate/building) "tC" = (/obj/structure/chair/sofa/right{dir = 1},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"tD" = (/mob/living/simple_animal/hostile/retaliate/clown/mutant/blob,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "tI" = (/obj/machinery/light{dir = 4; light_color = "#c1caff"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "tN" = (/obj/structure/chair/wood{dir = 8},/turf/open/floor/wood,/area/awaymission/stargate/building) +"tT" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "ua" = (/obj/structure/barricade/wooden,/obj/effect/decal/cleanable/blood/tracks{dir = 8},/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"uw" = (/obj/structure/flora/grass/jungle/b,/turf/open/floor/grass,/area/awaymission/stargate/building) "uA" = (/obj/structure/chair/wood{dir = 8},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "uB" = (/obj/structure/flora/ausbushes/ppflowers,/turf/open/floor/grass,/area/awaymission/stargate) -"uC" = (/obj/structure/barricade/wooden,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) +"uD" = (/obj/structure/showcase/horrific_experiment,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "uI" = (/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) "uO" = (/mob/living/simple_animal/cow,/turf/open/floor/grass,/area/awaymission/stargate) "uR" = (/turf/open/indestructible/cobble/corner,/area/awaymission/stargate) @@ -187,21 +291,24 @@ "vu" = (/mob/living/simple_animal/hostile/hs13mimic,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "vv" = (/obj/effect/spawner/structure/window,/turf/open/floor/wood,/area/awaymission/stargate/building) "vz" = (/obj/structure/table/wood/fancy/black,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) +"vD" = (/obj/structure/flora/junglebush/large,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "vM" = (/obj/structure/closet/crate/wooden,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "vO" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"vS" = (/obj/machinery/light{dir = 8},/obj/structure/showcase/horrific_experiment,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) -"wl" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) -"wv" = (/turf/open/indestructible/cobble/side,/area/awaymission/stargate) +"vX" = (/obj/machinery/light{dir = 8; light_color = "#e8eaff"},/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) +"vZ" = (/obj/machinery/pool/controller,/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"wc" = (/obj/structure/reagent_dispensers/keg/aphro/strong,/turf/open/floor/grass,/area/awaymission/stargate/building) +"wC" = (/obj/machinery/light{dir = 4},/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate/building) "wF" = (/obj/structure/rack/shelf,/obj/item/melee/classic_baton/telescopic,/obj/item/melee/classic_baton/telescopic,/obj/item/melee/classic_baton/telescopic,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "wL" = (/obj/structure/flora/ausbushes/palebush,/obj/structure/flora/ausbushes/ppflowers,/turf/open/floor/grass,/area/awaymission/stargate) "wP" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"wY" = (/obj/effect/decal/remains/xeno,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) -"wZ" = (/obj/machinery/door/airlock/wood,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"wZ" = (/obj/structure/table/wood/fancy/black,/obj/item/storage/fancy/ringbox/diamond,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "xm" = (/obj/structure/table/wood/fancy,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "xn" = (/turf/open/indestructible/cobble,/area/awaymission/stargate) +"xA" = (/obj/structure/pool/ladder{dir = 8; pixel_x = 2},/turf/open/pool,/area/awaymission/stargate/building) "xG" = (/obj/structure/chair/wood{dir = 4},/turf/open/floor/wood,/area/awaymission/stargate/building) "xK" = (/obj/structure/table/wood,/obj/item/shield/riot/buckler,/obj/item/shield/riot/buckler,/obj/item/shield/riot/buckler,/obj/item/shield/riot/buckler,/turf/open/floor/wood,/area/awaymission/stargate/building) "xT" = (/obj/structure/chair/sofa/right{dir = 1},/obj/machinery/light,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"yc" = (/obj/machinery/light{dir = 4; light_color = "#c1caff"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "yv" = (/turf/open/indestructible/cobble/corner{dir = 1},/area/awaymission/stargate) "yw" = (/obj/structure/reagent_dispensers/keg/aphro/strong,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "yA" = (/obj/structure/flora/junglebush/b,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) @@ -212,33 +319,35 @@ "yT" = (/obj/machinery/hydroponics/soil,/turf/open/floor/grass,/area/awaymission/stargate) "yX" = (/obj/structure/fence{dir = 4},/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "yZ" = (/turf/open/water/jungle,/area/awaymission/stargate) +"zc" = (/obj/machinery/light,/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate/building) "zn" = (/obj/structure/chair/stool/bar,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"zC" = (/obj/structure/table/abductor,/obj/item/surgical_drapes,/obj/item/scalpel/alien,/obj/item/cautery/alien,/obj/item/circular_saw/alien,/obj/item/hemostat/alien,/obj/item/retractor/alien,/obj/item/surgicaldrill/alien,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "zD" = (/obj/structure/closet/crate/wooden,/obj/item/clothing/suit/armor/bone,/obj/item/clothing/head/helmet/skull,/obj/item/clothing/gloves/bracer,/obj/item/clothing/accessory/talisman,/turf/open/floor/wood,/area/awaymission/stargate/building) -"zF" = (/mob/living/simple_animal/hostile/netherworld/migo,/turf/open/indestructible/cobble,/area/awaymission/stargate) "zW" = (/obj/effect/rune/apocalypse,/obj/structure/spawner/nether,/turf/open/floor/plasteel/cult,/area/awaymission/stargate/building) -"Al" = (/obj/item/lighter,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"Av" = (/turf/open/indestructible/concrete,/area/awaymission/stargate) +"Ac" = (/obj/machinery/light{dir = 8; light_color = "#e8eaff"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Aw" = (/obj/structure/table/wood,/obj/item/storage/toolbox/mechanical/old,/turf/open/floor/wood,/area/awaymission/stargate/building) "Az" = (/obj/structure/dresser,/turf/open/floor/wood,/area/awaymission/stargate/building) "AA" = (/obj/structure/table/wood,/obj/item/stack/sheet/leather,/obj/item/stack/sheet/leather,/obj/item/stack/sheet/leather,/obj/item/stack/sheet/leather,/obj/item/stack/sheet/leather,/turf/open/floor/wood,/area/awaymission/stargate/building) "AC" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "AO" = (/obj/machinery/door/airlock/wood/glass,/turf/open/floor/wood,/area/awaymission/stargate/building) -"AW" = (/obj/structure/barricade/sandbags,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) "Be" = (/obj/effect/decal/cleanable/blood/gibs/up,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"BB" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/obj/structure/closet/crate/coffin/metalcoffin,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"Bh" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"Bj" = (/obj/structure/flora/grass/jungle/b,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/grass,/area/awaymission/stargate/building) "BC" = (/obj/structure/flora/ausbushes/palebush,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) -"BI" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "BP" = (/obj/machinery/light,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "BR" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"BZ" = (/obj/structure/table/wood/fancy/black,/obj/item/export/bottle/champagne,/obj/item/reagent_containers/food/drinks/drinkingglass,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"Cb" = (/turf/open/indestructible/concrete/smooth,/area/awaymission/stargate) +"BZ" = (/obj/structure/table/wood/fancy/black,/obj/item/export/bottle/champagne,/obj/item/reagent_containers/food/drinks/drinkingglass,/obj/machinery/light,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "Cc" = (/obj/structure/table/wood/fancy/blackred,/obj/machinery/chem_dispenser/drinks/beer/fullupgrade,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) -"Cj" = (/obj/structure/showcase/horrific_experiment,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"Cf" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Cp" = (/obj/structure/chair/sofa/right{dir = 8},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "Cq" = (/turf/open/floor/plasteel/cult,/area/awaymission/stargate/building) "Ct" = (/obj/machinery/smartfridge/drying_rack,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Cw" = (/obj/structure/flora/junglebush,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "Cy" = (/obj/machinery/computer/operating,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) -"Df" = (/obj/machinery/gateway{dir = 1},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"CA" = (/obj/structure/table/wood/fancy/blackred,/turf/open/floor/grass/fairy/red,/area/awaymission/stargate/building) +"CO" = (/obj/structure/closet/secure_closet/freezer/fridge,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Da" = (/obj/effect/decal/cleanable/semen,/obj/structure/flora/grass/jungle/b,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/grass,/area/awaymission/stargate/building) +"Df" = (/obj/machinery/light{dir = 8},/obj/structure/table/wood/fancy/black,/obj/item/stack/sheet/mineral/gold{amount = 25},/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) "Di" = (/obj/structure/flora/ausbushes/ppflowers,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) "Dj" = (/obj/machinery/light{dir = 4},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "Dk" = (/turf/open/floor/mineral/titanium/yellow,/area/awaymission/stargate/building) @@ -248,105 +357,99 @@ "DD" = (/obj/structure/table/wood/fancy/black,/obj/structure/table/wood/fancy/black,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "DE" = (/mob/living/simple_animal/hostile/retaliate/clown/fleshclown,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "DF" = (/obj/machinery/smartfridge/food,/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) -"DM" = (/obj/effect/decal/remains/human,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) -"DQ" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/indestructible/cobble,/area/awaymission/stargate) +"DM" = (/obj/effect/decal/remains/human,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "Ed" = (/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) "Eh" = (/obj/effect/decal/remains/robot,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"Ei" = (/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"Ej" = (/obj/effect/decal/cleanable/blood/gibs/torso,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"En" = (/obj/machinery/chem_master,/turf/open/floor/wood,/area/awaymission/stargate/building) +"En" = (/obj/structure/bed,/obj/item/bedsheet/grey,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Et" = (/obj/effect/decal/cleanable/semen,/obj/machinery/light,/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) "Ey" = (/obj/structure/table/reinforced,/obj/item/stack/sheet/glass/fifty,/obj/item/stack/sheet/metal/fifty,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "EI" = (/obj/machinery/door/airlock/shuttle,/turf/open/floor/mineral/titanium,/area/awaymission/stargate/building) -"EQ" = (/mob/living/simple_animal/hostile/netherworld,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "ER" = (/obj/machinery/light{dir = 1},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"EY" = (/obj/effect/decal/cleanable/semen,/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) "Fc" = (/obj/structure/table/wood,/obj/item/flashlight/lantern{icon_state = "lantern-on"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Fg" = (/obj/structure/flora/grass/jungle,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) -"Fr" = (/obj/machinery/gateway,/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"Fs" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"Fw" = (/obj/structure/barricade/sandbags,/turf/open/indestructible/cobble/side{dir = 8},/area/awaymission/stargate) +"Fk" = (/obj/machinery/pool/drain,/turf/open/pool,/area/awaymission/stargate/building) +"Fr" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) +"Fw" = (/obj/structure/statue/sandstone/abs,/turf/open/floor/cobble,/area/awaymission/stargate) "FA" = (/obj/structure/ore_box,/turf/open/floor/wood,/area/awaymission/stargate/building) -"FI" = (/obj/machinery/gateway{dir = 5},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"FI" = (/obj/machinery/light{dir = 4},/obj/structure/table/wood/fancy/black,/obj/item/reagent_containers/food/drinks/trophy/gold_cup,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "FM" = (/obj/structure/table/wood,/obj/item/storage/firstaid/regular,/turf/open/floor/wood,/area/awaymission/stargate/building) -"FO" = (/obj/structure/chair/stool/alien,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "FQ" = (/obj/machinery/conveyor{id = "mining_internal"},/turf/open/floor/wood,/area/awaymission/stargate/building) -"Gb" = (/obj/effect/decal/cleanable/blood/gibs/torso,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) "Gg" = (/obj/machinery/mecha_part_fabricator,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"GS" = (/obj/structure/table/wood/fancy,/obj/item/seeds/chili/pink,/obj/item/seeds/chili/pink,/obj/item/seeds/chili/pink,/turf/open/floor/grass,/area/awaymission/stargate/building) "GT" = (/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "GV" = (/obj/machinery/light{dir = 8},/obj/structure/closet/crate/wooden,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) +"GY" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"Hc" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/loading_area{dir = 4; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Hi" = (/obj/machinery/light{light_color = "#e8eaff"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Ho" = (/obj/structure/flora/tree/palm,/obj/structure/flora/ausbushes/ywflowers,/turf/open/floor/grass,/area/awaymission/stargate) "Hp" = (/obj/structure/flora/grass/jungle/b,/turf/open/floor/grass,/area/awaymission/stargate) "HE" = (/obj/effect/decal/remains/xeno,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"Ia" = (/obj/structure/table/wood,/obj/item/storage/box/beakers,/obj/item/storage/box/syringes,/turf/open/floor/wood,/area/awaymission/stargate/building) -"Ib" = (/mob/living/simple_animal/butterfly,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) +"HH" = (/obj/machinery/abductor/experiment{team_number = 100},/turf/open/floor/plating/abductor{initial_gas_mix = "o2=14;n2=23;TEMP=300"},/area/awaymission/stargate/building) +"Ia" = (/obj/structure/table/wood,/obj/item/storage/box/syringes,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Ic" = (/obj/structure/mineral_door/woodrustic,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Ie" = (/obj/machinery/mineral/processing_unit{dir = 1},/turf/open/floor/wood,/area/awaymission/stargate/building) "Ik" = (/obj/structure/chair/sofa{dir = 8},/obj/machinery/light{dir = 4},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "Im" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"Ip" = (/turf/open/indestructible/cobble/corner{dir = 8},/area/awaymission/stargate) -"Iu" = (/obj/structure/table/optable/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) -"Iv" = (/obj/machinery/gateway{dir = 8},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"Iv" = (/obj/effect/decal/remains/robot,/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) +"IA" = (/obj/structure/statue/sandstone/abs,/turf/open/floor/grass/fairy/red,/area/awaymission/stargate/building) "IJ" = (/obj/structure/closet/crate/wooden,/obj/item/stack/sheet/metal/fifty,/obj/item/stack/sheet/metal/fifty,/turf/open/floor/wood,/area/awaymission/stargate/building) "IP" = (/obj/structure/chair/wood,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "IQ" = (/obj/effect/decal/cleanable/semen,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "IU" = (/obj/machinery/door/airlock/bananium,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) -"IV" = (/obj/effect/decal/remains/human,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) "IX" = (/obj/structure/flora/ausbushes/palebush,/obj/structure/flora/ausbushes/ywflowers,/turf/open/floor/grass,/area/awaymission/stargate) "Jb" = (/obj/effect/decal/remains/human,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Jc" = (/obj/effect/decal/remains/human,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"Jh" = (/obj/structure/rack/shelf,/obj/item/gun/ballistic/automatic/wt550,/obj/item/gun/ballistic/automatic/wt550,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"Jh" = (/obj/structure/rack/shelf,/obj/item/storage/firstaid/regular,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Jm" = (/obj/machinery/door/airlock/wood,/obj/structure/barricade/wooden/crude,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Jp" = (/obj/structure/flora/junglebush/c,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) -"Jw" = (/obj/effect/decal/cleanable/blood/gibs/human/limb,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) "JB" = (/obj/structure/shuttle/engine/heater,/obj/structure/window/reinforced{dir = 1},/turf/open/floor/plating,/area/awaymission/stargate/building) -"JX" = (/obj/machinery/sleeper{dir = 4; icon_state = "sleeper"},/turf/open/floor/wood,/area/awaymission/stargate/building) -"Kc" = (/mob/living/simple_animal/hostile/retaliate/clown/mutant,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"JP" = (/mob/living/simple_animal/hostile/netherworld,/turf/open/indestructible/necropolis/air,/area/awaymission/stargate/building/flesh) +"JX" = (/obj/structure/table/wood,/obj/item/defibrillator/loaded,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Kc" = (/obj/structure/table/wood/fancy/black,/obj/item/storage/fancy/ringbox,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"Kg" = (/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate/building) "Km" = (/obj/structure/table/wood/fancy/blackred,/obj/item/storage/box/drinkingglasses,/obj/item/storage/box/drinkingglasses,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) "Kn" = (/turf/open/floor/mineral/titanium,/area/awaymission/stargate/building) +"Ku" = (/obj/machinery/light{dir = 8},/obj/structure/showcase/horrific_experiment,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"Kv" = (/obj/structure/flora/junglebush/c,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/grass,/area/awaymission/stargate/building) "KE" = (/obj/structure/flora/junglebush/c,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) "KG" = (/obj/structure/chair/wood{dir = 1},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"KO" = (/obj/structure/statue/bananium/clown,/turf/open/indestructible/cobble/side{dir = 4},/area/awaymission/stargate) "KQ" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/wood,/area/awaymission/stargate/building) "KY" = (/obj/structure/dresser,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "KZ" = (/obj/structure/flora/grass/jungle/b,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "Lb" = (/obj/structure/loom,/turf/open/floor/wood,/area/awaymission/stargate/building) "Lf" = (/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate) -"Lj" = (/obj/structure/bonfire,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate/building/mountain) -"Lp" = (/obj/machinery/gateway{dir = 4},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"Lk" = (/obj/machinery/light{dir = 8},/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"Lp" = (/obj/structure/table/wood/fancy/blackred,/obj/item/storage/firstaid/regular,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) "Lq" = (/obj/structure/table/wood,/obj/machinery/reagentgrinder,/turf/open/floor/wood,/area/awaymission/stargate/building) "Ls" = (/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"Lv" = (/obj/effect/decal/remains/human,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) "Ly" = (/obj/structure/showcase/horrific_experiment,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "Lz" = (/obj/machinery/shower{dir = 4},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "LB" = (/obj/effect/decal/remains/human,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"LC" = (/obj/effect/decal/remains/xeno,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "LI" = (/obj/structure/flora/rock/pile,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "LJ" = (/obj/effect/decal/cleanable/blood/tracks,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "LK" = (/obj/structure/flora/ausbushes/reedbush,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) +"LM" = (/obj/structure/table/wood,/obj/item/storage/firstaid/regular,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "LO" = (/obj/structure/flora/tree/palm,/obj/structure/flora/junglebush/c,/turf/open/floor/grass,/area/awaymission/stargate) "LP" = (/obj/structure/shuttle/engine/propulsion,/turf/open/floor/plating,/area/awaymission/stargate/building) "LQ" = (/obj/structure/toilet,/turf/open/floor/wood,/area/awaymission/stargate/building) -"Mk" = (/obj/item/kitchen/knife/combat/bone,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "Mr" = (/turf/closed/wall/mineral/wood/nonmetal,/area/awaymission/stargate) "Ms" = (/obj/structure/chair/comfy/shuttle{dir = 1},/turf/open/floor/mineral/titanium/blue,/area/awaymission/stargate/building) "Mu" = (/obj/structure/mineral_door/woodrustic,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Mx" = (/obj/machinery/light{dir = 8; light_color = "#e8eaff"},/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) +"MB" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/loading_area{dir = 8; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "MC" = (/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "MD" = (/obj/structure/chair/sofa{dir = 4},/obj/machinery/light{dir = 8},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "MI" = (/obj/structure/flora/ausbushes/ywflowers,/turf/open/floor/grass,/area/awaymission/stargate) -"MZ" = (/obj/structure/reagent_dispensers/keg/semen,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) -"Ne" = (/obj/effect/decal/cleanable/blood/gibs,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) +"MM" = (/obj/effect/turf_decal/loading_area{dir = 8; icon_state = "drain"; name = "drain"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "Nh" = (/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Nk" = (/obj/structure/frame/computer,/obj/effect/decal/cleanable/glass,/obj/item/shard,/turf/open/floor/mineral/titanium/yellow,/area/awaymission/stargate/building) "Nr" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) "Nv" = (/obj/machinery/light{dir = 4; light_color = "#c1caff"},/turf/open/floor/mineral/basaltstone_floor,/area/awaymission/stargate/building) -"NA" = (/obj/structure/table/abductor,/obj/item/surgical_drapes,/obj/item/scalpel/alien,/obj/item/cautery/alien,/obj/item/circular_saw/alien,/obj/item/hemostat/alien,/obj/item/retractor/alien,/obj/item/surgicaldrill/alien,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "ND" = (/obj/structure/mirror,/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) "NN" = (/obj/effect/decal/cleanable/blood/gibs/torso,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "NR" = (/obj/machinery/processor,/turf/open/floor/wood,/area/awaymission/stargate/building) -"NU" = (/obj/structure/barricade/wooden,/turf/open/indestructible/cobble,/area/awaymission/stargate) "Oi" = (/turf/closed/wall/mineral/titanium,/area/awaymission/stargate/building) -"Ol" = (/obj/structure/bonfire,/turf/open/indestructible/cobble,/area/awaymission/stargate) -"Om" = (/obj/machinery/door/airlock/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "On" = (/obj/structure/curtain,/turf/open/floor/wood,/area/awaymission/stargate/building) "Op" = (/obj/structure/closet/crate/wooden,/turf/open/floor/wood,/area/awaymission/stargate/building) "Ov" = (/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) @@ -355,15 +458,15 @@ "OE" = (/turf/open/floor/wood,/area/awaymission/stargate) "OK" = (/obj/structure/rack/shelf,/obj/item/storage/box/lethalslugs,/obj/item/storage/box/lethalslugs,/obj/item/storage/box/lethalslugs,/obj/item/storage/box/lethalslugs,/obj/item/storage/box/lethalslugs,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "OM" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"OZ" = (/obj/machinery/abductor/experiment{team_number = 100},/turf/open/floor/plating/abductor{initial_gas_mix = "o2=14;n2=23;TEMP=300"},/area/awaymission/stargate/building) +"Pd" = (/obj/structure/table/wood/fancy,/obj/item/seeds/watermelon/milk,/obj/item/seeds/watermelon/milk,/obj/item/seeds/watermelon/milk,/turf/open/floor/grass,/area/awaymission/stargate/building) "Ph" = (/obj/structure/barricade/sandbags,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "Pi" = (/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"Pw" = (/obj/structure/fence{dir = 4},/turf/open/indestructible/cobble,/area/awaymission/stargate) "Pz" = (/obj/structure/table/wood,/obj/item/pickaxe,/obj/item/pickaxe,/obj/item/shovel,/obj/item/shovel,/turf/open/floor/wood,/area/awaymission/stargate/building) "PA" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "PC" = (/obj/structure/table,/turf/open/floor/mineral/titanium/white,/area/awaymission/stargate/building) "PD" = (/obj/structure/table/wood,/obj/item/storage/bag/ore,/obj/item/storage/bag/ore,/obj/item/mining_scanner,/obj/item/mining_scanner,/turf/open/floor/wood,/area/awaymission/stargate/building) -"PG" = (/obj/structure/barricade/sandbags,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"PG" = (/obj/structure/table/wood,/obj/item/storage/box/beakers,/turf/open/floor/wood,/area/awaymission/stargate/building) +"PR" = (/mob/living/simple_animal/hostile/netherworld,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "PS" = (/obj/machinery/light{light_color = "#e8eaff"},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) "PT" = (/obj/structure/flora/grass/jungle,/mob/living/simple_animal/butterfly,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "PW" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) @@ -372,36 +475,42 @@ "Qv" = (/turf/open/floor/grass,/area/awaymission/stargate) "Qx" = (/obj/structure/chair/wood,/turf/open/floor/mineral/gold,/area/awaymission/stargate/building) "QA" = (/obj/structure/flora/junglebush,/turf/open/floor/grass,/area/awaymission/stargate) -"QM" = (/obj/effect/decal/cleanable/blood/gibs,/turf/open/indestructible/cobble,/area/awaymission/stargate) +"QF" = (/obj/structure/flora/grass/jungle,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "QN" = (/obj/effect/decal/cleanable/blood/tracks{dir = 8},/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "QZ" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/wood,/area/awaymission/stargate/building) "Rb" = (/obj/machinery/rnd/destructive_analyzer,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"Rf" = (/mob/living/simple_animal/hostile/retaliate/clown/lube,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "Rj" = (/obj/structure/chair/comfy/shuttle{dir = 1},/turf/open/floor/mineral/titanium/yellow,/area/awaymission/stargate/building) "Rq" = (/mob/living/simple_animal/butterfly,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "Rt" = (/obj/effect/decal/cleanable/blood,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"Rx" = (/obj/machinery/vending/cigarette/beach,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"Ry" = (/obj/structure/table/wood,/obj/item/storage/backpack/duffelbag/med/surgery,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Rx" = (/obj/machinery/vending/cigarette{extended_inventory = 1; free = 1},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"Ry" = (/obj/structure/table/wood,/obj/item/storage/backpack/duffelbag/med/surgery,/obj/item/flashlight/lantern{icon_state = "lantern-on"},/turf/open/floor/wood,/area/awaymission/stargate/building) "RC" = (/obj/structure/pole,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) "RL" = (/obj/structure/table/wood,/obj/item/storage/fancy/candle_box,/obj/item/lighter,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"RM" = (/turf/closed/indestructible/sandstone,/area/awaymission/stargate/building/mountain) "RO" = (/obj/machinery/vending/kink{free = 1},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"RS" = (/obj/structure/flora/grass/jungle/b,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "RT" = (/obj/structure/flora/grass/jungle/b,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) "RX" = (/obj/structure/chair/sofa/corner{dir = 8},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) -"Sh" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/indestructible/cobble,/area/awaymission/stargate) +"Ss" = (/obj/effect/decal/cleanable/semen,/obj/structure/flora/grass/jungle/b,/turf/open/floor/grass,/area/awaymission/stargate/building) "Su" = (/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) +"SE" = (/obj/effect/decal/cleanable/blood/gibs/body,/mob/living/simple_animal/hostile/retaliate/clown/lube,/turf/open/floor/cobble,/area/awaymission/stargate) "SF" = (/obj/structure/table/wood,/obj/item/kitchen/knife/ritual,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "SI" = (/obj/item/storage/box/rubbershot{pixel_x = -3; pixel_y = 3},/obj/item/storage/box/rubbershot{pixel_x = -3; pixel_y = 3},/obj/item/storage/box/rubbershot,/obj/item/storage/box/rubbershot,/obj/item/storage/box/rubbershot{pixel_x = 3; pixel_y = -3},/obj/structure/rack/shelf,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "SP" = (/obj/machinery/door/airlock/wood/glass,/obj/structure/barricade/wooden/crude,/turf/open/floor/wood,/area/awaymission/stargate/building) "Tb" = (/obj/structure/chair/sofa/corner{dir = 4},/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"Te" = (/mob/living/simple_animal/hostile/retaliate/clown/lube,/turf/open/floor/concrete,/area/awaymission/stargate) "Tn" = (/obj/structure/table/wood/fancy,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "Tu" = (/mob/living/simple_animal/butterfly,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "Tv" = (/obj/structure/flora/tree/palm,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) -"TD" = (/obj/effect/decal/remains/xeno,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"TC" = (/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/destroyer,/turf/open/floor/cobble/side{dir = 1; icon_state = "cobble_side"},/area/awaymission/stargate) +"TD" = (/obj/effect/decal/remains/xeno,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "TE" = (/obj/machinery/deepfryer,/turf/open/floor/wood,/area/awaymission/stargate/building) -"TG" = (/obj/item/grown/log/tree,/turf/open/indestructible/cobble,/area/awaymission/stargate) "TI" = (/obj/structure/flora/tree/palm,/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate) "TM" = (/obj/machinery/rnd/production/circuit_imprinter,/obj/item/reagent_containers/dropper,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "TR" = (/obj/structure/mineral_door/woodrustic,/turf/open/floor/carpet,/area/awaymission/stargate/building) "TX" = (/obj/effect/decal/cleanable/blood/innards,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) +"Ub" = (/obj/structure/table/wood,/obj/item/reagent_containers/glass/bottle/mutagen,/turf/open/floor/wood,/area/awaymission/stargate/building) "Uc" = (/obj/structure/flora/junglebush/large,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "Ue" = (/obj/structure/flora/rock/pile/largejungle,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate) "Um" = (/obj/machinery/light{dir = 1; light_color = "#d1dfff"},/obj/structure/reagent_dispensers/water_cooler,/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) @@ -410,51 +519,54 @@ "UC" = (/turf/closed/indestructible/sandstone,/area/awaymission/stargate/building) "UF" = (/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "UG" = (/obj/effect/spawner/structure/window/shuttle,/turf/open/floor/plating,/area/awaymission/stargate/building) -"UI" = (/obj/structure/bed,/obj/item/bedsheet/grey,/turf/open/floor/wood,/area/awaymission/stargate/building) +"UH" = (/turf/open/pool,/area/awaymission/stargate/building) +"UI" = (/obj/effect/decal/cleanable/blood,/obj/structure/chair/wood{dir = 8},/turf/open/floor/wood,/area/awaymission/stargate/building) +"UM" = (/mob/living/simple_animal/hostile/retaliate/clown/lube,/turf/open/floor/concrete/smooth,/area/awaymission/stargate) "UN" = (/obj/machinery/biogenerator,/turf/open/floor/wood,/area/awaymission/stargate/building) +"Vd" = (/obj/structure/flora/junglebush,/turf/open/floor/grass,/area/awaymission/stargate/building) "Vh" = (/obj/structure/flora/junglebush/b,/mob/living/simple_animal/butterfly,/turf/open/floor/grass,/area/awaymission/stargate) "Vk" = (/obj/structure/table/plasmaglass,/obj/structure/table/plasmaglass,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"Vl" = (/obj/effect/decal/remains/xeno,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"Vx" = (/obj/effect/decal/cleanable/semen,/obj/structure/table/optable/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "Vy" = (/mob/living/simple_animal/hostile/retaliate/clown/fleshclown,/turf/open/floor/mineral/titanium,/area/awaymission/stargate/building) "VG" = (/obj/structure/table/plasmaglass,/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) "VJ" = (/obj/structure/table/wood,/obj/machinery/microwave,/turf/open/floor/wood,/area/awaymission/stargate/building) "VM" = (/obj/structure/table/reinforced,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) -"VU" = (/obj/structure/barricade/wooden,/turf/open/indestructible/cobble/side{dir = 4},/area/awaymission/stargate) "VY" = (/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate) "VZ" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/wood,/area/awaymission/stargate/building) "Wa" = (/obj/structure/bed,/obj/effect/decal/cleanable/semen,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "Wh" = (/turf/open/floor/carpet/royalblack,/area/awaymission/stargate/building) +"Wx" = (/obj/structure/chair/stool/alien,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "WB" = (/obj/machinery/gibber,/turf/open/floor/wood,/area/awaymission/stargate/building) -"WJ" = (/obj/structure/closet/crate/coffin/metalcoffin,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"WC" = (/obj/effect/decal/cleanable/greenglow,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) "WL" = (/obj/machinery/mineral/unloading_machine{dir = 1; icon_state = "unloader-corner"; input_dir = 1; output_dir = 2},/turf/open/floor/wood,/area/awaymission/stargate/building) "WO" = (/obj/machinery/mineral/processing_unit_console,/turf/closed/wall/mineral/sandstone,/area/awaymission/stargate/building) -"WR" = (/obj/machinery/gateway{dir = 9},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) -"WU" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/indestructible/cobble/side,/area/awaymission/stargate) +"WR" = (/obj/structure/table/wood,/obj/machinery/cell_charger,/turf/open/floor/wood,/area/awaymission/stargate/building) "WW" = (/obj/machinery/vending/boozeomat/all_access,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) -"Xg" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate/building/mountain) -"Xh" = (/obj/effect/decal/cleanable/semen,/obj/structure/table/optable/abductor,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) +"Xg" = (/mob/living/simple_animal/hostile/skeleton,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "Xi" = (/obj/structure/mineral_door/wood,/turf/open/floor/wood,/area/awaymission/stargate/building) "Xp" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"Xr" = (/obj/structure/barricade/sandbags,/turf/open/indestructible/cobble,/area/awaymission/stargate) "XE" = (/obj/structure/flora/tree/palm,/obj/structure/flora/ausbushes/ppflowers,/turf/open/floor/grass,/area/awaymission/stargate) "XF" = (/obj/structure/bonfire,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) "XH" = (/obj/structure/barricade/wooden,/turf/open/floor/plating/asteroid,/area/awaymission/stargate) -"XI" = (/obj/machinery/light{dir = 8},/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) -"XJ" = (/obj/machinery/gateway{dir = 10},/turf/open/floor/mineral/crimsonstone_floor,/area/awaymission/stargate/building) +"XJ" = (/obj/effect/decal/cleanable/blood/gibs/body,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "XW" = (/obj/machinery/door/airlock/wood,/turf/open/floor/carpet/red,/area/awaymission/stargate/building) "Yg" = (/obj/structure/chair/comfy/shuttle{dir = 1},/obj/machinery/light,/turf/open/floor/mineral/titanium/blue,/area/awaymission/stargate/building) "Yo" = (/obj/machinery/vending/hydroseeds,/turf/open/floor/wood,/area/awaymission/stargate/building) "Yv" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/carpet/orange,/area/awaymission/stargate/building) -"Yw" = (/obj/effect/decal/cleanable/blood/old,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate/building/mountain) -"YN" = (/obj/item/kitchen/knife/combat/bone,/turf/open/floor/plating/dirt/dark/jungle,/area/awaymission/stargate/building/mountain) +"Yw" = (/obj/effect/decal/cleanable/blood/old,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) +"YN" = (/obj/item/kitchen/knife/combat/bone,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) "YP" = (/obj/machinery/conveyor{dir = 8; id = "mining_internal"},/obj/structure/plasticflaps,/turf/open/floor/wood,/area/awaymission/stargate/building) "YQ" = (/obj/structure/closet/crate/wooden,/obj/item/stack/sheet/mineral/sandstone/twelve,/obj/item/stack/sheet/mineral/sandstone/twelve,/turf/open/floor/wood,/area/awaymission/stargate/building) "YS" = (/obj/structure/table/wood,/obj/item/mop,/obj/item/reagent_containers/glass/bucket,/obj/item/soap,/turf/open/floor/wood,/area/awaymission/stargate/building) -"Za" = (/mob/living/simple_animal/hostile/jungle/mook,/turf/open/indestructible/cobble/side{dir = 1},/area/awaymission/stargate) "Zh" = (/obj/structure/table/wood,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) +"Zk" = (/obj/effect/decal/cleanable/greenglow,/turf/open/floor/mineral/abductor,/area/awaymission/stargate/building) "Zl" = (/obj/structure/flora/grass/jungle,/turf/open/floor/grass,/area/awaymission/stargate) +"Zp" = (/obj/structure/table/wood/fancy,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/obj/item/reagent_containers/rag/towel,/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) "Zq" = (/obj/machinery/light,/turf/open/floor/mineral/bananium,/area/awaymission/stargate/building) "ZM" = (/obj/structure/chair/wood{dir = 4},/turf/open/floor/mineral/sandstone_floor,/area/awaymission/stargate/building) -"ZW" = (/obj/structure/bonfire,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"ZP" = (/obj/structure/flora/grass/jungle/b,/mob/living/simple_animal/hostile/jungle/mook,/turf/open/floor/plating/dirt/jungle,/area/awaymission/stargate/building/mountain) +"ZW" = (/obj/structure/bonfire,/turf/open/floor/plating/asteroid,/area/awaymission/stargate/building/mountain) (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -466,131 +578,131 @@ aaaaabababababababababababababababababababababababababababababababababababababab aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsababababababababababababababababababababababababababababababababababababLsLsababLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsabababababababababababababababababababababababababababababLsababLsLsLsLsLsLILsLsLsLsabababababababababababababababababababLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLILsLsLsLsLsLsLsabababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsabLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsabababababLsabLsababababLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLskeLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsababababababababababababababababababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsababLsLsLskeLsLsLsLILsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLsaWLsLsLsLsLsababababababLsLsLsLsLILsBRLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsLskeLsLsBRLsLsaWLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLILsLsLsLsLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLILsLsLsLsLsLsLsLsLILsLsLsLsLsLILsLsLsLILsLsLsaWLsLsLsLILsLsLsLsabababLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLILsBRLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLskeLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsBRLsLsLsLsLskeLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsLsLILsLsLsLsLsLsOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvLsLsLsLskeLsLsLsLsLsLsabababLsLsLsLsLsLBLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababLsLsLsLsLsLsLsLsLsLsabababababababLsLsLsLsLsLsLsLsLsLsLsLsLsUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsBRLsLsLsLsLsLsLsOvKYUFTnOvKYUFTnOvkQcsOvKYUFTnOvKYUFTnOvLsLsLsLsLsLsLsLsabababababababLsLsLsLsLILsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsBRLsabababababababababLsababLsLsLsLsLsLsLsLsUCrXrXDDvzyOvzvzrXrXUCWJNhBBNhWJUCwPPiUCNhNhNhNhPWNhNhNhNhUCLsLsLsLILsBRLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLskeLsLsLsLsLsLsLsLskeLsLsLsOvGVUFWaOvGVUFWaOveQVZOvvMUFDzOvvMUFDzOvLsLsLILsLILsLsababababababababLsLsLsLsLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsLsLsLsLsLsBRLILsabababababababababababababLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLILsLsUCrXrXnRQxjFQxnRrXrXUCNhNhOMNhNhmtPiqCUCNhEhNhRtNhNhJbNhBeUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLILsLsOvUFUFUFOvUFUFUFOvaqcsOvUFUFUFOvUFUFUFOvLsLsLsLsLsLsababababababababababLsLsLsOvOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsababababababababababababababLsLsLsLsLsLsLsUCMxrXrXrXrXrXrXrXNvUCWJNhWJNhWJUCPiQgUCNhNhPibQPiPiPiNhNhUCLsLsLsLsLsLsLsLsLsLILsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLILsLBLsLsaWLsLsLsLsLsOvOvXWOvOvOvXWOvOvOvSPOvOvXWOvOvOvXWOvOvLsLsLsLsLsLsababababababababababLsLsLsOvRylgvcOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsLsUCrXNrrXPiPiPirXrXrXUCUCUCUCUCUCUCJcPiUCNhBeJcWRDfFIPiNhNhUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvDrWhvOWhWhWhACWhWhWhWhACWhWhWhWhWhWhOvLsLsLsLsababababababababababababLsLsLsOvcsQZcsOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsLsLsabababababababababababababababababLsLsLsLsababababababababababababababLsLskeLsLsLsLsLsUCNhNhNhPiPiPiPiPiPiJmPiQgPiPibQPiPiqCUCoXNhPiIvoSLpPiRteZUCLsLsLsLsLsLsLsLsLsLsLsLskeLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLsOvWhWhWhWhWhWhWhWhvOWhWhWhWhvOWhWhWhWhOvLsLsLsabababababababababababababLsLsLsOvcscscsOvLsLsLsLsLsLsLsLskeLsLsLsLsabababababababababababababababababababababLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsLsUCNhNhNhPiPiPiPiPiPiJmkpwPPiJcPiPiPiPiUCNhEhwPXJFrmBPiNhNhUCLsLsBRLsLsLskeLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsOvOvsnOvOvOvOvOvOvOvOvOvOvOvOvOvOvsnOvOvLsLsLsababababababababababababLsLsLsLsOvOvfNOvOvOvOvOvOvLsLsLsLsLsLsLsLsabababababababababababababababababababababababLsLsLsLILsLsabababababababababababababLsLsLsLsLsLILsLsUCNhNhNhPiPiPiNhOMNhUCUCUCOmUCUCUCwPbQUCNhNhetPiLJPiJcNhNhUCLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsOvROWhROnnrUCcbLWWKmKmWWbLCcrUnnROWhROOvLsLsLsabababababababababababLskeLsLsLsOvcscsIaUILqcsEnOvLsLsLsLsLsLsLsLsLsabababababababababababababababababababababLsLsLskeLsLsLsLsababababababababababababLsLsLsLsLsLsLsLsUCKGKGKGPiPiPiKGKGKGUCgnEQgngngnUCPiPiUCRtJbNhPGPGPGNhBeNhUCLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsOvDrWhWhEdEdEdEdEdEdEdYvEdEdEdEdWhWhDjOvLsLsLsLsababababababababababLsLsLsLsLsOvJXcscscsltQZmvOvLsLsLsLsLsLsLsLsababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsababababababababababababLsLILsLsLsaWLsLsUCnXNhNhPiPiPiNhNhtIUCvSgnNAgnCjUCQgqCUCNhNhNhPikpPiNhNhRtUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsaWLsLsLsLskeLsLsLsLsaWLsLsOvWhWhznnnEdYvEdEdEdEdEdEdEdEdnnznWhWhOvLsHELsLsabababababababababababLsLsLsLsOvcsKQQZcscsKQcsOvLsLsLsLsLILsLsLsabababababababababababababababababababababLsLsLBLsLsLsLsLsababababababababababababababLsLsLsLsLsLsLsUCKGKGKGPiPiPiKGKGKGUCgnFOIugngnUCPiPiUCUCUCUCcjUCcjUCUCUCUCLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLILsLsababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLILsLsLsLsLsLsLsLsLsLsLsLsOvywWhznyCnnnnnnnnnnnnnnnnnnnnyCznWhywOvLsLsLsLsabababababababababababLsLsLsLsOvJXcscscscscscsOvLsLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsLsLILsLsLsababababababababababababababLsLsLsLsLsLsLsUCNhNhNhPiPiQgNhNhNhUCCjEQNAgnCjUCPiJckMPiPiPiwPERPiPiPiUmUCLsLsLsLsLsLsLsLILsBRLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLILsLsLsLsLsLsOvoxWhWhznznznznznznznznznznznznvOWhCpOvLsLsLsLsLsLsababababababababLsLsLsLsLsOvOvOvAOOvOvAOohOvLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsLsLsLsLsLsLsababababababababababababababLsLsLskeLsLsLsUCKGKGKGPiPiPiKGKGKGUCXIFOIugngnUCPiPiPiQgPiJcPiPiPiPiPiQgUCLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsOvMDVGWhWhWhEdEdEdWhWhEdEdEdWhWhWhVGIkOvLsLsLsLsLsLsLsLsabababababLsLsLsLsLsLsvvapapcsmaapcscsOvLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLILsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsUCnXNhNhPiPiPiNhNhtIUCCjLCNAgnCjUCUCUCUCUCUCUCUCmtUCUCUCUCUCLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLILsLsLsLILsLskeLsOvbPVkWhvOWhEdRCEdWhvOEdRCEdWhWhWhfmozOvLsLsLILsLsLsLsLsabababababLsLsLsLsLsLsvvxGcscscsahtNQZOvLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababLsLsLsLILsLsUCKGKGKGPiPiPiKGKGKGUCgnFOXhEQgnUCJhPWOKNhaxPWaiNhNhmbPWSIUCLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvbPVGWhWhWhEdEdEdWhWhEdEdEdWhWhWhVGozOvLskeLsLsLsLsLsLsLsabababababLsLsLsLsLsOvxGQZcscsapcscsOvLskeLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsUCNhNhOMPiPiPiNhNhNhUCvSgngngnCjUCJhNhOMNhNhOMNhNhOMNhNhdOUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsOvTbDxWhWhWhWhWhWhWhWhWhWhWhWhWhWhxTRXOvLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsvvxGcsKQcsahtNcsOvLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsabababababababababababababLsLsLsLsLsUCHiNhNhPiPSPiNhNhHiUCoCEQMZgnOZUCayNhazNhaiNhaiNhNhwFNhaGUCLsLsLsLILsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLILsLILsLsLsLsaWLsLsLsLsLsLsOvOvOvOvOvWhtChcBZWhWhBZtChcWhOvOvOvOvOvLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLskeLsOvxGcscsQZapcscsOvLsLsLsaWLsLsLsLsLsLsLsababababLsabLsLsabLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsababababababababababababababLsLsLsLsUCUCUCUCJmqKJmUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsLsLsLsLsLsLsLsBRLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvWhWhWhWhWhvOWhWhWhWhOvLsLsLsLsLsLsaWLsLskeLsLsLsLsLsLsLsLsaWLsLsLsLsvvxGcscscsahtNcsOvLsLsLsLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsyvmTmTmTuRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLILsLskeLsLsOvRxBPWhWhWhWhWhWhBPRxOvLsLILsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsvvapapcscsapcsKQOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsabababababababababababababababLsLsLskeLsLsuIxnxnxnnyLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLBLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvOvOvOvwZOvOvwZOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvOvOvSPSPOvvvvvOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsuIxnxnxnnyLsLsLILsLskeLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsBRLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsaWLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLILsLsyvmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTuRLsLsLsLsabababababababababababababababLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsabababababababababababababababababLsBRLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsHELsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababLsLsLskeLsLsLsLsLsLILsLsLsLsLsababLsLsLsLsLsLsLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsabababababababababababababababababLsLsLsLsLsuIxnxnsYnyLsLsLsaWLsLsLsLsLsLsLskeLsLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababLsLsLskeLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsababababababababababababababababababLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsababababLsLsLsLILsLsLsLsLsLsBRLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLILsLsLsLsLsLsLsLsLsabababababababLsLsLsLsIpwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvxnxnxnxnnyLsLsLsabababababababababababababababababLsLsLsLILsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLsLsLsBRLsLsababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLILsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsuIxnxnxnnyLsLsLsLsabababababababababababababababLsLsLsLsLsLsuIxnxnxnnyLsLsBRLsLsLsLsLsLsLsLsLsLsababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsaWLsLsLsLsLsLsLsabababLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLskeLsLsababababababababababababababLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLBLsLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsaWLsLsLILsLsLsLILsLsLILsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsabababababababLsLsuIxnxnxnnyLsLsLsLsabababababababababLsababababLsLsLsLskeLsLsuIxnxnxnnyLsLsLsLsLILsLsLsLsLsababababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsababLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsHELsLsLsLsLsLsLsLsLsabababababababababababLsuIxnxnxnnyLsLsLsababababababababLsLsLsababLsLsLsLILBLsLsLsLsuIsYxnxnnyLsLILsLsLsLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsabLsabLsLsLsLsLsLsLILsLsLsBRLsLsLsLsLsLsLsLsababababLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsuIxnxnxnnyLsLsLsLsLsababababababLsLsLsabLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsababababababababababababLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsabLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababLsLsLsLsLsuIxnxnxnnyLsLILsLsLsLsLsLsababLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsuIxnxnxnnyLsLskeLsLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsaWLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababLsLsLsLsLsBRLsLILsLskeLsLsLsLsabababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsabababababLsLsLsLsaWLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsLILskeLsLsLsLsLILsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLILsLsLsLsababababLsLsLsLsLsLsLskeLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLILsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLILskeLsLsabababababababababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLILsLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLskeLsLsababababababLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnxnmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTxnxnxnxnnyLsLsLsLsLsLsLsLsacacababababababababababababLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababLsLskeLsLsLILsLsLsabLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsabababababababababLsLILsLsLsabababababLsLsLsLsLskeLsLsLsLsLsLsLsLILsLsLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLILsLsLsLsacacBIababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababLsLsLsLsababababababababababLsLsLsabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsLsLsLsabababacabababababababababababLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLskeLsLsLsLsLsLsLsabababababababababababababababababababababLsababababababababababababababababababababababababLsLsLsLILsLsLsLILsLsLsLsLsLsLsuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsLsLsLsabababacacacababababababababLsLsLsLsvuLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLILsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsaWLsLsLILsuIxnxnxnxnwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvsCLsLsLsLsLsabababacacacacabababababababLsLsLILsLsLsLsLsLsvuLsLsLILsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLsLsabLsLsLsababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsabababababacabababababababLsLsLsLsLsvuLsaELsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababLsLILsLsLsLsLsLsLsLsLsababababababMrMrMrMrXHMrMrMrMrababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLILsLsLsLsLsLsLsLILsLsLsLsLskeLsLsLsLsLsLsLsLsLskeLsLsLsLsababababacacabababababababLsLsLsLsLsLsLsLsLsLsLsLsaFLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsImLsLsLsLsabababLsLsLsLsLILsLskeLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLskeLsLsLILsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababacacababababababLsLsLsLsLsLsLsaCLBLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLskiLsLsXpLsLsLILsLsLsLsLsabLsLsLsLsImLsLsLsLsLskeLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLILsLsLsLsLsLsuIxnxnxnnyLsLsaWLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsababLsabababababacacabababababLsLsLsLsvuLsLsLsaWaDLsLsLsLsLsvuLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLBLsLskeLsLsUsLsLsLsLsLsTXLsLsLsLsLsLsXpkiLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsababababLsLsLsababLsLsLsLsLsLsLsLsababababababababababacacacacababababLsLsLsLsLsLILsLsLsLsLsLsvuLsLILsLsLsLsvuLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLILsLsLsLILsLsLsLsLsrhLsLsLILsLsLsLsaWLsLsLsLsLsLsLsLsababababababababLsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsabababababababababababababLsLsLsLsLsabababababababababababacacabababababLsLsLsvuLsLsLsLsaBLsLsLsLsLsLsLsaALsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsImLsLsLshKLsLsLsLsLsLsLsLsLsXpLsLsLsLshKLsLsLsUsLsLsLsababababababLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsaWLsLsLsLsuIxnxnxnnyLsLILsLsabababababababababababababababababLsLsLsababababababababababababacabababababLsLsLsLsLsvuLskeLsLsvuLsLsLsLsLsLILsLsLskeLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLBTXLsLsLsLBLskeLsLsLsLsLsLsLBLsLILsLsLsLsababababababLsLILsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsuIxnxnxnnyLsLsLsLsabababababababababababababababababababababababababababababababacacabababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsvuLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLskeLsXpLsLsLsXpLsLsLsLsLskebALsLsLsLsLsXFLsLskeLsLsLsLBLsLsLsabababababababLskeLsLsabLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsuIxnxnxnnyLsLsLsLsababababababababababababababababababababababababababababababacacababababababababLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsTXLsLsLBLskeLsLsIQLsLILsLsLsXpLsLsLsLsLsLsbALsLsLsLsXpLsLsLsLsababababababLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababLsLsLILsLsuIxnxnxnnyLsLsLsLsLsababababababababababababababababababababababababababababacacacabababababababababababababababLsLsLsLskeLsababLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLskiLsLsLsXFLsLsLsLsLsLILsTXLsXpLsLsLsTXLsLsLsLILsLsababababababLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsuIxnxnxnnyLsLsLsLsLsababababababababababababababababababababababababababababacacababababababababababababababababababLsLsLsLsabababababababababLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsaWLsLsXpLsLsLsLsLsLsLsLsLsImhKLskeLsLsLsLskeLsLsLsLsLsLsLsLsLsMrLsLsLsababLsLsLsLILsLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsuIxnxnxnnyLsLsLsLsLsabababababababababababababababababababababababababababababacacabababababababababababababababababababLsLsLsabLsLsababababLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsImLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLBLsLsLsLsLsImLsLsLsXFLsLsLsMrLskeLsLsLsLsLsLsLsLsLsabLsabababLsLsLsabLsabababababababababababababababababababababababababababababababababababXHXHXHXHXHsuNUNUNUVUXHXHXHXHababababababababababababababababababababababababababababababacacabababababababababababababababababababLsLsLsLILsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsLILsLsImkiLsXpLsLBLsLsaWLsLsLsLILsLBLsLsLsLsLsLsLsLsQNQNuaQNQNQNLsLILsLskeLsLsLsLsLsLsLsabLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsabababababababababababababababababababababababababacabacacacababacacababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsXpLsLsbALsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsUsLsLsLsLsLsMrLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLsLskeLsLsuIxnxnxnnyLsLsababababababababababababababababababababababababhmacacDMacacacacacacababababababababababababababababababababLsabababababLskeLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsUsLsLsLsLsLsLsLsLILsLskeLsbALsLsLskiLsLsXpLsLsLsLsLsLsLsImLsLsLsMrLsLsLsLsLsLsLsLsLsLsLsababLsLsLsLsLsLsLskeLsLIabababababababababababababababababababababababababababababababLsLsLILsLsLsLsuIxnxnxnnyLsLsabababababababababababababababababababababababacacBIacacacMkacacacacababababababababababababababababababababababababababLsLsLsLsaWLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababLsLsLsLsLBLsLsLsLsXFLsLsUsLsLsLsLsHELskiLskeLsImLsLsLsXpLsLsLsLsLsabababLsLsLsLILsLsabLsLsLsabababLsLsLskeLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLILsLsuIxnxnxnnyLsLsababababababababababababababababababababababababacacacacZWhmacBIacababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsLsLsLsLsXpLsLsLskeLsLsLsTXLsLsLsXFLsLsLsLsLsLsaWLsLsLsLBLsLsLsabababababLsLsLsLsababLsLsLsababababLsLsLsLsLsLsLsLsLsLsabLsLsLsabababababLsLsabLsLsLsabababababababababababababababLsLsLsLsLsuIxnxnxnnyLsLILsabababababababababababababababababababababababacacMkacacacacacacababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLsLsLskeLsLsLsLsababababLsLsLsLsabLsLsLsLILsabababLsLsLsLILsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsababababababababababababababababLsLsLsLsuIxnxnxnnyLsLsLsababababababababababababababababababababacacacacacBIachmDMacacacacababababababababababababababababababababLsLsLsLILsLsLsLsLskeLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababLsLsLsLsImLsLsLILsabLsLsLsLsXpLsLsLsLBLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsababLsLsLsLsababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsuIxnxnxnnykeLsLsabababababababababababababababababababacacacabacacacacacacacBIacababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababLsLsLsLsLsLsababababLsLsLsLskeLsLsLsLsLsImLsLsLsLsababababLsLskeLsLsLsabLskeLsLsababLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsOvOvOvOvOvOvOvOvOvLsLsLsLsLsababababababababababLsLsLILsLsuIxnxnxnnyLsLsLsabababababababababababababababBIacacacacabababacacabababacacacacabababababababababababababababababababababLsLskeLsLsLsLsLILsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababLsLsLsLsLsabababababLsLsLsLsLsLsLsabababababababababababLsLILsLsLsQNQNQNLsLsLsLsLsLsLsLsabababLsLsLsLsababLsLsLsLsLsLsLsOvapcsOpOpOpAzdbOvLskeLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsuIxnxnxnnyLsLsababababababababababababababacacacacacacacababababababababacabababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababLsabababababababababababababLsLsLsLsabLsLsLILsLsLsLsababababLsLsLsLsLILsLsLsLsLsLsLsLILsOvancscscscscsaoOvLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsuIxnxnxnnyLsLsLsabababababababababababababacacacacababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsabababababLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvdbcscscscscsapOvLsLsOvOvOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsababababababababababababababacacabababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsababababababLsLsLsLsabLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsOvOvOvOvXiOvOvOvOvLsLsOvdbcscsRyOvLsLILsLsLsLsLsLsLskeLsLsuIxnxnxnnyLsLsLsababababababababababababacacacababababababababababababababababababababababababababababababababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLskeLsLsLsababababababLsLsLsLsOvFcNhNhNhNhNhFcOvLsLsOvFMcscsjeOvLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsabababababababababacacacababababababababababababababababababababababababababababababababababababLsLsLsLsLILsLsLsLsaWLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababLsLsLsOvNhNhIPIPIPNhNhOvLsLsOvfUcscsapOvLsLsLsLsLsLsaWLsLsLsLsLsuIxnxnxnnyLsLILsLsLsLsabababLsLsababacacababababababababababababababababababababababababababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLIHEabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacabababababababababababababababababLsLsLsLsLsLsLsLILsLsLsabababababLsLsLsOvNhZMmdadvfuANhOvLsLsOvFMcscsjeOvLsLsLsLsLsLsLsLsLsLILsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsabacacabababLsababababababababababababababababababLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacababababababababababababOvOvOvOvOvOvOvOvLsLsLsLsLsLsLsLsLsababLsLsLsLsOvNhNhKGKGKGNhNhOvLsLsOvfUcscsapOvLsLskeLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsabababLsLskeLsLILsLsabqSabLsLsLsLsLsababababababababababababababababLsLsLsLsLsLsLILsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacacababababababababOvdbPDPzFAFAdbOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvFcNhNhNhNhNhFcOvLsLsOvdbcscsjeOvLsLsLsLsLsLsLskeLsLsLsLsuIxnxnxnnyLsLsLsabababLsLsLsLsLsLskeheLBLsLsLskeLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabababacacacacacaeacacabOvcscscscscscsOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsOvOvofOvMuOvofOvOvLsLsOvOvXiOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsababLsLsLsLsLsLsheLsLsaWLsLsLsLILsababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacabacacacacacvhcscscscsOvWLvvcsdbOvyvmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTxnxnxnxnnyLsLskeLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLskeLsLsabLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababacabababababababababababababababababacacacabOvcscscsmFvvFQvvcscsgIuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsLsLsLsLsabababLsLsLsLsLsabababLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacababababababababababacacacacabababOvcscscscsWOIevvcscsOvuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsLsLsLsLsLsLsabababLsLIabababababababLsLsLsLILsLskeLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLspVZlQvLsLsLsababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababacacacacacacababababababTDababacacacacababababOvdbcsOvvvvvFQvvcscsgIuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyLsLsLsLILsLsLsLsLsLsabababababLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsMIQAQvLsLsLsLsLsLILsLsLsQvQvuBQvQvZlLsLsababababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababacacababacacabacacacacacacacacacabababababababOvcscsYPdzdziAvvcscsOvIpwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvxnxnxnxnnyLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsQvQvZlHpQvpVQvuBLsLsLsLsHpqDQvLfQvmJQvqDLfQvababababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababacacacacabababababababababOvcscsOvOvOvOvOvcscsOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLskeLsLsLsLsLsLsQvLfQvqDQvuBLfQvLfQvQvQvZlQvQvQvZluBZlQvQvuBababababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacababababababababababOvcscscscscscscscscsOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsLsLsLsLsaWLskeLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsQvpVQvZlsEMITIQvQvQvMIQvmJZlQvmJnYQvMIQAQvuBQAQvZlabababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacabababababababababababOvdbcscscsdbcscscsdbOvLsOveecscscsOpOvLsOveecscscsOpOvLsOveecscscsOpOvLsOveecscscsOpOvLsLILsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLILILsLsLsLsLsLsLsLsLsLsLsLsLsLsQvLOQvQvMIQvQvQvpVQAQvmJHpsEuBQvcIQvQvuBQvQvsEMIHpQvQvabababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacababababababababababOvOvOvOvOvOvOvOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsLsLsLsLsLsLsLsLsuIxnxnxnnyOvOvOvOvvvvvOvOvvvvvOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLspVQvQvHpQvuBfOQvmJLfQvQvQvuBZlQvQvqDfOQvsEHpQvqDmJQvQvQvsEuBHpLfQvababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacababacacacababababababLsLsLsLsLsLsLsLsLsLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsLsOvOvOvOvOvOvOvuIxnxnxnnyOvNReJeJVJeJyMLqTEfBWBcseLOvLsLsLsLILsLsLsLsLsLsLsaWLsLsLsLsLfLsMIQvsEZlQvpVQvQvQvrCQvHpQvmJMIQvQvmJZlQvZlQvQvZlQvQvpVQvTIQvfOQvQvpVQvZlababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababacababacacacacacacacacacababababababLsLsLsLsLsLsLILsLsLsLsOvcscsOncsarOvLsOvcscsOncsasOvLsOvcscsOncsatOvLsOvcscsOncsauOvLsLsOvFcZhZhNhNhOvuIxnpAxnnyOvcscscscscscscscscscscseLOvLsLsLsLsLsLsLsLsLsLsLsLsLsZlQvQvQvQvQvqDQvQvQvQvsEQvQAQvQvmJQvQvsELfQvHpsEQvQvHpQvmJsEQvHpuBQvHpMIQvmJQvmJHpababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababacacacacacacacacababababababababababababLsLskeLsLsLsLsLsLsLskeLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsLstjNhNhNhNhNhOvuIxnxnxnnyOvnacsdbcscscscscscsdbcseLOvLsLsLsLsLsLsLsLsQvQvQvQvqDQvQvmJpVQvmJQvmJuBfOQvZlQvMIZlQvQvpVQvQvQvqDQvQvQvmJLfMIQvQvLfsELfilmJsEQvLfQvqDQvQAabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababacababacacacabababacacababababababababababababLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsOvLzNhikOvNhOvuIxnxnxnnyOvOvDFOvXiOvOvOvOvXiOvOvOvOvLsLsLsQvLfQvsEQvQvmJHpfOQvLfuBMIQvsEQvHpQvMIQvmJqDfOQvsEuBLfQvQvmJbiQvmJLfuBQvQvQvpVQvqDQvQvHpQvqDQvZlQvHpabMIabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababacacacacababababababacacababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsOvLzNhikOvNhNhuIxnxnxnnyofFcaHaHNhNhRLFcNhNhaHaHFcOvLsQvQAZlQvqDQvLfQvMIuBQvQvQvQvQvQvbiQvQvmJLfQvsEQvHpQvMIHpQvHpqDQvLfQvQvQvmJZlQvmJQvsEQvmJZlQvQAQvpVQvmJababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababacacabacababababababababababababababababababLsLsLILsaWLsLsLsLsLsOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvLsLsOvOvOvOvOvOvOvOvOvLsLsOvOvOvOvOvLsHpOvLzNhikOvFcOvuIpAxnxnnyOvNhNhNhNhNhNhNhNhNhNhNhNhofLsqDQvQvQvmJQvQvQvZlQvZlQvmJQvnYQvQvQvQAQvQvQvQvZlQvQvmJQvmJQvmJfOuBQvpVQvQvQvQvQvpVQvMIZlQvQvMCJpQvuBMIababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLskeLsOvFcNhNhNhZMZMjDFcZMjDZMZMNhNhFcNhOvLsLsOvLbcscscscscsAwOvLsLsOvdbcsYQOvqDXEOvOvOvOvOvtjOvuIxnxnxnnyMuNhNhNhIPIPIPIPIPIPNhNhNhOvQvQvMIsEHpQvQvfOQvQvmJLfQvpVQvQvMIQvmJQvmJZlmJpVQvQAQvpVQvQvZlQvQvHpQvmJQvQAQvZlQAQvKZMCMCqfMCMCMCFgMCpVqDabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsOvmeNhNhNhZMZMjDvfZMjDZMZMNhNhNhNhOvLsLsOvLbcscsdbcscsAwOvLsLsOvIJcsYQOvyvuROvLQOvLQtjdbOvuIxnxnxnnyOvvfNhZMxmxmxmxmxmxmuANhvfofHpqDLfQvuBLfQvZlQvwLQvQvQvQvsEQvfOQvqDQvqDQvHpQvsEuBQvQvsEHpQvpVQvQvQvqDQvQvsEQvQvMCMCJpMCVYVYhCMCMChCVYVYabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsRqLsLsLsLsLsLsOvNhNhjDjDjDjDjDjDjDjDjDjDjDjDadNhOvLsQvOvCtcscsyMcscsUtOvLsLfOveQcscsXiuInyOvXiNDXitjcscsuIxnxnxnnyOvvfNhZMxmxmxmxmxmxmuANhvfofQvmJQvIXQvQvilQvMIQvHpQvmJqDQvQvQvLfmJuBLfQvQvMIQvQvLfQvQvQvmJQvQvndQvLfFgMCMCdQVYMCtcFgVYryMCFgjHyZVYdQjZMCtcFgababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLskeLsLsLsLsLsLILsLsOvNhNhjDjDjDjDjDjDjDjDjDjDjDjDSFNhOvLfqDOvCtcscsAAcscsUtOvuBQvOvYScscsOvuInyOvcscscstjcsOvuIxnxnxnnyMuNhNhNhKGKGKGKGKGKGNhNhNhOvQvqDQvpVQvQvqDmJLfQvfOQvQvpVQvmJQvRTQvQAQvQvmJLfQvmJQvMIZlmJQvZlQvQvMIMCMCryagVYyAjHMCyAgChQMCyZyZyZyZyZMCKZVYabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLILsLsLsLsLsLsLfLsLsOvpmNhNhNhZMZMjDvfZMjDZMZMNhNhNhNhOvMIQAOvUtcscsdbcscsUtOvHpsEOvjXcsaOvvuInyOvnacscscscsOvuIxnxnxnnyOvNhNhNhNhNhNhNhNhNhNhNhNhofZlsEuBMIQvmJQvQvQvsEQvMIQAQvQvQvuBQvQvQvuBQvQvQvQvQvLfQvqDQvQvQvLfQvFgyAMCJpTuMCyZyZyZyZjHMCyZyZyZyZyZyZqfMChCabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababQvLfHpQvLsLsLsLsLsLsLsLsQvmJqDLsOvFcNhNhNhZMZMjDFcZMjDZMZMNhNhFcNhOvHpQvOvUtcscscscscsUtOvMIqDOvdbcslnvvuInyOvdbcscscscsOvuIxnxnxnnyofFcaHaHNhNhmxFcNhNhaHaHFcOvQvQvQvfOQvQvnYQvQvHpZlQvQvQvsEQvTIQvLfsEQvLfZlHpQvTIQvmJQvQALfQvMCJpMCMCyZKZjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHMCababababababababababMCFgqfababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababababQvabababababababababababababababQvfOuBQvLsfOLsHpQvQAMIHpfOQvZlOvOvOvofofOvOvTROvOvTROvOvofofOvOvOvQvXEOvOvvvOvXiOvvvOvOvQAQvOvOvOvOvOvuInyOvOvOvOvOvOvOvuIxnxnxnnyOvOvOvOvXiOvOvOvOvXiOvOvOvOvHppVQvQvpVQvQvQvuBuBQvmJLfQvpVQvQvqDQvmJqDQvsEQvQvQvuBQvHpQvQvMCKZMCjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAUcFgMCabababababjHJpyAUcyZJpababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababababQvQvZlQvabababababababababababQvMIpVQvoQQvoQQvZlrCQvsLsLsLsLsLsLyvmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTxnxnmTmTmTmTmTmTmTxnpAxnxnnyOvtztzcscscscscscscscstztzOvQvQvmJQvMIQvsELfQvfOQvQvQvQvQvQvMIfOQvQvHpQvMIUcFgMCMCJpMCUcMCdQVYyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHtcJpKZyAFgtcyZyZyZyZtcjHKZababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababababababQvHpQvQvsEQvabqDabQvababZlQvHpLfLfQvHpQvQvQvQvoQQvmJQvsLdbUNdTYosLuIxnxnxnxnxnpAxnxnxnxnxnxnpAxnxnxnxnxnxnxnxnxnxnpAxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyOvdbcscscscscscscscscscsdbOvMIQvQvLfQvZlQvQvMIQvQvuBqDmJHpsEQvQvLfQvMCJpVYgCtcMCFgyAMCqfMCVYVYMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAKZabyAKZqfjHababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababababZlQvQvmJLfQvMIQvQvpVHpQvQvMIuBQvQvQvqDsEHpQvmJqDQvQvQvHpsLnacscscsXiuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyOvtztzzDxKdbjfjfdbxKzDtztzOvQvLfsEQvQvmJHpQvmJQvQAQvQvLfilQvMCtcMCKZyAMCdQLKyZyZyZKZMCMCFgyAFgKZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJptcFgyZyZUcababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababababHpQvMIQvqDilQvHpQvfOuBQvQvQAHpqDQvmJfOuBQvQvafQvQvQAQvpVsEuBsLapcscsapsLuIxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnpAxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnnyOvOvOvOvOvOvOvOvOvOvOvOvOvOvQvHpQvQvpVQvQvpVQvZlQvuBMCKZMChCVYUcMCMCMCjHFgyZyZyZyZyZyAjHyZyZjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababuBQvQvLfsEQvQvMIZlQvQvQvBCMIQvQvsEQvpVQvQvQvmJQvQvmJQvQvqUQvQvsLsLsLXisLsLIpwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvIbwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvxnxnxnxnnyMIpVsEQvQvHpQvLfQvQvuBQvQvQvMIQvfOQvQvLfQvQvMCKZMCMCyAMCqfgCjZMCyAKZqfyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababQvQvfOQvMIQvQvmJLfsEQvQvmJQvHpQvLfQvQvQvQvmJLfQvsEQvHpLfqDQvQvLfQvMIHpQvpVQvqDQvZlQvQvLfQvQvMIuOZlQvqDpVQvsEQvQvpVQvqDZlQvQvqDQvHpQvZlQvmJQvfOQvQvsEMIQvfOQvZlMIQvmJpVHpuIxnxnxnnysEQvQvZlmJQAQvZlsEqDHpmJZlQvXEQvQvBCMIQvMCJpVYhQMCyZyZjHMCJpMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZababababaaaa -aaaaababababababababababababababababababababababababababMIZlababababababababQvsEQvHpQvQvQvpVQvuBQvQvpVuBQvZlQvfOQvQvLfQvHpQvMIQvLfQvMIyTQvbCQvyTQvyTQvyTQvyTQvyTQvyTZlQvsEHpQvQvQvQvuOMIQvLfQvmJQvsEQvQvMIfOQvsEMIelQvuBQvLfQvqDsWQvpVQvQvsEQvLfqDQvsEuBuIxnxnxnnyQvqDQAQvqDQvHpQvQvQvQvQvLfQvQvQvyAMCMCjZVYVYVYMCUcyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZababababaaaa -aaaaababababababababababababababababababababababababababQvLfQvHpabababababZlQvQvMIQvqDQvmJQvQvQvHpQAQvQvLfsEQvMIQvmJQvQAqDQvfOQvQvqUuBQvQvQvQvQvQvQvQvQvQvilQvQvQvQvQvuBQvqUQvnYQvQvZlQvuOQvelQvuByvmTmTmTuRpVQvQvQvHpQvmJMIsEHpuBQvQvMCtcQvqDmJuBQAQvZluIxnxnxnnyQvZlQvuBQvmJQvQvmJLfpVMIQvVYVYqDKZMCJpVYhtVYjZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCjHFgyZyZyZyZyZyZyZyZUcyZyZKZqfjHyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZababababaaaa -aaaaababababababababababababababababababababababababababqDHpsEQvpVQvababqDQvQAHpQvpVsEQvuBHpQvmJQvQvMIQvQvqDZlQvQvQvHpQvZlQvQvmJHpZlQvyTQvyTQvyTQvyTQvyTQvyTQvyTQvyTQvQAQvQvQvQvuOuBQvLfQvQvQvQvHpuIAlTGxnnyQvQvmJpVQvKZyAMCtcMCKZZlMCJpMCyAQvHpQvsEHpQvuIxnxnxnnyQvmJQvLfsEMILfQvQvhCVYMCMChQVYyAMCMCyAVYVYVYVYyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZKZjHMCMCyAMChQVYdQjHyZyZjHyZyAyZMCFgJpyAababKZtcFgyZyZyZjHFgtcJpyZyZyZyZyZyZyZyAababababaaaa -aaaaabababababababababababababababababababababababababZlQvMIQvQvQvMIfOQvQvZlQvQvQvQvQvLfQvQvLfQvHpfOQvmJHpQvQvQAQvpVQvQvFgMCJpQvsEQvuBQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvqDmJZlQvJpMCKZQvLfHpMImJQvgcTGOlTGnyLfQvQAQvJpMCVYryMCJpMCyAKZqfMCMCZlfOQvmJMIQAuIxnxnxnnyLfQvHpqDQvKZMCqfMCVYryMCJpMCgCjHFgMCyZyZyZjHyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyAMCtcMCMCyAMCMCMCgCVYVYMCMCtcMCMCKZMCyAabababababababjHqfUcyAKZababKZqfUcyAyZyZyZqfJpababababaaaa -aaaaababababababababababababababababababababababababababQvmJpVQvmJHpQvQvHpQvHpLfQvHpQvQvyFQvqDMIQvQvuBLfQvfOQvqDLfQvMCKZMCqfMCMCKZJpQvyTQvyTQvyTQvyTQvyTQvyTQvbCQvyTQvLfQvMIQvMCMCMCtcMCUcQvqDQvmJuIxnTGxnnyQvZlQvQvUcMCqfMCFgMCyZjHFgyZMCUcMCuBHpqDpVQvuIxnxnxnnyuBQvfOQvVYdQMCFgMCtcMCyAyZyAjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCKZMCMCMCKZQvFgqDMCMCTuhtVYgCMCUcagMCJpMCabababababababababababababababababJpKZtcyAFgabababababaaaa -aaaaabababababababababababababababababababababababababababQvQvLfpVQvsEpVQvmJqDQvmJsEQvpVQvMIsEQvmJZlQvQvQvQvMIuBtcMCJptcFgMCUcyAiXMCUcQvQvHpQvpVQvQvHpQvZlQvfOQvuBQvHpMCMCtcKZMCagVYFgMCVYVYHpZlQvIpwvwvwvsCqDQvMCtcVYMCKZyZyZyAyZyZyZyZyAMCKZqfQvLfQvFguIxnxnxnnyQvsEUcKZVYLKyZyZKZMCjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCjHVYryagMCFgQvmJQvMIfOQvQvyAMCMCMCMCyAMCVYMCLfQvfOababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababfOZlQvQvQvsMQvQvQvQvuBQvfOMIQvsWQvQvqDQvQvmJpVQvsWQvHpMCKZjHyZyZyZyZyZjHtcMCMCKZqfMIQvqUQvMIQvmJqDHpQvLfQvMCFgyAMCMCUcVYVYKZtcMCyAKZJpQvLfQvMImJuBelQvMCFgLKyAyZyZyZyZyZyZyZyZyZyZyZjHKZJpLKUcuIxnxnxnnyKZJpjHMCyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAjHMCJpyAVYVYVYKZQvqDQvLfHpuBQvmJQvLfMCUcMCMIsEfOQvelHpQvababababababababababababababababababababababababababaaaa +aaaaababababababababUCUCUCUCUCUCUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCalrXawrXrXUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCrXbEbJbKrXUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCrXbMbNbOrXUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCrXbTbVbWalUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCbXrXJcrXrXUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaababababababababUCUCUCbYUCUCUCababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCJbPiRtUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPiNhUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhbZJbUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhcacpUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcyPiNhUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsababababababababababababababababababababababababababababababababababababLsLsababLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCakPiRtUCabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsabababababababababababababababababababababababababababababLsababLsLsLsLsLsLILsLsLsLsabababababababababababababababababababLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCakakNhUCabababababababababababababababLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLILsLsLsLsLsLsLsabababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsabLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajajakakUCababababababababababababababLsLsLsBRLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsabababababLsabLsababababLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajajajakUCabababababababababababababLsLskeLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsababababababababababababababababababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsababLsLsLskeLsLsLsLILsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajajakakUCababababababababababababLsLsLsLsLsLsLsaWLsLsLsLsLsababababababLsLsLsLsLILsBRLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajamakakUCababababababababababababLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsLskeLsLsBRLsLsaWLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLILsLsLsBRLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajakakajajajababababababababababababLsLsLsLILsLsLsLsLsLsLsLsLILsLsLsLsLsLILsBRLsLILsLsLsaWLsLsLsLILsLsLsLsabababLsLILsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLILsBRLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLskeLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsBRLsLsLsLsLskeLsLsLsLsLsLsLILsLsBRLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajakakakajajajabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLILsLsLsBRLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsBRLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajakakakakakajajajabababababababababababLsLsLsLsLsLsLsLILsLsLsLsBRLsUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsBRLsLskeLsBRLsLsLsLsabababLsLsBRLsLsLBLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababLsLsLsLsLsLsLsLsLsLsabababababababLsLsLsLsLsLsLsLsLsLsLsLsLsUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaabababababababababajakakamakakakakajabababababababababababLsLsLsBRLsLsBRLsLsLsLsLsLsLsUCKYUFTnUCKYUFTnUCkQcsUCKYUFTnUCKYUFTnUCLsLsLsLsLsLsLsLsabababababababLsLsLsLsLILsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsBRLsabababababababababLsababLsLsLsLsLsLsLsLsUCrXrXDDvzyOvzvzrXrXUCazaHaIaJaKUCwPPiUCNhNhczeGjaeGczNhNhUCLsLsLsLILsBRLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababajajakakakakakajajajajababababababababLsLskeLsLsLsLsLsLsLsLskeLsLsLsUCGVUFWaUCGVUFWaUCeQVZUCvMUFDzUCvMUFDzUCLsLsLILsLILsLsababababababababLsLsLsLsLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsLsLsLsLsLsBRLILsabababababababababababababLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLILsLsUCrXrXnRQxjFQxnRrXrXUCNhNhOMNhNhmtPiqCUCNhEhczltczczmvNhBeUCLsBRLsLsLsLsLsLsLsLsLsBRLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabababababababababajajajajakakajajakakajababababababababLsLsLsLsLsLsLsLsLsLsLsLsLILsLsUCUFUFUFUCUFUFUFUCaqcsUCUFUFUFUCUFUFUFUCLsLsLsLsLsLsababababababababababLsLsLsUCUCUCUCUCLsLsLsLsLsLsLsLsLsBRLsLsLILsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsababababababababababababababLsLsLsLsLsLsLsUCMxrXrXrXrXrXrXrXNvUCaLZMvfuANhUCPiQgUCmBmBPibQPiPiPimBmBUCLsLsLsLsLsLsLsLsLsLILsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaababababababababajajakajajajakakakakakajababababababababLsLsLsLsLILsLBLsLsaWLsLsLsLsLsUCUCXWUCUCUCXWUCUCUCSPUCUCXWUCUCUCXWUCUCLsLsLsLsBRLsababababababababababLsLsLsUCRylgvcUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsBRLsUCrXNrrXPiPiPirXrXrXUCUCUCUCUCUCUCJcPiUCohqBJcrXrXrXPimBwZUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababajajakakakakajakakamakajajabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsUCDrWhvOWhWhWhACWhWhWhWhACWhWhWhWhWhWhUCLsLsLsLsababababababababababababLsLsLsUCcsQZcsOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsLsLsabababababababababababababababababLsBRLsLsababababababababababababababLsLskeLsLsLsLsLsUCNhNhNhPiPiPiPiPiPiJmPiQgPiPibQPiPiqCUCDfmBPirXoSrXPiFrFIUCLsLsLsLsLsLsLsLsLsLsLsLskeLsababababababababababababababababababababababababababababaaaa +aaaaabababababababajajakakakakakakakajajajababababababababababLsLsLsLsBRLsLsLsBRLsLsLsLsLsUCWhWhWhWhWhWhWhWhvOWhWhWhWhvOWhWhWhWhUCLsLsLsabababababababababababababLsLsLsUCcscscsUCLsLsLsLsLsLsLsLskeLsLsLsLsabababababababababababababababababababababLsLsLsLsLsLsLsabababababababababababababLsBRLsLsLsLsLsLsUCNhNhNhPiPiPiPiPiPiJmkpwPPiJcPiPiPiPiUCohIvwPrXrXrXPimBKcUCLsLsBRLsLsLskeLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaababababababajajakakajakamakakakajajajabababababababababLsLsLsLsLsLsLsLsLsLsLIBRLsLsLsUCUCsnUCUCUCUCUCUCUCUCUCUCUCUCUCUCsnUCUCLsBRLsababababababababababababLsLsBRLsUCUCfNUCUCUCUCUCUCLsLsLsLsLsLsLsLsabababababababababababababababababababababababLsLsLsLILsLsabababababababababababababLsLsLsLsLsLILsLsUCNhNhNhPiPiPiNhOMNhUCUCUCaMUCUCUCwPbQUCmBmBetPiLJPiJcmBmBUCLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaababababababajakakakajajakajajajajababababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsUCROWhROLprUCcbLWWKmKmWWbLCcrUnnROWhROUCLsLsLsabababababababababababLskeLsLsLsUCcscsIadbPGcsEnUCLsLsLsLsLsLsLsLsLsabababababababababababababababababababababLsLsLskeLsLsLsLsababababababababababababLsLsLsLsBRLsLsLsUCKGKGKGPiPiPiKGKGKGUCaNaPNhaPaNUCPiPiUCRtJbNhPiPiPiNhBeNhUCLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababajamakakajajajajajababababababababababababLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsUCDrvOWhEdEdEdEdEdEdEdYvEdEdEdEdWhvODjUCLsLsLsLsababababababababababLsLsLsLsLsUCJXcscscsQZcsapUCLsLsBRLsLsLsLsLsababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsababababababababababababLsLILsLsLsaWLsLsUCnXNhNhPiPiPiNhNhtIUCoXNhOMNhNhUCQgqCUCNhNhNhPikpPiNhNhRtUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa +aaaaababababababajajakakakakajajababababababababababababababLsLsaWLsLsLsLskeLsLsLsLsaWLsLsUCWhWhznnnEdYvEdEdEdEdEdEdEdEdnnznWhWhUCLsHELsLsabababababababababababLsLsLsLsUCUbUIQZcscsKQEnUCLsLsLsLsLILsLsLsabababababababababababababababababababababLsLsLBLsLsLsLsLsababababababababababababababLsLsLsLsLsLsLsUCKGKGKGPiPiPiKGKGKGUCNhNhNhNhNhUCPiPiUCUCUCUCcjUCcjUCUCUCUCLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLILsLsababababababababababababababababababababababababaaaa +aaaaababababababajajajakakajajajababababababababababababababLsLsLILsLsLsLsLsLsLsLsLsLsLsLsUCywWhznyCnnnnnnnnnnnnnnnnnnnnyCznWhywUCLsLsLsLsabababababababababababLsLsLsLsUCWRcscscscscsapUCLsLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsLsLILsLsLsababababababababababababababLsLsLsLsLsLsLsUCNhNhNhPiPiQgNhNhNhUCNhvfNhvfNhUCPiJckMPiPiPiwPERPiPiPiUmUCLsLsLsLsLsLsLsLILsBRLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa +aaaaababababababababajakakakakajababababababababababababababLsLsLsLsLsLsBRLsLILsLsLsLsLsLsUCoxWhWhznznznznznznznznznznznznvOWhCpUCLsLsLsLsLsLsababababababababLsLsLsLsLsOvOvOvAOOvOvAOOvUCLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsLsLsLsLsLsLsababababababababababababababLsLsLskeBRLsLsUCKGKGKGPiPiPiKGKGKGUCaQaRNhaRNhUCPiPiPiQgPiJcPiPiPiPiPiQgUCLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsababababababababababababababababababababababababaaaa +aaaaababababababababajUCakakakajabababababababababababababLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsUCMDVGWhWhWhEdEdEdWhWhEdEdEdWhWhWhVGIkUCLsLsLsLsLsLsLsLsabababababLsLsLsLsLsLsvvdbapcsmadbcscsOvLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLILsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsUCnXNhNhPiPiPiNhNhtIUCNhvfNhvfOMUCUCUCUCUCUCUCUCmtUCUCUCUCUCLsLskeLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsababababababababababababababababababababababababaaaa +aaaaabababababababababUCXJamakajababababababababababababLsLsLsBRLsLsLsLsLILsLsLsLILsLskeLsUCbPVkWhvOWhEdRCEdWhvOEdRCEdWhWhWhfmozUCLsLsLILsLsLsLsLsabababababLsLsLsBRLsLsvvxGcscscsahtNQZOvLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababLsLsLsLILsLsUCKGKGKGPiPiPiKGKGKGUCNhaROMaRNhUCJhPWOKNhaSPWaiNhNhmbPWSIUCLsLsLsLsLsBRLsLsLskeLsLsLILsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPiakUCabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsUCbPVGWhWhWhEdEdEdWhWhEdEdEdWhWhWhVGozUCLskeLsLsLsLsBRLsLsabababababLsLsLsLsLsOvxGQZcscsapcscsOvLskeLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsBRLsLsLsLsLsBRBRLsLsLsabababababababababababababLsLsLsLsLsLsUCNhNhOMPiPiPiNhNhNhUCoXLMNhvfNhUCayNhOMNhNhOMNhNhOMNhNhdOUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababUCJbPiNhUCabababababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsUCTbDxWhWhWhvOWhWhWhWhWhWhWhvOWhWhxTRXUCLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsvvxGcsKQcsahtNcsOvLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsabababababababababababababLsLsLsLsLsUCHiNhNhPiPSPiNhNhHiUCNhaRNhaRNhUCayNhaSNhaiNhaiNhNhwFNhdOUCLsLsLsLILsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcpcacyUCabababababababababababababLsLsLILsLILsLsLsLsaWLsLsLsLsBRLsUCUCUCUCUCWhtChcBZWhWhBZtChcWhUCUCUCUCUCLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLskeLsOvxGcscsQZapcscsOvLsLsLsaWLsLsLsLsLsLsLsababababLsabLsLsabLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsBRLsababababababababababababababLsLsLsLsUCUCUCUCJmqKJmUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsLsLsLsLsLsLsLsBRLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcyPiJbUCababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsUCWhWhWhUCUCUCUCWhWhWhUCLsLsLsLsLsLsaWLsLskeLsLsLsLsBRLsLsLsaWLsLsLsLsvvxGcscscsaptNcsOvLsLsLsLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsaTaUaUaUaVLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcyPiRtUCababababababababababababLsLsBRLsLsLsLskeLsLsLsLsLsLsLsLILsLskeLsLsUCRxBPWhUCyvuRUCWhBPRxUCLsLILsLsLsBRLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsvvdbapcscsdbcsKQOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsabababababababababababababababLsLsLskeLsLsuIaXaXaXaYLsLsLsLsLsLsLsLILsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPiNhUCababababababababababababLsLsLsLsLsLBLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsUCUCUCpIUCuIaYUCpIOvUCUCLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvOvOvSPSPOvvvvvOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsuIaXaXaXaYLsLsLILsLskeLsLsLsLsLsLsLsLsLsLsLILsLsBRLsLsLsLsLsBRLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhwPXJUCababababababababababababLsLsaWLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLILsLsaTaUaUFwaXaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaVLsLsLsLsabababababababababababababababLsLsLsLsLsBRuIaXaXaXaYLsLsLsLsBRLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsababababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhJcNhUCabababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsLsabababababababababababababababababLsBRLsLsLsuIaXaXaXaYLsLsLsLsLsLsLsLsHELsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPiRtUCabababababababababababLsLsLskeLsLsLsLsLsLILsLsLsLsLsababLsLsLsLsLsLsLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsLsabababababababababababababababababLsLsLsLsLsuIaXaXbaaYLsLsLsaWLsLsLsLsLsLsLskeLsLsLsBRLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhPiNhUCabababababababababababLsLsLsLsLsLsLsLsLsLsLsBRLsLsabababababLsLsLskeLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsababababababababababababababababababLsLsLsLsLsuIaXaXaXaYLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsababababLsLsLsLILsLsLsLsLsLsBRLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcyPiakUCababababababababababababLsLsLILsLsLsLsLsLsLsLsLsabababababababLsLsLsLsbbbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdxnaXaXaXaYLsLsLsabababababababababababababababababLsLsLsLILsuIaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhbZakUCabababababababababababababLsLsLsLsLsLsLsLsBRLsLsababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLILsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsaWLsaZaXaXaXaYLsLsLsLsabababababababababababababababLsLsLsLsLsLsuIaXaXaXaYLsLsBRLsLsLsLsLsLsLsLsLsLsababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaababababababajajajUCNhakakUCabababababababababababababLsLsLsLsLsaWLsLsLsLsLsLsLsabababLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsBRLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLskeLsLsababababababababababababababLsLsLsLsLsLsLsuIaXaXaXaYLsLsLsLsLsLsLsLBLsLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababajakakUCakakakajabababababababababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsaWLsLsLILsLsLsLILsLsLILsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsabababababababLsLsaZaXaXaXaYLsLsLsLsabababababababababLsababababLsLsLsLskeLsLsuIaXaXaXaYLsLsLsLsLILsLsLsLsLsababababababababababababLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababajajakakakakajajababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsababLsLsLsLsBRLsLsBRLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsHELsLsLsLsLsLsLsLsLsabababababababababababLsaZaXaXaXaYLsLsLsababababababababLsLsLsababLsLsLsLILBLsLsLsLsuIbaaXaXaYLsLILsLsLsLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa +aaaaabababababababajamakakajajajabababababababababababababLsLsabLsabLsLsLsLsLsLsLILsLsLsBRLsLsLsLsLsLsLsLsababababLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsabababababababababLsLsaZaXaXaXaYLsLsLsLsLsababababababLsLsLsabLsLsLsLsLsLsLsLsLsLsuIaXaXaXaYLsLsLsLsLsBRLsLsLsababababababababababababLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababajajakakakajajababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsabLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsBRLsLsLsLsBRLsLsababababababLsLsLsLsLsaZaXaXaXaYLsLILsLsLsLsLsLsababLsLsLsLsLsLsLsLsBRLsLsLsLsaWLsuIaXaXaXaYLsLskeLsLsLsLsLsLsababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsaWLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababababajUCakakajajababababababababababababababababababababLsLsLsLsLsBRLsLILsLskeLsLsLsLsabababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsabababababLsLsLsLsaWLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsLILskeLsLsLsLsLILsLsLsLsuIaXaXaXaYLsLsLsLsLsLsLsLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababababUCXJakakUCababababababababababababababababababababababababLsLsLsLsLsLsLsLsLILsLsLsLsababababLsBRLsLsLsLsLskeLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLILsLsLsLsLsBRLsLsLsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIaXaXaXaYLsLsLsLsLILskeLsLsabababababababababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababUCJbPiakUCabababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLILsLsLsLsLsBRLsLsLsabababababababababababLsLsLsLsLskeLsLsababababababLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaXaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaXaXaXaXaYLsLsLsLsLsLsLsLsqwqwababababababababababababLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPicyUCabababababababababababababababababababababababababababababababLsLskeLsLsLILsLsLsabLsLsLsLsLsLsLsLsLsLsabababababababababababababababLsLsLsLsLsLsabababababababababLsLILsLsLsabababababLsLsBRLsLskeLsLsLsBRLsLsLsLILsLsLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsLILsLsLsLsqwqwXgababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhceRtUCababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsLsababababababababababababababababababLsLsLsLsababababababababababLsLsLsabababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsLsLsLsLsabababqwabababababababababababLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcywPNhUCababababababababababababababababababababababababababababababababLsLsLsLsLsLsLskeLsLsLsLsLsLsLsabababababababababababababababababababababLsababababababababababababababababababababababababLsLsLsLILsLsLsLILsLsLsLsLsLsLsaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYLsLsLsLsLsLsabababqwqwqwababababababababLsLsLsLsvuLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhJcNhUCababababababababababababababRMRMRMRMRMRMRMRMRMabababababababababLsLsLsLsLILsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababLsBRLsLsLsLsLsLsLsaWLsLsLILsaZaXaXaXaXbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbeLsBRLsLsLsabababqwqwqwqwabababababababLsLsLILsLsLsLsLsLsvuLsLsLILsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhPicyUCababababababababababababababRMLsLsLsRMLsLsLsRMRMRMRMRMabababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsabababababqwabababababababLsLsLsLsLsvuLsaELsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCcpbZNhUCababababababababababababRMRMRMLsLILsLsLsLsLsLsLsLsLsRMRMabRMRMRMMrMrMrMrXHMrMrMrMrababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLILsLsLsLsLsLsLsLILsLsLsLsLskeLsLsLsLsLsLsLsLsLskeLsLsLsLsababababqwXgabababababababLsLsLsLsLsLsLsLsLsLsLsLsaFLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCNhPiRtUCababababababababababababRMLsLsLsLsLsLsLsLsLsImLsLsLsLsRMRMRMLsLsLsLsLILsLskeLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLskeLsLsLILsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababqwqwababababababLsLsLsLsLsLsLsaCLBLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababUCRtPiNhUCababababababababababababRMLsLsLskiLsLsXpLsLsLILsLsLsLsLsRMLsLsLsLsImLsLsLsLsLskeLsabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLILsLsLsLsLsLsaZaXaXaXaYLsLsaWLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsaWLsLsLsLsLsLsababLsabababababqwqwabababababLsLsLsLsvuLsLsLsaWaDLsLsLsLsLsvuLsLsLsLsLsabababababababababababUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCUCabaaaa +aaaaabababababababababUCNhPiNhUCUCUCUCUCUCUCUCUCUCUCUCUCUCLsLsLsLsLsLBLsLskeLsLsUsLsLsLsLsLsTXLsLsLsLsLsLsXpkiLsLsababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsLsLsababababLsLsLsababLsLsLsLsLsLsLsLsababababababababababXgqwqwqwababababLsLsLsLsLsLILsLsLsLsLsLsvuLsLILsLsLsLsvuLsLsLsababababababababababUCCACAUCUCUCCACAUCCACAUCUCUCCACAUCabaaaa +aaaaabababababababababUCcyJcNhXJNhNhRtNhNhXJNhNhNhcyNhNhUCLsPhLILsLsLsLILsLsLsLsLsrhLsLsLILsLsLsLsaWLsLsLsLsLsLsLsLsababababababababLsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsabababababababababababababLsLsLsLsLsabababababababababababqwqwabababababLsLsLsvuLsLsLsLsaBLsLsLsLsLsLsLsaALsLsLsLsLsLsLsababababababababababUCCACAUCUCUCCACAUCCACAUCUCUCCACAUCabaaaa +aaaaabababababababababUCNhPitTPiPiPiPiPiwPPiPiPiwPakPiPibYLsPhLsLsImLsLsLshKLsLsLsLsLsLsLsLsLsXpLsLsLsLshKLsLsLsUsLsLsLsababababababLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsaWLsLsLsLsaZaXaXaXaYLsLILsLsabababababababababababababababababLsLsLsababababababababababababqwabababababLsLsLsLsLsvuLskeLsLsvuLsLsLsLsLsLILsLsLskeLsLsLsLsabababababababababUCIAsrUCZpUCIAsrUCIAsrUCZpUCIAsrUCabaaaa +aaaaabababababababababUCXJRtNhNhNhcyNhNhNhJbakXJakakcyNhUCLsPhLsLsLsLsLsLsLsLsLBTXLsLsLsLBLskeLsLsLsLsLsLsLBLsLILsLsLsLsababababababLsLILsLsabababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsaZaXaXaXaYLsLsLsLsabababababababababababababababababababababababababababababababqwqwabababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsvuLsLsLsLsLsLsabababababababababUCPiQgPiPikMoyoyPioyoykMPiPiQgPiUCabaaaa +aaaaabababababababababUCUCUCUCUCUCUCUCUCajakakakakakajUCUCLskeLsXpLsLsLsXpLsLsLsLsLskebALsLsLsLsLsXFLsLskeLsLsLsLBLsLsLsabababababababLskeLsLsabLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsaZaXaXaXaYLsLsLsLsababababababababababababababababababababababababababababababqwXgababababababababLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababUCuwoyCfCfCfQguwnKEYQgCfvZCfoynQUCabaaaa +aaaaababababababababababababababababababajakamakakajajabRMRMLsTXLsLsLBLskeLsLsIQLsLILsLsLsXpLsLsLsLsLsLsbALsLsLsLsXpLsLsLsLsababababababLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababLsLsLILsLsaZaXaXaXaYLsLsLsLsLsababababababababababababababababababababababababababababqwqwqwabababababababababababababababLsLsLsLskeLsababLsLsLsLsLsLsabababababababababababUCKghMUHkyUHMMiKqrnQhMUHUHUHMMKgUCabaaaa +aaaaabababababababababababababababababababajakakajajababRMRMLsLsLsLsLsLsLskiLsLsLsXFLsLsLsLsLsLILsTXLsXpLsLsLsTXLsLsLsLILsLsababababababLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsaZaXaXaXaYLsLsLsLsLsababababababababababababababababababababababababababababqwqwababababababababababababababababababLsLsLsLsabababababababababLsabababababababababUCnGhMUHUHUHMMKguwSshMUHUHUHMMesUCabaaaa +aaaaabababababababababababababababababababajajajajababRMRMLsLsaWLsLsXpLsLsLsLsLsLsLsLsLsImhKLskeLsLsLsLskeLsLsLsLsLsLsLsLsLsMrLsLsLsababLsLsLsLILsLsababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsaZaXaXaXaYLsLsLsLsLsabababababababababababababababababababababababababababababqwqwabababababababababababababababababababLsLsLsabLsLsababababLsLsLsababababababababUCuwhMUHUHUHMMPdpYGShMUHUHUHMMuwUCabaaaa +aaaaababababababababababababababababababababajababababRMLsLsLsLsImLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLBLsLsLsLsLsImLsLsLsXFLsLsLsMrLskeLsLsLsLsLsLsLsLsLsabLsabababLsLsLsabLsabababababababababababababababababababababababababababababababababababXHXHXHXHXHbfbgbgbgbhXHXHXHXHababababababababababababababababababababababababababababababqwqwabababababababababababababababababababLsLsLsLILsLsLsLsLsLsLsLsabababababababababUCKghMUHUHUHMMjziKDahMUHUHUHMMnQUCabaaaa +aaaaabababababababababababababababababababababababababRMRMLsLsLsLsLsLILsLsImkiLsXpLsLBLsLsaWLsLsLsLILsLBLsLsLsLsLsLsLsLsQNQNuaQNQNQNLsLILsLskeLsLsLsLsLsLsLsabLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsabababababababababababababababababababababababababqwabqwqwqwababXgqwababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababUCuwhMnCUHUHMMrLwcrLhMUHUHxAMMKgUCabaaaa +aaaaabababababababababababababababababababababababababRMLsLsLsXpLsLsbALsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsUsLsLsLsLsLsMrLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLsLskeLsLsaZaXaXaXaYLsLsababababababababababababababababababababababababYwqwqwDMqwqwqwqwqwqwababababababababababababababababababababLsabababababLskeLsLsLsLsababababababababUCsRhMUHUHUHMBCfGYCfHcUHUHUHMMKvUCabaaaa +aaaaabababababababababababababababababababababababababRMLsLsUsLsLsLsLsLsLsLsLILsLskeLsbALsLsLskiLsLsXpLsLsLsLsLsLsLsImLsLsLsMrLsLsLsLsLsLsLsLsLsLsLsababLsLsLsLsLsLsLskeLsLIabababababababababababababababababababababababababababababababLsLsLILsLsLsLsaZaXaXaXaYLsLsabababababababababababababababababababababababqwqwXgqwqwqwYNqwqwqwqwababababababababababababababababababababababababababLsLsLsLsaWLsLsabababababababUCvXhMUHUHUHUHUHUHUHUHUHUHUHMMwCUCabaaaa +aaaaabababababababababababababababababababababababababRMLsLsLsLsLBLsLsLsLsXFLsLsUsLsLsLsLsHELskiLskeLsImLsLsLsXpLsLsLsLsLsabababLsLsLsLILsLsabLsLsLsabababLsLsLskeLsLsLsLsLsLsabababababababababababababababababababababababababababababababLsLsLsLILsLsaZaXaXaXaYLsLsababababababababababababababababababababababababqwqwqwXgZWYwqwXgqwababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababUCnKhMUHUHUHUHUHFkUHUHUHUHUHMMuwUCabaaaa +aaaaabababababababababababababababababababababababababRMRMLsLsLsLsLsXpLsLsLskeLsLsLsTXLsLsLsXFLsLsLsLsLsLsaWLsLsLsLBLsLsLsabababababLsLsLsLsababLsLsLsababababLsLsLsLsLsLsLsLsLsLsabLsLsLsabababababLsLsabLsLsLsabababababababababababababababLsLsLsLsLsaZaXaXaXaYLsLILsabababababababababababababababababababababababXgqwYNqwqwqwqwqwqwababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsababababababababUCuwhMUHUHUHUHUHUHUHUHUHUHUHMMKgUCabaaaa +aaaaababababababababababababababababababababababababababRMRMLsLsLsLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLsLsLskeLsLsLsLsababababLsLsLsLsabLsLsLsLILsabababLsLsLsLILsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsababababababababababababababababLsLsLsLsaZaXaXaXaYLsLsLsababababababababababababababababababababqwqwqwqwqwXgqwYwDMqwqwqwqwababababababababababababababababababababLsLsLsLILsLsLsLsLskeLsabababababababababUCnQPiBhrSBhBhBhBhBhBhBhBhBhPiVdUCabaaaa +aaaaabababababababababababababababababababababababababababRMRMRMLsLsLsLsImLsLsLILsRMLsLsLsLsXpLsLsLsLBLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsababLsLsLsLsababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsaZaXaXaXaYkeLsLsabababababababababababababababababababqwqwqwabqwqwqwqwqwqwqwXgqwababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababababUCKguweIBjVdKguwzcKgnKoyPiEtqRnKUCabaaaa +aaaaabababababababababababababababababababababababababababababRMRMRMLsLsLsLsLsLsRMRMRMRMLsLsLsLskeLsLsLsLsLsImLsLsLsLsababababLsLskeLsLsLsabLskeLsLsababLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsLsOvOvOvOvOvOvOvOvOvLsLsLsLsLsababababababababababLsLsLILsLsaZaXaXaXaYLsLsLsabababababababababababababababXgqwqwqwqwabababqwXgabababqwqwqwqwabababababababababababababababababababababLsLskeLsLsLsLsLILsLsababababababababababUCUCUCUCUCUCUCUCUCUCUCQgPiUCUCUCUCabaaaa +aaaaabababababababababababababababababababababababababababababababRMRMLsLsLsLsLsRMababRMRMLsLsLsLsLsLsLsabababababababababababLsLILsLsLsQNQNQNLsLsLsLsLsLsLsLsabababLsLsLsLsababLsLsLsLsLsLsLsOvapcsOpOpOpAzdbOvLskeLsLsLsLsLsLsLsLsLsababababLsLsLsLsLsaZaXaXaXaYLsLsababababababababababababababqwqwqwqwqwXgqwababababababababqwabababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababUCCACAUCPiPiUCCACAUCabaaaa +aaaaababababababababababababababababababababababababababababababababRMRMRMRMRMRMRMabababRMRMRMRMabababLsabababababababababababababLsLsLsLsabLsLsLILsLsLsLsababababLsLsLsLsLILsLsLsLsLsLsLsLILsOvancscscscscsaoOvLsLsLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsaZaXaXaXaYLsLsLsabababababababababababababqwqwqwqwababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababUCCACAUCPiPiUCCACAUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsabababababLsLsLsLsababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvdbcscscscscsapOvLsLsOvOvOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsababababababababababababababqwXgabababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababUCeCNhUCIcIcUCeCNhUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsababababababLsLsLsLsabLsLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsOvOvOvOvXiOvOvOvOvLsLsOvdbcscsapOvLsLILsLsLsLsLsLsLskeLsLsaZaXaXaXaYLsLsLsababababababababababababqwqwqwababababababababababababababababababababababababababababababababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsabababababababababababababababUCNhNhNhQgQgNhNhNhUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLskeLsLsLsababababababLsLsLsLsOvFcNhNhNhNhNhFcOvLsLsOvFMcscsjeOvLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsabababababababababqwqwqwababababababababababababababababababababababababababababababababababababLsLsLsLsLILsLsLsLsaWLsLsLsLsLsLsabababababababababababababababUCnXNhNhPiPiNhNheZUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsabababababababLsLsLsOvNhNhIPIPIPNhNhOvLsLsOvfUcscsapOvLsLsLsLsLsLsaWLsLsLsLsLsaZaXaXaXaYLsLILsLsLsLsabababLsLsababqwqwababababababababababababababababababababababababababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLskeLsLIHEababababababababababababababUCNhOMUCPiPiUCOMNhUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwqwabababababababababababababababababLsLsLsLsLsLsLsLILsLsLsabababababLsLsLsOvNhZMmdadvfuANhOvLsLsOvFMcscsjeOvLsLsLsLsLsLsLsLsLsLILsLsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsabqwababababLsababababababababababababababababababLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsabababababababababababababababUCNhNhNhPiPiNhNhNhUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwqwqwababababababababababababOvOvOvOvOvOvOvOvLsLsLsLsLsLsLsLsLsababLsLsLsLsOvNhNhKGKGKGNhNhOvLsLsOvWRcscsapOvLsLskeLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsabababLsLskeLsLILsLsabqSabLsLsLsLsLsababababababababababababababababLsLsLsLsLsLsLILsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababUCNhNhNhPiPiNhNhNhUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwqwqwqwababababababababOvdbPDPzFAFAdbOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsOvFcNhNhNhNhNhFcOvLsLsOvdbcscsjeOvLsLsLsLsLsLsLskeLsLsLsLsaZaXaXaXaYLsLsLsabababLsLsLsLsLsLskeheLBLsLsLskeLsLsabababababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLBLsLsLsLsLsLsLILsLsLsLsLsababababababababababababababababUCNhOMUCPiPiUCOMNhUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwabababqwqwqwqwqwaeqwqwabOvcscscscscscsOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsOvOvofOvMuOvofOvOvLsLsOvOvXiOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsababLsLsLsLsLsLsheLsLsaWLsLsLsLILsababababababababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsabababababababababababababababababUCNhNhNhPiPiNhNhNhUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwabqwqwqwqwqwvhcscscscsOvWLvvcsdbOvaTaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUxnaXaXaXaYLsLskeLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLskeLsLsabLsLsabababababababababababababababababUCnXNhNhPiPiNhNheZUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababqwabababababababababababababababababqwqwqwabOvcscscsmFvvFQvvcscsgIaZxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnaXaXaXaYLsLsLsLsLsLsLsabababLsLsLsLsLsabababLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababUCNhOMUCPiPiUCOMNhUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwababababababababababqwqwqwqwabababOvcscscscsWOIevvcscsOvaZxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnaXaXaXaYLsLsLsLsLsLsLsLsLsabababLsLIabababababababLsLsLsLILsLskeLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLspVZlQvLsLsLsabababababababababababababababababababababUCPiPiPiPiPiPiPiPiUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwababababababTDababqwqwqwqwababababOvdbcsOvvvvvFQvvcscsgIaZxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnaXaXaXaYLsLsLsLILsLsLsLsLsLsabababababLsLsLsLsLsabababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsMIQAQvLsLsLsLsLsLILsLsLsQvQvuBQvQvZlLsLsabababababababababababababababababababababUCPiPiQgPiPiQgPiPiUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababqwqwababqwqwabqwqwqwqwqwqwqwqwqwabababababababOvcscsYPdzdziAvvcscsOvbbbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdxnaXaXaXaYLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsQvQvZlHpQvpVQvuBLsLsLsLsHpqDQvLfQvmJQvqDLfQvabababababababababababababababababababababUCPiPiUCUCUCUCPiPiUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwababqwqwqwqwabababababababababOvcscsOvOvOvOvOvcscsOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsOvvvOvXiOvOvOvLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLskeLsLsLsLsLsLsQvLfQvqDQvuBLfQvLfQvQvQvZlQvQvQvZluBZlQvQvuBabababababababababababababababababababababUCPiPiUCCACAUCPiPiUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwababababababababababOvcscscscscscscscscsOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsOvdbtNcscsOpOvLsLsLsLsLsaWLskeLsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsQvpVQvZlsEMITIQvQvQvMIQvmJZlQvmJnYQvMIQAQvuBQAQvZlababababababababababababababababababababUCPiPiUCCACAUCPiPiUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwabababababababababababOvdbcscscsdbcscscsdbOvLsOveecscscsOpOvLsOveecscscsOpOvLsOveecscscsOpOvLsOveecscscsOpOvLsLILsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLILILsLsLsLsLsLsLsLsLsLsLsLsLsLsQvLOQvQvMIQvQvQvpVQAQvmJHpsEuBQvcIQvQvuBQvQvsEMIHpQvQvababababababababababababababababababababUCAcPiUCeCNhUCPiycUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwababababababababababOvOvOvOvOvOvOvOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsOvcscsOvOvOvOvLsLsLsLsLsLsLsLsLsaZaXaXaXaYOvOvOvOvvvvvOvOvvvvvOvOvOvOvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLspVQvQvHpQvuBfOQvmJLfQvQvQvuBZlQvQvqDfOQvsEHpQvqDmJQvQvQvsEuBHpLfQvabababababababababababababababababUCQgPiPiPiPiPiPiQgUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwababqwqwqwababababababLsLsLsLsLsLsLsLsLsLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsOvcscsOvAzdbOvLsLsOvOvOvOvOvOvOvaZaXaXaXaYOvNRCOCOVJeJyMLqTEfBWBcseLOvLsLsLsLILsLsLsLsLsLsLsaWLsLsLsLsLfLsMIQvsEZlQvpVQvQvQvrCQvHpQvmJMIQvQvmJZlQvZlQvQvZlQvQvpVQvTIQvfOQvQvpVQvZlabababababababababababababababUCPiPiPiPiPiPiPiPiUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababqwababqwqwqwqwqwqwqwqwqwababababababLsLsLsLsLsLsLILsLsLsLsOvcscsOncsarOvLsOvcscsOncsasOvLsOvcscsOncsatOvLsOvcscsOncsauOvLsLsOvFcZhZhNhNhOvaZaXbjaXaYOvcscscscscscscscscscscseLOvLsLsLsLsLsLsLsLsLsLsLsLsLsZlQvQvQvQvQvqDQvQvQvQvsEQvQAQvQvmJQvQvsELfQvHpsEQvQvHpQvmJsEQvHpuBQvHpMIQvmJQvmJHpabababababababababababababababUCUCUCUCPiPiUCUCUCUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwqwqwqwqwababababababababababababLsLskeLsLsLsLsLsLsLskeLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsOvOvOvOvOvOvOvLsLstjNhNhNhNhNhOvaZaXaXaXaYOvnacsdbcscscscscscsdbcseLOvLsLsLsLsLsLsLsLsQvQvQvQvqDQvQvmJpVQvmJQvmJuBfOQvZlQvMIZlQvQvpVQvQvQvqDQvQvQvmJLfMIQvQvLfsELfilmJsEQvLfQvqDQvQAababababababababababababababUCCACAUCPiPiUCCACAUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababqwababqwqwqwabababqwqwababababababababababababLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsOvLzNhikOvNhOvaZaXaXaXaYOvOvDFOvXiOvOvOvOvXiOvOvOvOvLsLsLsQvLfQvsEQvQvmJHpfOQvLfuBMIQvsEQvHpQvMIQvmJqDfOQvsEuBLfQvQvmJbiQvmJLfuBQvQvQvpVQvqDQvQvHpQvqDQvZlQvHpabMIababababababababababababababUCCACAUCPiPiUCCACAUCabaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababqwqwqwqwababababababqwqwababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsOvLzNhikOvNhNhaZaXaXaXaYofFcNhNhNhNhRLFcNhNhNhNhFcOvLsQvQAZlQvqDQvLfQvMIuBQvQvQvQvQvQvbiQvQvmJLfQvsEQvHpQvMIHpQvHpqDQvLfQvQvQvmJZlQvmJQvsEQvmJZlQvQAQvpVQvmJRMababababababababababababababababUCIAsrUCIcIcUCIAsrUCabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababqwqwabqwababababababababababababababababababLsLsLILsaWLsLsLsLsLsOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvOvLsLsOvOvOvOvOvOvOvOvOvLsLsOvOvOvOvOvLsHpOvLzNhikOvFcOvaZbjaXaXaYOvNhNhNhNhNhNhNhNhNhNhNhNhofLsqDQvQvQvmJQvQvQvZlQvZlQvmJQvnYQvQvQvQAQvQvQvQvZlQvQvmJQvmJQvmJfOuBQvpVQvQvQvQvQvpVQvMIZlQvQvMCJpQvuBMIRMRMabababababababababababababababRMQFljRSQFCwrbQFRSRMabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLskeLsOvFcNhNhNhZMZMjDFcZMjDZMZMNhNhFcNhOvLsLsOvLbcscscscscsAwOvLsLsOvdbcsYQOvqDXEOvOvOvOvOvtjOvaZaXaXaXaYMuNhNhNhIPIPIPIPIPIPNhNhNhOvQvQvMIsEHpQvQvfOQvQvmJLfQvpVQvQvMIQvmJQvmJZlmJpVQvQAQvpVQvQvZlQvQvHpQvmJQvQAQvZlQAQvKZMCMCqfMCMCMCFgMCpVqDRMabababababababababababababababRMRMCwrbvDljCwvDRMRMabaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsLsLsLsOvmeNhNhNhZMZMjDvfZMjDZMZMNhNhNhNhOvLsLsOvLbcscsdbcscsAwOvLsLsOvIJcsYQOvyvuROvLQOvLQtjdbOvaZaXaXaXaYOvvfNhZMxmxmxmxmxmxmuANhvfofHpqDLfQvuBLfQvZlQvwLQvQvQvQvsEQvfOQvqDQvqDQvHpQvsEuBQvQvsEHpQvpVQvQvQvqDQvQvsEQvQvMCMCJpMCVYVYhCMCMChCVYVYRMRMRMRMabababababababababababababRMRMhwCwQFZPRMRMababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLsRqLsLsLsLsLsLsOvNhNhjDjDjDjDjDjDjDjDjDjDjDjDadNhOvLsQvOvCtcscsyMcscsUtOvLsLfOveQcscsXiaZaYOvXiNDXitjcscsaZaXaXaXaYOvvfNhZMxmxmxmxmxmxmuANhvfofQvmJQvIXQvQvilQvMIQvHpQvmJqDQvQvQvLfmJuBLfQvQvMIQvQvLfQvQvQvmJQvQvndQvLfFgMCMCdQVYMCtcFgVYryMCFgjHyZVYdQjZMCtcFgRMababababababababababababababRMRMrbljRMRMabababaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLskeLsLsLsLsLsLILsLsOvNhNhjDjDjDjDjDjDjDjDjDjDjDjDSFNhOvLfqDOvCtcscsAAcscsUtOvuBQvOvYScscsOvaZaYOvcscscstjcsOvaZaXaXaXaYMuNhNhNhKGKGKGKGKGKGNhNhNhOvQvqDQvpVQvQvqDmJLfQvfOQvQvpVQvmJQvRTQvQAQvQvmJLfQvmJQvMIZlmJQvZlQvQvMIMCMCryagVYyAjHMCyAgChQMCyZyZyZyZyZMCKZVYRMRMabababababababababababababababRMRSCwRMababababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsLILsLsLsLsLsLsLfLsLsOvpmNhNhNhZMZMjDvfZMjDZMZMNhNhNhNhOvMIQAOvUtcscsdbcscsUtOvHpsEOvjXcsaOvvaZaYOvnacscscscsOvaZaXaXaXaYOvNhNhNhNhNhNhNhNhNhNhNhNhofZlsEuBMIQvmJQvQvQvsEQvMIQAQvQvQvuBQvQvQvuBQvQvQvQvQvLfQvqDQvQvQvLfQvFgyAMCJpTuMCyZyZyZyZjHMCyZyZyZyZyZyZqfMChCRMababababababababRMRMRMRMRMabababRMCwrbRMababababaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababQvLfHpQvLsLsLsLsLsLsLsLsQvmJqDLsOvFcNhNhNhZMZMjDFcZMjDZMZMNhNhFcNhOvHpQvOvUtcscscscscsUtOvMIqDOvdbcslnvvaZaYOvdbcscscscsOvaZaXaXaXaYofFcNhNhNhNhmxFcNhNhNhNhFcOvQvQvQvfOQvQvnYQvQvHpZlQvQvQvsEQvTIQvLfsEQvLfZlHpQvTIQvmJQvQALfQvMCJpMCMCyZKZjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHMCRMRMRMabababRMRMRMRMMCFgqfRMabababRMljvDRMababababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababababQvabababababababababababababababQvfOuBQvLsfOLsHpQvQAMIHpfOQvZlOvOvOvofofOvOvTROvOvTROvOvofofOvOvOvQvXEOvOvvvOvXiOvvvOvOvQAQvOvOvOvOvOvaZaYOvOvOvOvOvOvOvaZaXaXaXaYOvOvOvOvXiOvOvOvOvXiOvOvOvOvHppVQvQvpVQvQvQvuBuBQvmJLfQvpVQvQvqDQvmJqDQvsEQvQvQvuBQvHpQvQvMCKZMCjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAUcFgMCRMRMRMRMRMjHJpyAUcyZJpRMRMRMabRMQFCwRMababababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababababQvQvZlQvabababababababababababQvMIpVQvoQQvoQQvZlrCQvsLsLsLsLsLsLaTaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUxnxnaUaUaUaUaUaUaUaXbjaXaXaYOvtztzcscscscscscscscstztzOvQvQvmJQvMIQvsELfQvfOQvQvQvQvQvQvMIfOQvQvHpQvMIUcFgMCMCJpMCUcMCdQVYyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHtcJpKZyAFgtcyZyZyZyZtcjHKZRMRMRMvDljRMRMabababaaaa +aaaaabababababababababababababababababababababababababababababababababababababababababababQvHpQvQvsEQvabqDabQvababZlQvHpLfLfQvHpQvQvQvQvoQQvmJQvsLdbUNdTYosLaZaXaXaXaXaXbjaXaXaXaXaXaXbjaXaXaXaXaXaXaXaXaXaXbjaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaYOvdbcscscscscscscscscscsdbOvMIQvQvLfQvZlQvQvMIQvQvuBqDmJHpsEQvQvLfQvMCJpVYgCtcMCFgyAMCqfMCVYVYMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAKZRMyAKZqfjHRMabababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababababZlQvQvmJLfQvMIQvQvpVHpQvQvMIuBQvQvQvqDsEHpQvmJqDQvQvQvHpsLnacscscsXiaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbkbkbkaYOvtztzzDxKdbjfjfdbxKzDtztzOvQvLfsEQvQvmJHpQvmJQvQAQvQvLfilQvMCtcMCKZyAMCdQLKyZyZyZKZMCMCFgyAFgKZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJptcFgyZyZUcRMabababaaaa +aaaaababababababababababababababababababababababababababababababababababababababababHpQvMIQvqDilQvHpQvfOuBQvQvQAHpqDQvmJfOuBQvQvafQvQvQAQvpVsEuBsLapcscsapsLaZaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbjaXaXaXaXaXaXaXaXaXaXaXaXbkbkbkaYOvOvOvOvOvOvOvOvOvOvOvOvOvOvQvHpQvQvpVQvQvpVQvZlQvuBMCKZMChCVYUcMCMCMCjHFgyZyZyZyZyZyAjHyZyZjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpRMabababaaaa +aaaaabababababababababababababababababababababababababababababababababababababababuBQvQvLfsEQvQvMIZlQvQvQvBCMIQvQvsEQvpVQvQvQvmJQvQvmJQvQvqUQvQvsLsLsLXisLsLbbbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdblbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdaXbkbkbkaYMIpVsEQvQvHpQvLfQvQvuBQvQvQvMIQvfOQvQvLfQvQvMCKZMCMCyAMCqfgCjZMCyAKZqfyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZRMabababaaaa +aaaaababababababababababababababababababababababababababababababababababababababQvQvfOQvMIQvQvmJLfsEQvQvmJQvHpQvLfQvQvQvQvmJLfQvsEQvHpLfqDQvQvLfQvMIHpQvpVQvqDQvZlQvQvLfQvQvMIuOZlQvqDpVQvsEQvQvpVQvqDZlQvQvqDQvHpQvZlQvmJQvfOQvQvsEMIQvfOQvZlMIQvmJpVHpaZaXaXaXaYsEQvQvZlmJQAQvZlsEqDHpmJZlQvXEQvQvBCMIQvMCJpVYhQMCyZyZjHMCJpMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZRMabababaaaa +aaaaababababababababababababababababababababababababababMIZlababababababababQvsEQvHpQvQvQvpVQvuBQvQvpVuBQvZlQvfOQvQvLfQvHpQvMIQvLfQvMIyTQvbCQvyTQvyTQvyTQvyTQvyTQvyTZlQvsEHpQvQvQvQvuOMIQvLfQvmJQvsEQvQvMIfOQvsEMIelQvuBQvLfQvqDsWQvpVQvQvsEQvLfqDQvsEuBaZaXaXaXaYQvqDQAQvqDQvHpQvQvQvQvQvLfQvQvQvyAMCMCjZVYVYVYMCUcyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZRMabababaaaa +aaaaababababababababababababababababababababababababababQvLfQvHpabababababZlQvQvMIQvqDQvmJQvQvQvHpQAQvQvLfsEQvMIQvmJQvQAqDQvfOQvQvqUuBQvQvQvQvQvQvQvQvQvQvilQvQvQvQvQvuBQvqUQvnYQvQvZlQvuOQvelQvuBaTmTmTmTaVpVQvQvQvHpQvmJMIsEHpuBQvQvMCtcQvqDmJuBQAQvZlaZaXaXaXaYQvZlQvuBQvmJQvQvmJLfpVMIQvVYVYqDKZMCJpVYhtVYjZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCjHFgyZyZyZyZyZyZyZyZUcyZyZKZqfjHyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZRMabababaaaa +aaaaababababababababababababababababababababababababababqDHpsEQvpVQvababqDQvQAHpQvpVsEQvuBHpQvmJQvQvMIQvQvqDZlQvQvQvHpQvZlQvQvmJHpZlQvyTQvyTQvyTQvyTQvyTQvyTQvyTQvyTQvQAQvQvQvQvuOuBQvLfQvQvQvQvHpaZbmbnaXaYQvQvmJpVQvKZyAMCtcMCKZZlMCJpMCyAQvHpQvsEHpQvaZaXaXaXaYQvmJQvLfsEMILfQvQvhCVYMCMChQVYyAMCMCyAVYVYVYVYyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZKZjHMCMCyAMChQVYdQjHyZyZjHyZyAyZMCFgJpyARMRMKZtcFgyZyZyZjHFgtcJpyZyZyZyZyZyZyZyARMabababaaaa +aaaaabababababababababababababababababababababababababZlQvMIQvQvQvMIfOQvQvZlQvQvQvQvQvLfQvQvLfQvHpfOQvmJHpQvQvQAQvpVQvQvFgMCJpQvsEQvuBQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvQvqDmJZlQvJpMCKZQvLfHpMImJQvbobnbpbnaYLfQvQAQvJpMCVYryMCJpMCyAKZqfMCMCZlfOQvmJMIQAaZaXaXaXaYLfQvHpqDQvKZMCqfMCVYryMCJpMCgCjHFgMCyZyZyZjHyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyAMCtcMCMCyAMCMCMCgCVYVYMCMCtcMCMCKZMCyARMRMRMRMRMRMRMjHqfUcyAKZRMRMKZqfUcyAyZyZyZqfJpRMabababaaaa +aaaaababababababababababababababababababababababababababQvmJpVQvmJHpQvQvHpQvHpLfQvHpQvQvyFQvqDMIQvQvuBLfQvfOQvqDLfQvMCKZMCqfMCMCKZJpQvyTQvyTQvyTQvyTQvyTQvyTQvbCQvyTQvLfQvMIQvMCMCMCtcMCUcQvqDQvmJaZaXbnaXaYQvZlQvQvUcMCqfMCFgMCyZjHFgyZMCUcMCuBHpqDpVQvaZaXaXaXaYuBQvfOQvVYdQMCFgMCtcMCyAyZyAjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCKZMCMCMCKZQvFgqDMCMCTuhtVYgCMCUcagMCJpMCRMRMababababRMRMRMRMRMRMRMRMRMRMRMJpKZtcyAFgRMRMabababaaaa +aaaaabababababababababababababababababababababababababababQvQvLfpVQvsEpVQvmJqDQvmJsEQvpVQvMIsEQvmJZlQvQvQvQvMIuBtcMCJptcFgMCUcyAiXMCUcQvQvHpQvpVQvQvHpQvZlQvfOQvuBQvHpMCMCtcKZMCagVYFgMCVYVYHpZlQvbbbdbdbdbeqDQvMCtcVYMCKZyZyZyAyZyZyZyZyAMCKZqfQvLfQvFgaZaXaXaXaYQvsEUcKZVYLKyZyZKZMCjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCjHVYryagMCFgQvmJQvMIfOQvQvyAMCMCMCMCyAMCVYMCLfQvfORMababababababababababababababRMRMRMRMRMRMabababababaaaa +aaaaabababababababababababababababababababababababababababfOZlQvQvQvsMQvQvQvQvuBQvfOMIQvsWQvQvqDQvQvmJpVQvsWQvHpMCKZjHyZyZyZyZyZjHtcMCMCKZqfMIQvqUQvMIQvmJqDHpQvLfQvMCFgyAMCMCUcVYVYKZtcMCyAKZJpQvLfQvMImJuBelQvMCFgLKyAyZyZyZyZyZyZyZyZyZyZyZjHKZJpLKUcaZaXaXaXaYKZJpjHMCyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAjHMCJpyAVYVYVYKZQvqDQvLfHpuBQvmJQvLfMCUcMCMIsEfOQvelHpQvRMabababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababQvqDsEDifOQvZlQvfOQAQvMIQvQvQvZlQvpVQvQvHpQvQvQvQvJpqfMCyAyZyZyZyZyZyZyZyZMCtcMCJpMCMCqDQvmJQAQvQvqUQvHpMCMCMCMCJpMCMCyAjHyZyZyZMCKZMCMCMCZlQvHpQvKZhCVYMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAyZaggCOEOEOEOEOEqfyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCqfMCMCuBQvmJHpQvfOQvpVQvQvsEQvLfQvQvMCfOQvQvQvQvqDQvMIQvfOabababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababQvfOQvQvQvQvmJqDQvHpQvmJQvnYQvuBilsEQvmJQvQAQvMCUcMCKZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyAMCLfQvQvuBHpQvZlMIVYVYUeMCKZjHyAyZyZyZyZyZyZyZMCagLKyAMCsEQvUcMCVYgCyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZOEOEOEOEOEyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZUcMCMCFgilHpQvQvQvuBQvQvQvuBfOQvQvQvMIfOQvQvMILfHpQvQvmJQvLfQvabababababababababababababababababababababababababaaaa aaaaababababababababababababababababababababababababababMImJQvQvnYQvMIpVQvQvHpQvZlQvQvQvfOQvqDQvQvHpQvMIJpMCyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCMCUcMCMCQvQvmJKZMCVYgCMCJpyZyZyZyZyZyZyZyZyZyZyZUcyZKZJpMCKZMCqfMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZOEOEOEOEOEyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyAyZyZyZyZyZyZyZyZyZyZyZyZyZjHMCtcMCMIfOQvLfQvnYQvLfQvmJQvHpQvmJqDQvQvHpQvmJQvsEQvQvuBQvQvababababababababababababababababababababababababababaaaa @@ -600,64 +712,64 @@ aaaaabababababababababababababababababababababababababababQvQAQvQvfOZlQvHpQvQAQv aaaaababababababababababababababababababababababababababZlQvHpQvpVQvHpQvQvQvQvpVQvmJQvZlQvuBQvZlMCMCtcMCjHyZyZyZyZyZyZyZyZyZyZyZyZjHyZyZyZyZyZyZyZyZyZFgyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZOEOEOEOEOEyZyZyZyZyZMCjHFgyAyZyZyZyZUctcMCjZMCQvHpQvelQvfOQvQvelQvQvfOpVQvQvHpQvsEQvQvfOQvpVQvsEqDQvfOQvqDLfQvQvuBQvQvQvQvfOQvQvmJQvQvqDQvmJQvLfQvQvabababababababababababababababababababababababababaaaa aaaaababababababababababababababababababababababababababMIsEfOQvpVsEuBQvLOQvbiQvQvQvLfQvsEQvQvMCqfUcMCKZyZyZyZyZyZyZyZyZUcyZyZyZJptcjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyAyZyZUcyZyZyZyZyZyZyZyZyZyZyZyZyZOEOEOEOEOEyZyZyZyZtcMCagVYMCMCjHFgyAMCMCQvLfQvHpQvQvQvMIQvmJHpQvQvuBHpQvQvfOQvQvQvQvLfmJMIQvilQvQvQvQvQvQvMIQvmJHpQvpVmJHpQvelQvHpLfQvQAQvQvHpQvuBababababababababababababababababababababababababababaaaa aaaaababababababababababababababababababababababababababHpQvuBQvQvQvfOQvQvQvmJQvfOQvMIQvQvpVJpKZMCMCyAyZyZyZyZyZyZyZJpKZMCtcjHMCUcMCMCKZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCjHqfKZMCyZyZyZyZmDyZyZyZyZyZyZyZyZMCtcVYVYVYMCjHJpMCKZMCyZMCUcyZyZyZyZyZyZyZOEOEOEOEOEyZyZjHFgMCMCVYdQMCUcqfMCZlQvQvQvQvuBQvQvmJLfHpQvHpQvmJZlfOQvQvmJQvQvmJLfQvQvQvQvQvfOQvmJLfHpQvmJQvQvpVQvQvQvQvLfQvsEuBQvQvQvsEQvZlQvQvQvZlabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababQvLfQvmJpVQvmJqDsEpVQvQvZlQvHpQvUcMCKZMCtcMCJpyZyZyZyZyZyZyZjHMCMCMCMCMCqfVYMCtcMCyZyZyZyZyZyZyZyZyZyZyZyZyZMCtcJpMCUcMCKZMCyAMCyZyZyZyZyZyZyZyZyZyZUcjHFgJpMCfOZlQvqfQvuBMCyAMCtcMCjHyZyZyZyZdQjZuIxnxnxnnyKZhQMCyAMCQvQvqDQvMILfQvQvQvmJpVQvmJfOQvLfsEQvfOQvQvqDQvQvelQvZlQAQvqDMIQvHpQvmJqDQvMIpVQvQvQvQvZlfOQvQvmJQvZlQvQvLfQvsEQvMIQvQvQvmJfOQvababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababsEQvqDQvQAQvLfQvQvQvLfQvMCMCyAMCMCMCMCyAMCjHyZyZyZyZyZyZyZyZFgMCUeVYhCMCKZMCJpMCMCFgyZyZyZyZyZyZyZyZyZyZyZjHyAMCMCZltcQvQvfOMCUcVYdQyZyZyZyAMCqfjHFgyAMCQvMCQvMIuBQvQvQvfOQvMIJpVYgCVYJpyZyZyAVYgCuIxnxnxnnyJpFgQvfOQvQvfOQvsEQvQvQvHpMIQvQvQvQvQvQvQvZluBQvQvelQvpVMIilQvQvQvQvZlQvQAQvpVQvQvfOQvQvQvfOQvHpQvqDQvQvilelQvQvmJQvQvqDLfQvmJLfQvMIQvQvababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababQvpVfOHpQvHpQvfOfOtcMCJpqfjHMCgCVYhtMCMCyZyZyZyZyZyZyZyZyZKZyAMCMCVYVYPTQvyAMCqfVYVYyAjHKZJpMCyZyZyZyZyZUcJpQvqDQvuBQvQvLfQvQvMChQVYFgjHKZMCJpQvuBQvQvHpQvQvQvHpfOQvMILfQvHpQvQvVYVYhQMCFgjHMCVYhCuIthXrXrnyHpQviluBQvLfQvQvQvQvZlQvmJfOQvHpQvelQvpVsEQvQvQvpVQvQvsEQvfOQvfOQvmJuBQvQvsEQvfOQvmJQvnYQvQvQvmJuBQvQvLfQvMIQvHpQvfOQvQvQvQvQvQvuBHpababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababQvMIQvqfVYUcsEMCyAKZUcMCyZtcjZLKVYMCJpyZyZyZyZyZyZyZyZyZyZJpUcMChCVYMCelQvLfuBMCMCMChQVYMCqfjHMCyAMCJpMCVYQvQvelQvMImJQvQvZlQvMIQvMCyAMCMIQvQvMIfOLfQvQvmJpVsEQvLfQvmJMIsEQvLffOQvfOMCMCqfMCUcuBuIxnxnxnnyMIQvHpsEpVQvQvQvpVsEQvLfQvHpQvsEQvMIbRQvQvZlQvmJQvLfHpQvuBQvTvQvQvQvQvfOQvMIqDQvmJQvpVQvQvQvZlQvLfQvmJQvQvsEQvQvmJQvmJuBfOQvQAQvsEQvuBabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababZltcgCjZVYJpKZjHFgMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCMCMCMCQvHpQvLfQvZlQvQvHpMCUcMCFgMCMIMCMCqDKZMCZlQvQvpVQvQvQvQvZlQAQvQvfOQvLfQvQvQvQvfOQvQvQvQvuBQvQvuBQvQvQvQvQvQvpVQvQvuBQvHpQvQvMILfQvuIxnxnxnnyQvQvQvMIQvQvmJuBQvQvQvQvsEilZluBQvQvLfQvfOQvQvLfQvQvQvLfQAQvQvpVQvQAQvQvLfQvfOQvZlQvQvQvQvmJQvQvQvHpQvQvfOQvQvLfQvQvQvQvsEQvQvqDQvpVQvabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababMCJpKZyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZUctcMCyAqfMCqDQvQvfOQvQvfOQvLfMCQvuBHpQvpVQvQvQvQvuBQvQvQAHpQvfOsMQvQvQvQvQvMIuBQvQAQvpVQvQvelQvfOQvQvmJMIQvfOQvnYQvQvQvsEQvQvmJQvQvpVQvQvqDuIxnxnxnnyuBmJLfQvHpQvQvQvelQvfOQvpVQvfOQvQvmJQvQvmJpVLfQvfOQvmJHpQvMILfsEQvuBQvmJpVQvsEQvQvQvuBQvQvQvfOQvLsLsLsLsQvMIQvsEpVQvLfQvfOZlQvQvLfQvababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababMCUcFgtcyAJpqfjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZmDyZjHMCMCKZMCMCMCQvelQvuBQvmJZlQvQvHpQvsEQvMIQAQvuBQvfOQvMILfQvQvuBQvQvsELfQvmJHpsEQvZlQvsEQvQvmJQvHpQvpVQvQvfOilQvsEQvQvfOuBQvfOQvQvnYQvQvQvQvMIuIxnxnxnnyQvQvQvsEQvfOQvQvQvQvQvmJQvQvQvQvQvQvpVQvQvQvsEMIQvZlQvQvfOQvQvqDfOQvQvQvQvQvuBQvQAQvQvfOmJMILsaWLskeLILsLsLsQvHpQvfOQvmJQvQvQvmJQvMILfabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababJpyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHKZyZMCJpMCqfMCFgQvLfQvQvQvQvQAQvMIQvmJZlQvuBfOQvilQvQvsEQvQvmJQvQvQvQvmJLfQvQvZlQvQvQvQvQvpVQvLfQvqDQvQvsEQvLfQvQvfOQvQvQvHpQvfOQvQvMIQvQvQvQvmJuBZluIxnxnxnnyMIQvpVQvuBQvQvmJLfQvHpQvqDelQvpVQvfOQvQvQAQvHpQvfOQvsEQvQvsEQvQvQvQvfOQvmJsEQvHpQvLfQvQvLsLILsLsLsLsLsLsLILsLsLsQvQvQvQvQvQAQvQvHpQvababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababMCtcjHMCabqfjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZUcqfMCyAMCVYMCMCQvQvHpQvQvmJLfQvQvQvLfQvQvQvQvQvQvqDZlmJpVQvHpQvQvpVQvelQvQvQvQvQvmJQvfOQvmJQvQvQvQvQvQvLfQvuBQvsELfQvQvQvmJpVQvQvQvQvelLfQvuBQvMIQvQvQvuIxnxnxnnyQvQvQvZlQvsEQvMIQvQAQvQvsEQvQvmJQvZlQvmJQvuBilQvLfuBQvQvpVsEQvmJQvHpQvQvQvilfOMIQvLsLsLsLsababababababLsLsLsLskeLsLsLsZlQvQvHpQvfOabababababababababababababababababababababababababababababaaaa -aaaaabababababababababababJpMCKZyZyZFgyAMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCMCMCFgMCMChQMCyAQvLfQvQAQvQvfOQvsEHpuBQvelQvpVQvsEQvQvQvQvelQvfOQvQvQvLfqDQvfOHpQvQvQvuBQvQvQvnYQvsEZlQvmJQvQvpVQvQvQvQAQvQvQvsELfQvmJHpQvQvmJfOQvLfQvQvuIxnxnxnnyqDLfQvQvLfQvQvQvpVQvQvpVilMIQvQvQvQvMIQvHpQvQvmJfOQvHpQvHpfOQvQvLfsEQvMIfOQvQvQvLsabababababababLsLsababLsLsLILsLsLsLsLsLsLsLsMIababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCtcMCJpQvFgMCQvLfQvsEpVQvqDMIQvZlQvQvQvLfQvQvQvfOQvMILfQvZlQvQvQvQvQAQvLfsEQvpVQvQvpVQvQvQAQvHpQvQvQvQvQvMIQvLfilQvHpQvQvQvZlqDQvMIQvQvQvQvQvsEQvQvQvQvHpuIxnxnxnnyQvQvQvQAQvQvfOQvQvQvmJQvQvfOHpQvnYQvQvLfsEqDQvQvQvQvpVmJQvQvMIQvHpQvpVQvQvZlQvabLsababLsLsLBLsLsLsLILsabababLsababLsLsLsaWLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaababababKZFgtcjHyAUcFgtcyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHMCUcyZyZyZyZMCjHMCMCyAMCQvuBQvLfQvQvQvMIQvQvsEQvLfHpQvQvmJQvQvuBQvmJQvHpQvQvmJQvQvLfQvTIQvuBQvQvQvQvQvfOQvsELfQvQvQvuBQvLfQvHpQAQvQvQvmJQvQvmJMIQAQvQvZlQvuBQAQvfOQvQvQvmJMIMIuIxnxnxnnyQvHpQvilMImJHpQvLfQvuBZlQvQvQvQvQvpVQvQvQvQvLfQvQAQvQvQvLfQvfOuBQvQvmJMIQvLsLsLsLsLsLsLsLILsLsaWLsLskeLsLsabLsLsabababLsLsLsLILsababababababababababababababababababababababababababababababaaaa -aaaaababqfUcyAyZyZyZyZyZqfyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyZyZyZUcVYhQVYagMCJpMCyAMCqfKZMCFgQvelHpQvQvQvfOQvHpQvLfQvilQveluBQvelqDQvQvZlQvQvpVQvQvelQvHpQvQvLfQvmJQvLfQvmJQvQvQvQvQvZlQvmJQvQvQvQvQvsEQvqDQvQAQvuBQvQvQvmJfOsEHpQvQvuBsEbiQvQvqDQvuIxnxnxnnyMIQvQvQvQvQvQveluBQvfOQvQvmJLfQvsEuBQvmJpVQvQvLfQvQvmJZlQvLsQvQvQvLsLsLskeLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa -aaaaababFgyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCqfgChCMCMCVYVYjZVYMCKZMCMCUcMCMCQvQvQvQvQvQvmJuBZlQvmJQvQvfOQvQvLfQvZlQvQvQvLfQvQvmJQvfOQvQvqDQvfOQvuBQvQvfOQvQvuBZlQvmJMIsEQvQvQvQAQvmJpVQvQvQvfOMIQvQvLfQvMIQvQvMIQvQvQvmJQvQvQvfOQvLfQvuIxnxnxnnyuBQvpVQvZlLfQvQvQvQvZlQvpVQvQvfOQvQvQvQvQvQvmJZluBQvQvQvLsLsLsLsLsLsLILsLsLsababLIabababqwacqwacDMacacacLsLsLsabLsLsLsLsLsLsLskeLsLsababababababababababababababababababababababababababababaaaa -aaaaababyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCUcjZVYMCMCUeMCMCyAQvHpMCtcMCQvMIfOQvHoQvLfQvQvQvQvZlQvXEQvuBQvmJQvQvsEQvLfQvQAQvHpQvuBQvsEQvLfQvQvQvsEQvLfQvqDQvQvQvQvQvQvQvQvfOQvQvQvHpQvLfQvQvQvQvsEQvQvfOQvpVQvsEQvLfQvQvQvLfQvQvQvQvQvuIxnxnxnnyQvQvQvQvuBQvfOHpQvmJQvfOQvQvQvQvQvZlQvfOHpMIQvQvLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababacqwacacqwacacacacqwababababLsLsLILsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZtcyZKZJpyAjHMCQvMCtcQvmJMCMCMCFgMCQvMIQvZlQvZlQvQvQvQvHpQvQvpVsELfQvQvQvQvfOQvQvpVQvfOQvQvmJQvZlQvQvpVQvHpQvQvQvmJpVQvMIQvQAQvelQvmJLfQvpVQvqDQvQvsEQvMIQvsEQvQvmJuBQvHpQvQvmJQvQvZlQvQvqDelQvQvsEQvHpQvuBuIxnxnxnnyQvZlQvQvQvHpQvQvQvQvLIMILsLsuBQvLfLsQvQvQvLsLsLsLsLsLskeLsLsLsLsLsLsLsababababababababacqwqwacacqwacacqwacqwababababLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZFgFgMCyAababZlQvmJMIQvHpuBQvQvJpQvLfQvsEQvQvmJQvHpsELfuBQvmJsEQvQvQvQvKEQvQvQvMIQvsEHpQvpVilcpZlQvQvmJsEQvQvuBQvfOQvLfQvmJHpQvMIQvQvqDsEQvQAQvQvmJLfQvQvVhQvuBMIQvQvpVQvQvelQvQvQvQAQvQvfOQvQvQvuBMIQvQvQvmJuIxnxnxnnyQvQvQvQvTIQvQAQvLfLsLsLsLsLsLsLsQvpVLsLsLsLsLsLsLsLILsLsLsLsLsLILsLsLsabababababababqwqwqwXgYwMkqwacBIacacqwabababababLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyAababababababQvpVQvsEQvQvQvKEQvQvQvuBQvqDQvQvQAQvQvQvQvZlQvMIQvHpQvmJQvQvmJMIQvLfuBQvQvsEMIQvLfQAuBQvMIQvQAQvQvHpQvQvQvQvQvfOQvQvZlQvHpQvQvuBQvQvQvQvZlQvQvQvQAHpQvfOQvLfQvQvHpLfQvQvQvQvQvmJfOQvQvLfQvQvMIuIxnxnxnnyqDQvLfQvQvQvQvQvLsLsLILsLsLsLsLsLILskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababacBIqwacacqwacacqwacacababababababLskeLsLsLsLsLILsabababababababababababababababababababababababababababaaaa -aaaaababyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZqfUctcjHababababababuBQvmJqDQvelQvQvQvZlQvfOQvmJLfQvQvQvQvHpelQvQvQvLfQvQvQvQAQvQvQvQvHpQvLfQvQvQvQvQvQvQvQvfOQvQvQvmJMIQvuBQvmJQvQvQvHpQvLsQvfOQvQvfOQvLsLILsLsLfQvQvQvLsLsQvQvfOuBQvQvLILsLsMIQvQvQvLsLsLILsLsLsuIxnxnxnnyQvQvQvQvpVLsLsLsLsLskeLsaWLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsLsLsLsababababababqwacacacacacLjqwYNqwYwacqwabababababLsLsLsLsLBLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababyAyZyZyZyZyZJpyZyZyAtcFgJpKZyAjHabababababababababQvZlQvfOQvpVQvmJQvQvsEMIQvpVQvQvpVQvmJQvQvQvQvmJQvQvMIQvQvqDQvLfelQvQvQvZlQvLfQvmJpVsEZlQvHpQvQvQvQvelQvQvQvQvpVQvLfLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsQvQvLsLsLsLsaWLsLsLsLsLsLsLILsLsLsuIxnxnxnnyQvQvHpQvLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababqwqwqwXghmqwqwacBIqwqwqwacabababababLsLsLILsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababFgyZyZyZyZFgqfjHUcMCabababababababababababababababababQvQvsEQvQvQvLfQvHpQvHpQvQvQvsEQvQvZlpVilqDQvZlQvnYQvQvsEuBQvQvpVQvmJQvsEQvqDQvQvQvQvLsLspVLsLfQvQvQvLfQvHpQvLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLILsuINUNUNUnyLsMIQvLsLsLsLsLsLsLILsLsLsLsLsLsLsLsBRLsLsLsLsLsLskeLsLsLsLsLsLsLILsababababababababacacqwacqwMkqwqwqwacqwqwabababababLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababJpjHtcUcyAKZababababababababababababababababababababQvQAQvHpQvMILfQvQvelQvQvmJQAQvqDQvuBQvQvQAQvQvQvmJQvpVQvQvQvQvfOQvQvQvLfuBQvQvQvLfQvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsabababLsabababLsLsLsLsLsLsLsLsLsLsLsLsLILsLskeLsLsLsLsLILsLsLILsLsLsLsuIxnxnxnnyLsLsLsLskeLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsabababababababababqwqwqwqwXgacqwqwqwababababababLsLsLsLsLsBRLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababQvQvMIQvQAQvQvQvmJQvpVQvQvQvQvLfQvHpmJQvQvQvpVQvQvQvQvQvLfZlQvQvLsLfLsQvQvHpfOQvQvLsLsLILsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsabababababababLsLsBRLsLskeLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsXHXHsuxnxnxnVUXHXHLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLBLsLsLsLsLskeLsLsLsababababababababababababqwqwqwqwabababababababLsLsLsLsLsLsLsLskeLsLsLsLsababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababfOQvQvmJQvQvfOQvQvQvilLfQvpVQvQvMIQvQvQvQvsEQvLfQvuBLsLsQvQvLsLsLILsLsLsLsLsLsLsLILsLsLsLsLsLsababLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsababababababLsLsLsLsLBLsuIxnxnxnnyLsLsLsLsLsaWLsLsababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababLsLILsLsLsaWLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababQvsEQvqDZlQvuBQvLfmJLfQvsEQvQvmJQvQvLfQvpVQvLsLsLsLsLsLsLsLsLsLsLsLsabababababLsLsLsLsLsLILsabababLsLsLsLsLsLsLILsLsabababababababLsLILsLsLsaWLsLsLsLILsLsLsLsLsababababababababLsLILsLsLsLIuIxnxnxnnyLsLsLsLsLsLsLsLsababababababababLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsababababababababababababababababababababLsLsLsLsLsLsLsLsLsBRLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababQvQvuBZlQvQvmJQvQvQvMIQvQvZlQvQvQvQAQvqDQvQvLsLsLsLILsLsLsLsLsLskeLsLsabababababLsLsLsBRLsLsLsabababababLsLsLsLsLsLsLsLsLsababababababababLsLsLsLsLsLBLsLsLsLsLsLsababababababababLsLsLsXpLsLsuIxnxnxnnyLsXpLsLsLsLsLsLsababababababababLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsBRLsLsLsLILsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababQvmJLfQvelQvQvsEQvfOQvLsLsLsLILsLsQvQvQvLsLskeLsLsLsLILsLsLsLsLsLsLsababababababababLsLsLskeLsLsababababLsLsLskeLsLsLILsLsLsababLsababababLsLsLsLsLsLsLsLsLsLILsabababababababababLsLsLsLsLsLsuIxnxnxnnyLsLsLsLILsLsababababababababababLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsLsLsLsLsabababababababababababababababLsLskeLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababQvpVQvQvQvpVQvQvLfQvQvLsLILsLsLsLsLsLsLBLsLsLsLsaWLsLsLsLsLILsLsLILsababababababLsLsLsLILsLsLsLsLsababLsLsLILsLsLsLsLskeLsLsababLsLsLskeLsLsLsLsLsLsLsLskeLsLsLsababababababababLsLsLsLsLskeLsFwXrXrXreILsLsLsLsLsLsababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLskeLsLsLsLsLILsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababQvQvQAQvBRLILsLsBRZlLIkeLsLsLsLsLILsLsLsLILsLILsLsLsLsLsLsLskeLsLsLsLsLsLsLsabLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsLsLILsLsLsLsFwxnxnxneILsLsLskeLsLsLsLsLsLsLsLsababLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLskeLsLsLsLsLsLsababLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababpVQvkeLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLswlxnxnxnnyXpLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXqPsyPwsyfHyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLILsLsLILsabababLsLsLsLskeLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLILsLsLILsLsLsLsLsLsLskeLsLsLsLsLsLILsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLILsLsLsuIxnxnxnnyLsLsLILsLsLskeLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLILsLsLsabLsLsLsLsLILsLsLILsLsLsLsLILsLsLsLsaWLsLsLsLILsLsLsLILsLsLsLsLsaWLskeLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababLsababababababababababLsLsLsLILsLsLsLsLsLsLskeLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsababLsLILsLsLsLsLskeLsLsLsLsLsLILsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsXpLsLILsuIxnxnxnnyLsLsLsLsLsLsLsLsLILsLsLsLILsLskeLsLsLsLsLsLsLsabLsababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsabababLsabLsLsababLsLIabababababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababajababababLILsLsLsLsLsLsLsLsLsLsLsababababLsababababababLsLsLskeLsLsaWLsLsLsLILsLsLsLsLsLILsLsabababpuCqCqCqpuLsLsLsLsLsLskeLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLILsLskeLsLsLsLsLsuIxnxnxnnyLsLsXpLsaWLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsabababababababababababababLsLILsLsLsLskeLsLsLsLILsabababababababababLIabababababababababLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababajajajabababababLsababababababababababababababababajajababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababpupuCqQuCqpupuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsuIxnxnxnnyLsLsLsLsLsLsLsLssLsLsLsLsLLsLsLsLsLsLsababababababababababababababababLsLsaWLsLILsLsababababababababababababababababababababababLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababajakajajababababababababababababajajajajajajajajajajajababababLsLsLsLsLILsLsababLsLsLsLsabababababCqCqCqCqCqCqCqCqCqLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLssLsLsLsLsLLsLsLsPhPhPhPhPhuIxnxnxnnysLsLsLsLsLLsLsLssLcscscssLLsLsLsLsLsLsababababababababababababababababLsabLsLsLsLsLsababababababababababababababababLsabababLsLsLsLsLsLILsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababajakakajajajajababababababababajajakakakakakakakakakajajababababababLsLsabababababababababababLspuCqCqCqCqOwCqCqCqCqpuLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLssLcscscssLLsLsLsLsLILsLsLsuIxnxnxnnysLVZcscssLLsXpLssLcsnmcssLLsLsLsXpLsabababababababababababababababababababLsababLsabababababababababababababLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababajajajajajakakalakajajajajajajajajajajajakakakakakakajajakakakajajabababababababababababababababababLspupuQuCqOwCqCqCqOwCqQupupuLsLsLsLsLsLsLsLsLsLsLsLsLILsXpLsLssLcsnmcscsLsLsLsLsLsLsLsLsuIFsxnxnnycscsnmcssLLsLsLssLVZcscssLLsLsLsLsLsababababababababababLsLsabLsLsLsabababababababababababLsLsLsababababLsLsLILsLsLsLsLsLsLsLsLsLskeLsLsabLsLsabababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababajakakakakakakakakajajakakakakakakakakakakakakakajajajakakakakajabababababababababababLsabLsLsLsLsLsCqCqCqCqCqCqCqCqCqCqCqCqCqLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLssLVZcscssLLsXpLssLsLsLsLsLuIxnxnxnnysLcscscssLLsLsLssLsLcssLsLLsLsLsLsLsabababababababLsLsLsLsLsLsLsLsLsabababababababLsLsLsLsLIDELsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababajakakakakamakakakajajajakakakakakakajajajakakajajajakakakakakajabababababababababLsLsLsLsLsLsLILsLsCqCqCqOwCqCqzWCqCqOwCqCqCqLsLsLsLsLsLskeLsLsLskeLsLsLsLsLsLssLsLsLsLsLLsLsLssLcsVZcssLuIxnxnxnnysLsLsLsLsLLsLsLsLsLsXpLsLsLsaWLsLsababababababLsLsLsLskeLsLsLsLsLILsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsaWLsLsLsLsDELsLsLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajajajajakakakakakakakakakajajakakakakakakakajajakakakakakakakakakakajajababababababhshsLsLsLsLskeLsLsLsLsCqCqCqCqCqCqCqCqCqCqCqCqCqLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskesLcsnmcscsuIxnxnxnnyLsLsLsLsLsLskeLsLILsLsLsLsLsLsLsLsabababababLsLsLsLILsLsLsDELsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsDELsLsLsLILsLsLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababajajakakakakakajakakakakakakakakakakakakamakakakakakamakakakakakakakakakajababababababCqhshsLsLsLILsLskeLsLspupuQuCqOwCqCqCqOwCqQupupuLsLsLsLsLsLsLskeLsLsLsLILsLsaWLsLsLssLsLsLsLsLLsLssLcscscssLuIxnxnxnnysLsLsLsLsLLsLsLssLsLsLsLsLLsLsLsLsLsababLsLsLskeLsLsLsLsaWLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLILsLsLsLsDELsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajakakakakajajajakakakakakakakakakakakajajakakakakakakajakajakakakamakajajajajajababCqCqhshsLsLsLsLsaWLsLsLspuCqCqCqCqOwCqCqCqCqpuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLssLcscscssLLsLssLsLsLsLsLuIxnxnxnnysLcscsVZsLLsLsLssLcscsVZsLLsLskeLsababLsLsLILsLsLseMLsLsLsLsLsLILskeLsdtdtdtdtdtdtdtdtdtdtLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajajakakakajajakakakakakakakakakakajajajajakakakakajajajajajakakakakakakakakakajajCqCqCqCqhshsLskeLsLsLsLsLILsCqCqCqCqCqCqCqCqCqLsLsLsLskeLsLILsLsLsLskeLsLsLsLsLsLsLsLssLcsnmVZsLLsLsLsXpLsLsPhuIxnFsxnnycscsnmcssLLsLsLscscsnmcssLLsLILsLsababLsLsLshKLsLBLsLskeLsDELsLsLsLsdtdtLyGTLyPALyGTLyGTdtdtLsLskeLsLsLsLILsAvAvAvAvAvAvAvAvAvLsLsLsababababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababajakakakakakakakakakajajajakakakakajajakakakakakakajajajajajakakakakakakakakajajCqCqawCqCqhshsLsLsLskeLsLsLsLspupuCqQuCqpupuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLssLcscscssLLsLsLsLsLsLsPhuIxnxnxnnysLcscscssLLskeLssLcscsVZsLLsLsLsLsabababLseMLsLsDELILshKLsLsLseMLsdtdtPAGTGTGTGTGTGTGTGTPAdtdtLsLsLsLsLsLsLsAvCbCbCbCbCbCbCbAvLsLsLsababababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajajakakakakakakakakakakajakakamakakakakakakakakamakakakajajakakakakakakajajajajCqCqCqCqCqCqCqhsLsLsLsLsLsLsLsLsLspuCqCqCqpuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLssLsLcssLsLLsLsPhPhPhPhPhuIxnxnxnnysLsLsLsLsLLsLsLssLsLsLsLsLLsLsLsLsababLsLsLsLsNNLseMLsNNLsnhLBLsdtdtGTGTGTSuGTGTGTGTGTGTGTGTdtdtLsLsLsLsLsLsAvCbOiOiUGOiOiCbAvaWLsLsLsabababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajajakakakamakakakakajajajakakakakakakakakajajakakakakakakakakakakakakakajmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTZamTmTmTmTmTmTmTmTmTmTmTmTmTmTmTxnxnxnxnxnmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTmTdimTJwIVNeJwmTNemTfJIVJwmTmTkhdtGTGTVMGTGTcxOyCyEyGTGTVMGTGTdtdtdtdtdtdtdtAvCbOiPCNkPCOiCbAvLsLsLsLsabababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababajakakakakakakakakajajakajakakakakakakajakakakakakakakakakakakajakakakajxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnXrxnxnxnxnxnxnxnxnFsxnxnxnxnxnxnxnxnXrxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnNUxnnpxnxnxnrDxnShEjxnxnShEjnyIUGTGTVMGTGTGTGTGTGTGTGTVMGTGTGTGTGTPAGTGTIUAvCbUGDkRjDkUGCbAvLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababajajajakajajajakakakakakakakakakakakakajajakakakakakajakakamakajajajakakajxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnXrxnxnxnxnxnxnxnxnxnxnxnxnxnOlxnxnxnXrxnxnxnxnFsxnxnxnxnxnxnxnxnxnxnxnNUxnxnxnQMxnmkDQDQmkxnEixnxnKOdtrtGTdtrtGTnLGgavbcGTpddtGTGTGTGTGTGTGTKcdtAvCbEIKnKnVyEICbAvLILskeLsLsLsLsababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababajajajabajakakakakakakakakajakakakajajakakakakajajajakakakakajakakakakxnxnxnxnzFxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnXrxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnXrxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnxnNUxnnpxnxnxnnpxnQMxnShxnxnrDnyIUGTGTVMGTGTGTGTGTGTGTGTVMGTGTZqGTGTGTGTGTIUAvCbEIMsYgMsEICbAvLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababajajajakakakakakakajajakakakakakakakajajajakakakakakajakakakajwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvAWwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvuCwvwvwvWULvwvwYGbwvwvLvrgwvsCdtGTGTVMGTGTeaRbjRTMGTGTVMGTGTdtdtdtdtdtdtdtAvCbOiOiOiOiOiCbAvLsDELsLILsLsabababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababajajakamakakajajajakakakakakakakakakakakakakakakakakakakajCqCqCqCqCqCqCqCqCqCqhsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsPhLsLsLsLssLsLcssLsLLsPhPhPhLssLsLcssLsLLssLsLcssLsLLsLsLsLsLILsLsLsLsababLsNNeMLsnhLsLseMLskiLsLBkidtdtGTGTGTSuGTGTGTGTGTGTGTGTdtdtLsLsLsLsLsLsAvCbOiJBJBJBOiCbAvLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababajajajakakakajakajakamakakakakakakakajakakakakakakakajajCqCqCqCqCqCqCqCqCqhshsLsLsLskeLsLskeLsLsLsLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLssLVZcscssLLsLskeLsLssLVZcscssLLssLcscscssLLsLskeLsLsLsLsLsababababLsLsLskeLsLBLsLshKLseMLsLsdtdtZqGTGTGTGTGTGTGTGTZqdtdtLsLsLsLILsLsLsAvCbLPLPLPLPLPCbAvLsLsLsaWLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababajakakakakakakakakakakakakakajajajakakakakakakajajCqCqCqCqCqCqCqCqCqhshsLsLsLsLsLsLsLsaWLsLsLILsLsLsLILsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsXpLsLssLcsnmVZsLLsaWLsLsLssLcsnmcssLLssLcsnmcssLLILsLsLsLsabababababababababLBLshKLskiLsLskeLsLsDELsdtdtLyGTLyZqLyGTLyGTdtdtLsLsLskeLsLsLsLsAvCbCbCbCbCbCbCbAvLsLsLsLsLsLsabababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababajajakakakakakajajajakakakakajajajajakakamakajajCqCqawCqCqCqCqCqCqhshsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLssLcscscssLLsLsLsLsLssLcscscssLLssLVZcscssLLsLsababababababababababababLsLsLsLsLsDELsLsLsLsLsLsLsdtdtdtdtdtdtdtdtdtdtLsLsLsLsLsLsLILsLsAvAvAvAvAvAvAvAvAvLsLskeLsLsababababababababababababababababababababababababababaaaa -aaaaababababababababababababababababababababababababababababababababababababababajakakakajajajabajajajajajajajajakakakakajajCqCqCqCqCqCqCqCqCqhshsLsLskeLsLsLsLsLskeLsLsLsLsLskeLsLsLsLsLsabLsLsLILsLsLsLsabLsLsLsLsLsLsLILsLsLsLsLsLsLssLsLsLsLsLLsLsLsababsLsLsLsLsLLssLsLsLsLsLabababababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLILsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababQvLfQvmJpVQvmJqDsEpVQvQvZlQvHpQvUcMCKZMCtcMCJpyZyZyZyZyZyZyZjHMCMCMCMCMCqfVYMCtcMCyZyZyZyZyZyZyZyZyZyZyZyZyZMCtcJpMCUcMCKZMCyAMCyZyZyZyZyZyZyZyZyZyZUcjHFgJpMCfOZlQvqfQvuBMCyAMCtcMCjHyZyZyZyZdQjZaZaXaXaXaYKZhQMCyAMCQvQvqDQvMILfQvQvQvmJpVQvmJfOQvLfsEQvfOQvQvqDQvQvelQvZlQAQvqDMIQvHpQvmJqDQvMIpVQvQvQvQvZlfOQvQvmJQvZlQvQvLfQvsEQvMIQvQvQvmJfOQvababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababsEQvqDQvQAQvLfQvQvQvLfQvMCMCyAMCMCMCMCyAMCjHyZyZyZyZyZyZyZyZFgMCUeVYhCMCKZMCJpMCMCFgyZyZyZyZyZyZyZyZyZyZyZjHyAMCMCZltcQvQvfOMCUcVYdQyZyZyZyAMCqfjHFgyAMCQvMCQvMIuBQvQvQvfOQvMIJpVYgCVYJpyZyZyAVYgCaZaXaXaXaYJpFgQvfOQvQvfOQvsEQvQvQvHpMIQvQvQvQvQvQvQvZluBQvQvelQvpVMIilQvQvQvQvZlQvQAQvpVQvQvfOQvQvQvfOQvHpQvqDQvQvilelQvQvmJQvQvqDLfQvmJLfQvMIQvQvababababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababRMQvpVfOHpQvHpQvfOfOtcMCJpqfjHMCgCVYhtMCMCyZyZyZyZyZyZyZyZyZKZyAMCMCVYVYPTQvyAMCqfVYVYyAjHKZJpMCyZyZyZyZyZUcJpQvqDQvuBQvQvLfQvQvMChQVYFgjHKZMCJpQvuBQvQvHpQvQvQvHpfOQvMILfQvHpQvQvVYVYhQMCFgjHMCVYhCaZbqbrbraYHpQviluBQvLfQvQvQvQvZlQvmJfOQvHpQvelQvpVsEQvQvQvpVQvQvsEQvfOQvfOQvmJuBQvQvsEQvfOQvmJQvnYQvQvQvmJuBQvQvLfQvMIQvHpQvfOQvQvQvQvQvQvuBHpababababababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababRMRMQvMIQvqfVYUcsEMCyAKZUcMCyZtcjZLKVYMCJpyZyZyZyZyZyZyZyZyZyZJpUcMChCVYMCelQvLfuBMCMCMChQVYMCqfjHMCyAMCJpMCVYQvQvelQvMImJQvQvZlQvMIQvMCyAMCMIQvQvMIfOLfQvQvmJpVsEQvLfQvmJMIsEQvLffOQvfOMCMCqfMCUcuBaZaXaXaXaYMIQvHpsEpVQvQvQvpVsEQvLfQvHpQvsEQvMIbRQvQvZlQvmJQvLfHpQvuBQvTvQvQvQvQvfOQvMIqDQvmJQvpVQvQvQvZlQvLfQvmJQvQvsEQvQvmJQvmJuBfOQvQAQvsEQvuBabababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababRMZltcgCjZVYJpKZjHFgMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCMCMCMCQvHpQvLfQvZlQvQvHpMCUcMCFgMCMIMCMCqDKZMCZlQvQvpVQvQvQvQvZlQAQvQvfOQvLfQvQvQvQvfOQvQvQvQvuBQvQvuBQvQvQvQvQvQvpVQvQvuBQvHpQvQvMILfQvaZaXaXaXaYQvQvQvMIQvQvmJuBQvQvQvQvsEilZluBQvQvLfQvfOQvQvLfQvQvQvLfQAQvQvpVQvQAQvQvLfQvfOQvZlQvQvQvQvmJQvQvQvHpQvQvfOQvQvLfQvQvQvQvsEQvQvqDQvpVQvabababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababRMRMRMRMRMRMRMMCJpKZyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZUctcMCyAqfMCqDQvQvfOQvQvfOQvLfMCQvuBHpQvpVQvQvQvQvuBQvQvQAHpQvfOsMQvQvQvQvQvMIuBQvQAQvpVQvQvelQvfOQvQvmJMIQvfOQvnYQvQvQvsEQvQvmJQvQvpVQvQvqDaZaXaXaXaYuBmJLfQvHpQvQvQvelQvfOQvpVQvfOQvQvmJQvQvmJpVLfQvfOQvmJHpQvMILfsEQvuBQvmJpVQvsEQvQvQvuBQvQvQvfOQvLsLsLsLsQvMIQvsEpVQvLfQvfOZlQvQvLfQvababababababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababRMRMMCUcFgtcyAJpqfjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZmDyZjHMCMCKZMCMCMCQvelQvuBQvmJZlQvQvHpQvsEQvMIQAQvuBQvfOQvMILfQvQvuBQvQvsELfQvmJHpsEQvZlQvsEQvQvmJQvHpQvpVQvQvfOilQvsEQvQvfOuBQvfOQvQvnYQvQvQvQvMIaZaXaXaXaYQvQvQvsEQvfOQvQvQvQvQvmJQvQvQvQvQvQvpVQvQvQvsEMIQvZlQvQvfOQvQvqDfOQvQvQvQvQvuBQvQAQvQvfOmJMILsaWLskeLILsLsLsQvHpQvfOQvmJQvQvQvmJQvMILfabababababababababababababababababababababababababababaaaa +aaaaababababababababababababRMRMRMRMRMRMRMJpyAyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHKZyZMCJpMCqfMCFgQvLfQvQvQvQvQAQvMIQvmJZlQvuBfOQvilQvQvsEQvQvmJQvQvQvQvmJLfQvQvZlQvQvQvQvQvpVQvLfQvqDQvQvsEQvLfQvQvfOQvQvQvHpQvfOQvQvMIQvQvQvQvmJuBZlaZaXaXaXaYMIQvpVQvuBQvQvmJLfQvHpQvqDelQvpVQvfOQvQvQAQvHpQvfOQvsEQvQvsEQvQvQvQvfOQvmJsEQvHpQvLfQvQvLsLILsLsLsLsLsLsLILsLsLsQvQvQvQvQvQAQvQvHpQvababababababababababababababababababababababababababababaaaa +aaaaababababababababababRMRMRMMCtcjHMCRMqfjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZUcqfMCyAMCVYMCMCQvQvHpQvQvmJLfQvQvQvLfQvQvQvQvQvQvqDZlmJpVQvHpQvQvpVQvelQvQvQvQvQvmJQvfOQvmJQvQvQvQvQvQvLfQvuBQvsELfQvQvQvmJpVQvQvQvQvelLfQvuBQvMIQvQvQvaZaXaXaXaYQvQvQvZlQvsEQvMIQvQAQvQvsEQvQvmJQvZlQvmJQvuBilQvLfuBQvQvpVsEQvmJQvHpQvQvQvilfOMIQvLsLsLsLsababababababLsLsLsLskeLsLsLsZlQvQvHpQvfOabababababababababababababababababababababababababababababaaaa +aaaaababababababababababRMJpMCKZyZyZFgyAMCyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCMCMCFgMCMChQMCyAQvLfQvQAQvQvfOQvsEHpuBQvelQvpVQvsEQvQvQvQvelQvfOQvQvQvLfqDQvfOHpQvQvQvuBQvQvQvnYQvsEZlQvmJQvQvpVQvQvQvQAQvQvQvsELfQvmJHpQvQvmJfOQvLfQvQvaZaXaXaXaYqDLfQvQvLfQvQvQvpVQvQvpVilMIQvQvQvQvMIQvHpQvQvmJfOQvHpQvHpfOQvQvLfsEQvMIfOQvQvQvLsabababababababLsLsababLsLsLILsLsLsLsLsLsLsLsMIababababababababababababababababababababababababababababababaaaa +aaaaabababRMRMRMRMRMRMRMRMjHyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCtcMCJpQvFgMCQvLfQvsEpVQvqDMIQvZlQvQvQvLfQvQvQvfOQvMILfQvZlQvQvQvQvQAQvLfsEQvpVQvQvpVQvQvQAQvHpQvQvQvQvQvMIQvLfilQvHpQvQvQvZlqDQvMIQvQvQvQvQvsEQvQvQvQvHpaZaXaXaXaYQvQvQvQAQvQvfOQvQvQvmJQvQvfOHpQvnYQvQvLfsEqDQvQvQvQvpVmJQvQvMIQvHpQvpVQvQvZlQvabLsababLsLsLBLsLsLsLILsabababLsababLsLsLsaWLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaabRMRMRMKZFgtcjHyAUcFgtcyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHMCUcyZyZyZyZMCjHMCMCyAMCQvuBQvLfQvQvQvMIQvQvsEQvLfHpQvQvmJQvQvuBQvmJQvHpQvQvmJQvQvLfQvTIQvuBQvQvQvQvQvfOQvsELfQvQvQvuBQvLfQvHpQAQvQvQvmJQvQvmJMIQAQvQvZlQvuBQAQvfOQvQvQvmJMIMIaZaXaXaXaYQvHpQvilMImJHpQvLfQvuBZlQvQvQvQvQvpVQvQvQvQvLfQvQAQvQvQvLfQvfOuBQvQvmJMIQvLsLsLsLsLsLsLsLILsLsaWLsLskeLsLsabLsLsabababLsLsLsLILsababababababababababababababababababababababababababababababaaaa +aaaaabRMqfUcyAyZyZyZyZyZqfyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZjHyZyZyZUcVYhQVYagMCJpMCyAMCqfKZMCFgQvelHpQvQvQvfOQvHpQvLfQvilQveluBQvelqDQvQvZlQvQvpVQvQvelQvHpQvQvLfQvmJQvLfQvmJQvQvQvQvQvZlQvmJQvQvQvQvQvsEQvqDQvQAQvuBQvQvQvmJfOsEHpQvQvuBsEbiQvQvqDQvaZaXaXaXaYMIQvQvQvQvQvQveluBQvfOQvQvmJLfQvsEuBQvmJpVQvQvLfQvQvmJZlQvLsQvQvQvLsLsLskeLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsabababababababababababababababababababababababababababababaaaa +aaaaabRMFgyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZMCqfgChCMCMCVYVYjZVYMCKZMCMCUcMCMCQvQvQvQvQvQvmJuBZlQvmJQvQvfOQvQvLfQvZlQvQvQvLfQvQvmJQvfOQvQvqDQvfOQvuBQvQvfOQvQvuBZlQvmJMIsEQvQvQvQAQvmJpVQvQvQvfOMIQvQvLfQvMIQvQvMIQvQvQvmJQvQvQvfOQvLfQvaZaXaXaXaYuBQvpVQvZlLfQvQvQvQvZlQvpVQvQvfOQvQvQvQvQvQvmJZluBQvQvQvLsLsLsLsLsLsLILsLsLsababLIabababqwqwqwqwDMqwqwqwLsLsLsabLsLsLsLsLsLsLskeLsLsababababababababababababababababababababababababababababaaaa +aaaaabRMyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZJpMCUcjZVYMCMCUeMCMCyAQvHpMCtcMCQvMIfOQvHoQvLfQvQvQvQvZlQvXEQvuBQvmJQvQvsEQvLfQvQAQvHpQvuBQvsEQvLfQvQvQvsEQvLfQvqDQvQvQvQvQvQvQvQvfOQvQvQvHpQvLfQvQvQvQvsEQvQvfOQvpVQvsEQvLfQvQvQvLfQvQvQvQvQvaZaXaXaXaYQvQvQvQvuBQvfOHpQvmJQvfOQvQvQvQvQvZlQvfOHpMIQvQvLsLsLsLsLsLsLsLsLsBRLsLsLsabababababababqwqwqwqwqwqwqwqwqwqwababababLsLsLILsBRLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabRMyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZtcyZKZJpyAjHMCQvMCtcQvmJMCMCMCFgMCQvMIQvZlQvZlQvQvQvQvHpQvQvpVsELfQvQvQvQvfOQvQvpVQvfOQvQvmJQvZlQvQvpVQvHpQvQvQvmJpVQvMIQvQAQvelQvmJLfQvpVQvqDQvQvsEQvMIQvsEQvQvmJuBQvHpQvQvmJQvQvZlQvQvqDelQvQvsEQvHpQvuBaZaXaXaXaYQvZlQvQvQvHpQvQvQvQvLIMILsLsuBQvLfLsQvQvQvLsLsLsLsLsLskeLsLsLsLsLsLsLsababababababababqwqwqwqwqwqwqwqwqwqwqwababababLsLsLsLsLsLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabRMyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZFgFgMCyARMRMZlQvmJMIQvHpuBQvQvJpQvLfQvsEQvQvmJQvHpsELfuBQvmJsEQvQvQvQvKEQvQvQvMIQvsEHpQvpVilQvZlQvQvmJsEQvQvuBQvfOQvLfQvmJHpQvMIQvQvqDsEQvQAQvQvmJLfQvQvVhQvuBMIQvQvpVQvQvelQvQvQvQAQvQvfOQvQvQvuBMIQvQvQvmJaZaXaXaXaYQvQvQvQvTIQvQAQvLfLsLsLsLsLsLsLsQvpVLsLsLsLsLsLsLsLILsLsLsLsLsLILsLsLsabababababababqwqwqwXgYwYNqwqwXgqwqwqwabababababLsLsLsLsBRLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabRMyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZyARMRMRMRMRMRMQvpVQvsEQvQvQvKEQvQvQvuBQvqDQvQvQAQvQvQvQvZlQvMIQvHpQvmJQvQvmJMIQvLfuBQvQvsEMIQvLfQAuBQvMIQvQAQvQvHpQvQvQvQvQvfOQvQvZlQvHpQvQvuBQvQvQvQvZlQvQvQvQAHpQvfOQvLfQvQvHpLfQvQvQvQvQvmJfOQvQvLfQvQvMIaZaXaXaXaYqDQvLfQvQvQvQvQvLsLsLILsLsLsLsLsLILskeLsLsLsLsBRLsLsLsLsLsBRLsLsLsLsLsabababababababqwXgqwqwqwqwqwqwqwqwqwababababababLskeLsLsLsLsLILsabababababababababababababababababababababababababababaaaa +aaaaabRMyZyZyZyZyZyZyZyZyZyZyZyZyZyZyZqfUctcjHRMababababRMuBQvmJqDQvelQvQvQvZlQvfOQvmJLfQvQvQvQvHpelQvQvQvLfQvQvQvQAQvQvQvQvHpQvLfQvQvQvQvQvQvQvQvfOQvQvQvmJMIQvuBQvmJQvQvQvHpQvLsQvfOQvQvfOQvLsLILsLsLfQvQvQvBRLsQvQvfOuBQvQvLILsLsMIQvQvQvLsLsLILsLsLsaZaXaXaXaYQvQvQvQvpVLsLsLsLsLskeLsaWLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsLsLsLsababababababqwqwqwqwqwqwZWqwYNqwYwqwqwabababababLsLsLsLsLBLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabRMyAyZyZyZyZyZJpyZyZyAtcFgJpKZyAjHRMRMRMRMababababRMQvZlQvfOQvpVQvmJQvQvsEMIQvpVQvQvpVQvmJQvQvQvQvmJQvQvMIQvQvqDQvLfelQvQvQvZlQvLfQvmJpVsEZlQvHpQvQvQvQvelQvQvQvQvpVQvLfLsLILsLsLsBRLsLsBRLsLsLsLsLsLsLsLsLILsLsQvQvLsLsLsLsaWLsLsLsLsLsLsLILsLsLsaZaXaXaXaYQvQvHpQvLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsabababababababqwqwqwXgYwqwqwqwXgqwqwqwqwabababababLsLsLILsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabRMFgyZyZyZyZFgqfjHUcMCRMRMRMRMRMRMRMababababababababababQvQvsEQvQvQvLfQvHpQvHpQvQvQvsEQvQvZlpVilqDQvZlQvnYQvQvsEuBQvQvpVQvmJQvsEQvqDQvQvQvQvLsLspVLsLfQvQvQvLfQvHpQvLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsLsLILsaZbgbgbgaYLsMIQvLsLsLsLsLsLsLILsLsLsLsLsLsLsLsBRLsLsLsLsLsLskeLsLsLsLsLsLsLILsababababababababqwqwqwqwqwYNqwqwqwqwqwqwabababababLsBRLsLsLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabRMJpjHtcUcyAKZlQRMRMRMRMabababababababababababababababQvQAQvHpQvMILfQvQvelQvQvmJQAQvqDQvuBQvQvQAQvQvQvmJQvpVQvQvQvQvfOQvQvQvLfuBQvQvQvLfQvLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLsabababLsabababLsLsLsLsLsLsLsLsLsLsLsLsLILsLskeLsLsLsLsLILsLsLILsLsLsLsaZaXaXaXaYLsLsLsLskeLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsabababababababababqwqwqwqwXgqwqwqwqwababababababLsLsLsLsLsBRLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabRMRMRMRMRMbsbtbuRMababababababababababababababababababQvQvMIQvQAQvQvQvmJQvpVQvQvQvQvLfQvHpmJQvQvQvpVQvQvQvQvQvLfZlQvQvLsLfLsQvQvHpfOQvQvLsLsLILsLsLsLsLsLILsLsaWLsLsLsLsLsLsLsabababababababLsLsBRLsLskeLsLsLsLsLsLsLsLsLsabababLsLsLsLsLsLsLsXHXHbfaXaXaXbhXHXHLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLBLsLsLsLsLskeLsLsLsababababababababababababqwqwqwqwabababababababLsLsLsLsLsLsLsLskeLsBRLsLsababababababababababababababababababababababababaaaa +aaaaabababababRMWCacacRMababababababababababababababababababfOQvQvmJQvQvfOQvQvQvilLfQvpVQvQvMIQvQvQvQvsEQvLfQvuBLsLsQvQvLsLsLIBRLsLsLsLsLsLsLILsLsLsLsLsLsababLsLsLsLsLsLsLsLsLsabababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsababababababLsLsLsLsLBLsaZaXaXaXaYLsLsLsLsLsaWLsLsababababababLsLsLsLsLILsLsLsLsLsLsLsLsLsBRLsLsLsLsLsabababababababababababababababababababababababLsLILsLsLsaWLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababRMRMacRMRMababababababababababababababababababQvsEQvqDZlQvuBQvLfmJLfQvsEQvQvmJQvQvLfQvpVQvLsLsLsLsBRLsLsBRLsLsLsLsabababababLsLsLsLsLsLILsabababLsLsLsBRLsLsLILsLsabababababababLsLILsLsLsaWLsLsLsLILsLsLsLsLsababababababababLsLILsLsLsLIaZaXaXaXaYLsLsLsLsLsLsLsLsababababababababLsLsLsLsLsLsBRLsLsLsLILsLsLsLsLsBRLsLsLsababababababababababababababababababababLsLsLsLsLsLsLsLsLsBRLsLsababababababababababababababababababababababababababaaaa +aaaaabababababbvbvbwbvbvabababababababababababababababababQvQvuBZlQvQvmJQvQvQvMIQvQvZlQvQvQvQAQvqDQvQvLsLsLsLILsLsLsLsLsLskeLsLsabababababLsLsLsBRLsLsLsabababababLsLsLsLsLsLsLsLsLsababababababababLsLsLsLsLsLBLsLsLsLsLsLsababababababababLsLsLsXpLsLsaZaXaXaXaYLsXpLsLsLsLsLsLsababababababababLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabababababababababababababababababababLsLsLsLsBRLsLsLsLILsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababbvPRbxbxbybybybybybyababababababababababababQvmJLfQvelQvQvsEQvfOQvLsLsLsLILsLsQvQvQvLsBRkeLsLsLsLILsLsLsLsLsLsLsababababababababLsLsLskeLsLsababababLsLsLskeLsLsLILsLsLsababLsababababLsLsLsLsLsLsLsLsLsLILsabababababababababLsLsLsLsLsLsaZaXaXaXaYLsLsLsLILsLsababababababababababLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsBRLsLsLsabababababababababababababababLsLskeLsLsLsLsBRLsLsLsLsBRLsLsabababababababababababababababababababababababababaaaa +aaaaabababababbybxZkbxbxbxPRbxZkbyababababababababababababQvpVQvQvQvpVQvQvLfQvQvLsLIBRLsLsBRLsLsLBLsLsLsLsaWLsLsLsLsLILsLsLILsababababababLsLsLsLILsLsLsLsLsababLsLsLILsLsLsLsLskeLsLsababLsLsLskeLsLsLsLsLsLsLsLskeLsLsLsababababababababLsLsLsLsLskeLsbzbrbrbrbBLsLsLsLsLsLsababababababababLsLsLsLsLsLsLsLsBRLsLsLsLsLskeLsLsLsLsLILsLsLsLsLsLsLsLsabababababababababababLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababbybxPRbxPRbxbxbxPRbyabababababababababababQvQvQAQvBRLILsLsBRZlLIkeLsLsLsLsLILsLsLsLILsLILsLsLsLsLsLsLskeLsLsLsLsLsLsLsabLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababLsLsLILsLsLsLsbzaXaXaXbBLsLsLskeLsLsLsLsLsLsLsLsababLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsBRLsLsLsaWLsLsLskeLsLsLsLsLsLsababLsLsLsLsLsLsLsLsLILsLsLsLsBRLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa +aaaaabababababbybybybybybybybxbxbyababababababababababababpVQvkeLsLsLILsLsLsLsLsLsBRLsLsLsLsLsLsLsLsBRLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsbDaXaXaXaYXpLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababababbybxPRbyababababababababababababyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXbFbGbHbGbIyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXyXabababababababababababababababababababababababababababaaaa +aaaaabababababababababababbyZkbxbyababababababababababababLILsLsLILsabababLsLsLsLskeLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLILsLsLILsLsLsLsLsLsLskeLsLsLsLsLsLILsLsLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLskeLsLsLsLILsLsLsLsLsLsLsLILsLsLsaZaXaXaXaYLsLsLILsLsLskeLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLILsLsLsabLsLsLsLsLILsLsLILsLsLsLsLILsLsLsLsaWLsLsLsLILsLsLsLILsLsLsLsLsaWLskeLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaabababababababababababbyPRbxbyababababababababababababLsababababababababababLsLsLsLILsLsLsLsLsLsLskeLsLILsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLsLsLsababLsLILsLsLsLsLskeLsLsLsLsLsLILsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsXpLsLILsaZaXaXcbaYLsLsLsLsLsLsLsLsLILsLsLsLILsLskeLsLsLsLsLsLsLsabLsababababLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsabLsabababLsabLsLsababLsLIabababababababababababababababababababababababababababababababaaaa +aaaaabababababababababababbybxbxbybybybyajajajababababababababababababajababababLILsLsLsLsLsLsLsLsLsLsLsababababLsababababababLsLsLskeLsLsaWLsLsLsLILsLsLsLsLsLILsLsabababpuCqCqCqpuLsLsLsLsLsLskeLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsXpLsLILsLskeLsLsLsLsXpaZaXaXaXaYLsLsXpLsaWLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsabababababababababababababLsLILsLsLsLskeLsLsLsLILsabababababababababLIabababababababababLsLsLsababababababababababababababababababababababababababaaaa +aaaaabababababababababababbybxbxbxPRbUakajajajajajabababababababababajajajabababababLsababababababababababababababababajajababababLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababpupuCqQuCqpupuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsaZaXaXaXaYLsLsLsLsLsLsLsLssLsLsLsLsLLsLsLsLsLsLsababababababababababababababababLsLsaWLsLILsLsababababababababababababababababababababababLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababababababbybxPRbxbxakJPakajakakajajababababababababajakajajababababababababababababajajajajajajajajajajajababababLsLsLsLsLILsLsababLsLsLsLsabababababCqCqCqCqCqCqCqCqCqLsLsLsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLssLsLsLsLsLLsXpLsPhPhPhPhPhaZaXaXaXaYsLsLsLsLsLLsLsLssLcscscssLLsLsLsLsLsLsababababababababababababababababLsabLsLsLsLsLsababababababababababababababababLsabababLsLsLsLsLsLILsabababababababababababababababababababababababababaaaa +aaaaabababababababababababbybybybybwbybybyajamakakajajabababababababajakakajajajajababababababababajajakakakakakakakakakajajababababababLsLsabababababababababababLspuCqCqCqCqOwCqCqCqCqpuLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLssLcscscssLLsLsLsLsLILsLsLsaZaXaXaXaYsLVZcscssLLsXpLssLcsnmcssLLsLsLsXpLsabababababababababababababababababababLsababLsabababababababababababababLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsabababababababababababababababababababababababaaaa +aaaaababababababababababababbybxPRbxbxbxbyajajakakakajajababajajajajajakakakakajajajajajajajajajajajakakakakakakajajakakakajajabababababababababababababababababLspupuQuCqOwCqCqCqOwCqQupupuLsLsLsLsLsLsLsLsLsLsLsLsLILsXpLsLssLcsnmcscsLsLsLsLsLsLsLsLsaZcbaXaXaYcscsnmcssLLsLsLssLVZcscssLLsLsLsLsLsababababababababababLsLsabLsLsLsabababababababababababLsLsLsababababLsLsLILsLsLsLsLsLsLsLsLsLskeLsLsabLsLsabababababababababababababababababababababababaaaa +aaaaababababababababababababbyKubxzCZkuDbyabajajajakakajajababajakakakakakakakakajajakakakakakakakakakakakakakajajajakakakakajabababababababababababLsabLsLsLsLsLsCqCqCqCqCqCqCqCqCqCqCqCqCqLsLsLsaWLsLsLsLsLsLsLsLsLsLsLsLsLssLVZcscssLLsXpLssLsLsLsLsLaZaXaXaXaYsLcscscssLLsXpLssLsLcssLsLLsLsLsLsLsabababababababLsLsLsLsLsLsLsLsLsabababababababLsLsLsLsLIDELsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa +aaaaababababababababababababbybxWxrnbxbxbyabababajajamakajajabajamakakakamakakakajajajakakakakakakajajajakakajajajakakakakakajabababababababababLsLsLsLsLsLsLILsLsCqCqCqOwCqCqzWCqCqOwCqCqCqLsLsLsLsLsLskeLsLsLskeLsLsLsLsLsLssLsLsLsLsLLsLsLssLcsVZcssLaZaXaXaXaYsLsLsLsLsLLsLsLsLsLsXpLsLsLsaWLsLsababababababLsLsLsLskeLsLsLsLsLILsLsLsabLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsaWLsLsLsLsDELsLsLsLsababababababababababababababababababababababababababaaaa +aaaaababababababababababababbyuDPRzCZkuDbyababababajajakakajajajakakakakakakakakakajajakakamakakakakajajakakakakakakakakakakajajababababababhshsLsLsLsLskeLsLsLsgJCqCqCqCqCqCqCqCqCqCqCqCqCqLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsXpLsLsLsLsLsLsLsLskesLcsnmcscsaZaXcbaXaYLsLsLsLsLsLskeLsLILsLsLsLsLsLsXpLsabababababLsLsLsLILsLsLsDELsLsLsLsLsLsLsLsLsLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsDELsLsLsLILsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaababababababababababababbyLkfYrnbxbxbyabababababajajamakakakakakajakakakakakakakakakakakakamakakakakakamakakakakakakakakakajababababababCqhshsLsLsLIgJLskeLsLspupuQuCqOwCqCqCqOwCqQupupuLsLsLsLsLsLsLskeLsLsLsLILsLsaWLsLsLssLsLsLsLsLLsLssLcscscssLaZaXaXaXaYsLsLsLsLsLLsLsLssLsLsLsLsLLsLsLsLsLsababLsLsLskeLsLsLsLsaWLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLILsLsLsLsDELsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaababababababababababababbyuDVlzCbxuDbyababababababajajakakakakajajajakakakamakakakakakakakajajakakakakakakajakajakakakamakajajajajajababCqCqhshsLsLsLsLsaWLsLsLspuCqCqCqCqOwCqCqCqCqpuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLskeLssLcscscssLLsLssLsLsLsLsLaZaXaXaXaYsLcscsVZsLLsLsXpsLcscsVZsLLsLskeLsababLsLsLILsLsLseMLsLsLsLsLsLILskeLsdtdtdtdtdtdtdtdtdtdtLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababababaaaa +aaaaababababababababababababbybxWxVxPRbxbyabababababababajajakakakajajakakakakakakakakakakajajajajakakakakajajajajajakakakakakakakakakajajCqCqCqCqhshsLskeLsLsLsLsLIgJCqCqCqCqCqCqCqCqCqLsLsLsLskeLsLILsLsLsLskeLsLsLsLsLsLsLsLssLcsnmVZsLLsLsLsXpLsLsPhaZaXcbaXaYcscsnmcssLLsLsLscscsnmcssLLsLILsLsababLsLsLshKLsLBLsLskeLsDELsLsLsLsdtdtLyGTLyPALyGTLyGTdtdtLsLskeLsLsLsLILsccccccccccccccccccLsLsLsababababababababababababababababababababababababababababaaaa +aaaaababababababababababababbyKuZkbxbxuDbyababababababababajakakakakakakakakakajajajakakakakajajakakakakakakajajajajajakamakakakakakakajajCqCqCqCqCqhshsLsLsLskeLsLsLsLspupuCqQuCqpupuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsXpLssLcscscssLLsXpLsLsLsLsPhaZaXaXaXaYsLcscscssLLskeXpsLcscsVZsLLsLsLsLsabababLseMLsLsDELILshKLsLsLseMLsdtdtPAGTGTGTGTGTGTGTGTPAdtdtLsLsLsLsLsLsLscccdcdcdcdcdcdcdccLsLsLsababababababababababababababababababababababababababababaaaa +aaaaababababababababababababbyfCPRecZkHHbyabababababababajajakakakakakakakakakakajakakamakakakakakakakakamakakakajajakakakakakakajajajajCqCqCqCqCqCqCqhsLsLsgJLsLsgJgJLsLspuCqCqCqpuLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLssLsLcssLsLLsLsPhPhPhPhPhaZaXaXaXaYsLsLsLsLsLLsLsLssLsLsLsLsLLsLsLsLsababLsLsLsLsNNLseMLsNNLsnhLBLsdtdtGTGTGTSuGTGTGTGTGTGTGTGTdtdtLsLsLsLsLsLscccdOiOiUGOiOicdTeaWLsLsLsabababababababababababababababababababababababababababaaaa +aaaaababababababababababababbybybybybybybyabababababababajajakakakamakakakakajajajakakakakakakakakajajakakakakakakakakakakakakakajaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUchaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaXcbaXaXaXaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUaUciaUckclcmckaUcmaUcnclckTCaUcodtGTGTVMGTGTcxOyCyEyGTGTVMGTGTdtdtdtdtdtdtdtcccdOiPCNkPCOicdccLsLsLsLsabababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababababajakakakakakakakakajajakajakakakakakakajakakakakakakakakakakakajakakakajaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbraXaXaXaXaXaXaXaXcbaXaXaXaXaXaXaXaXbraXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbgaXcfaXgBaXcgaXSEcraXaXcqcraYIUGTGTVMGTGTGTGTGTGTGTGTVMGTGTGTGThGPAGTGTIUccUMUGcvRjDkUGcdccLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababababajajajakajajajakakakakakakakakakamakakajajakakamakakajakakamakajajajakakajaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbraXaXaXaXaXaXaXaXaXaXaXaXaXbpaXaXaXbraXaXaXaXcbaXaXaXaXaXaXaXaXaXaXaXbgaXaXaXctaXcucwcwcuaXaXaXaXcBdtrtSudtrttDnLGgavbcGTpddtGTGTGTGTGTGTGTGTdtcccdEIKnKnVyEIcdccLILskeLsLsLsLsababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababababababajajajabajakakakakakakakakajakakakajajakakakakajajajakakakakajakakakakaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXaXbraXcbaXcbaXaXaXaXaXaXaXaXaXaXaXaXaXbraXcbaXaXaXaXaXcbaXcbaXaXaXaXaXaXbgaXcfaXaXaXcfaXctaXcqaXaXcgaYIUGTGTVMGTGTGTGTGTGTGTGTVMGTGTZqGThGGTGTGTIUcccdEIMsYgMsEIcdccLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababababababababababajajajakakakakakakajajakakakakakakakajajajakakakakakajakakakajbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdcDbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdcEbdbdbdcFcGbdcHcJbdbdcGcKbdbedtGTGTVMGTGTeaRbjRTMGTGTVMGTGTdtdtdtdtdtdtdtcccdOiOiOiOiOicdccLsDELsLILsLsabababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababababababababababababajajakamakakajajajakakakakakakakakakakakakamakakakakakakajCqCqCqCqCqCqCqCqCqCqhsLsLsLsLsgJLsLsLsLsgJLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsXpLsPhLsLsLsLssLsLcssLsLLsPhPhPhLssLsLcssLsLLssLsLcssLsLLsLsLsLsLILsLsLsLsababLsNNeMLsnhLsrmeMLskiRfLBkidtdtGTGTGTSuGTGTGTGTGTGTGTGTdtdtLsLsLsLsLsLscccdOiJBJBJBOicdccLsLsLsLsLsLsLsababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababababababababababababajajajakakakajakajakamakakakakakakakajakakakakakakakajajCqCqCqCqCqCqCqCqCqhshsLsLsLskeLsLskeLsLsLsLsLskeLsLsLsLsLsLsaWLsLsLsLsLsLsLsLsLskeLsLsLILsLsLsLsLsLsLssLVZcscssLLsLskeLsLssLVZcscssLLssLcscscssLLsLskeLsLsLsLsLsababababLsLsLskeLsLBLsLshKLseMLsLsdtdtZqGTGTGTGTGTGTGTGTZqdtdtLsLsLsLILsLsLscccdLPLPLPLPLPcdccLsLsLsaWLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababababababababababababababajakakakakakakakakakakakakakajajajakakakakakakajajCqCqCqCqCqCqCqCqCqhshsLsgJLsLsLsLsLsaWLsLsLILsLsLsLILsLskeLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsXpLsLsXpLsLssLcsnmVZsLLsaWXpLsXpsLcsnmcssLLssLcsnmcssLLILsLsLsLsabababababababababLBLshKLskiLsLskeLsLsDELsdtdtLyGTLyZqLyGTLyGTdtdtLsLsLskeLsLsLsLscccdcdcdcdcdcdcdccLsLsLsLsLsLsabababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababababababababababababababajajakakakakakajajajakakakakajajajajakakamakajajCqCqCqCqCqCqCqCqCqhshsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsLsLsLsLsLsLsLssLcscscssLLsLsLsLsLssLcscscssLLssLVZcscssLLsLsababababababababababababLsLsLsLsLsDELsLsLsLsLsLsLsdtdtdtdtdtdtdtdtdtdtLsLsLsLsLsLsLILsLsccccccTeccccccccccLsLskeLsLsababababababababababababababababababababababababababaaaa +aaaaababababababababababababababababababababababababababababababababababababababajakakakajajajabajajajajajajajajakakakakajajCqCqCqCqCqCqCqCqCqhshsLsLskeLsLsLsLsLskeLsLsgJLsLskeLsgJLsLsLsabLsLsLILsLsLsLsabLsLsLsLsLsLsLILsLsLsLsLsLsLssLsLsLsLsLLsLsLsababsLsLsLsLsLLssLsLsLsLsLabababababababababababababababLsLsLsLsLsLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsaWLsLsLILsaWLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababaaaa aaaaababababababababababababababababababababababababababababababababababababababajajajajajababababababajabajajajajajajajajCqCqCqabCqCqCqCqCqhshsLsLsLsLsLsLsLsLsLsabLsLsLsLsLsLsLsLsLsabLsabLsLsLsLsababababababLsLsLsLsLsaWLsLskeLsLsLsLsLsLsLsLsLsabababababababLsLsLsabababababababababababababababababababababababLsLsLsaWLsLsLsLsLsLsaWLsLsLskeLsLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLILsLsDELsLsLILsLsLsababababababababababababababababababababababababababaaaa -aaaaabababababababababababababababababababababababababababababababababababababababajajabajabababababababababababajabajajajabababababababCqhshsLsLsLsLsLsLsabababababababLsLsLsababababababababLsLsabababababababLsLsLsabLsabLsLsLsLsLsLsLILsLsLsababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsDELsLsLsLsLsLsLsLsabLsLsabLsLsLskeLsLsDELsLsLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa +aaaaabababababababababababababababababababababababababababababababababababababababajajabajabababababababababababajabajajajabababababababCqhshsLsLsLsLsgJLsabababababababLsLsLsababababababababLsLsabababababababLsLsLsabLsabLsLsLsLsLsLsLILsXpLsababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsDELsLsLsLsLsLsLsLsabLsLsabLsLsLskeLsLsDELsLsLskeLsLsLsLsLsLsLsLsLsababababababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababajajababababababababhsLsLsababLsLsababababababababLsLsabababababababababababababababababababababababababababLsLsLsLsLsLsLsabababababababababababababababababababababababababababababababababababababababLsLsLsLsLsLsLsabLsLsabLsabababababLsLsLsLsLsLsLsLsLsLsLsLsLILsLsLsLsLsabababababababababababababababababababababababababababababaaaa aaaaababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsLsabababababababababababababababababababababababababababababababababababababababababababababLsabLsLsababababababababababababababababababababababababababababababababababababababababababLsLsababababababababababababLsLsLsLsLsLILsLsLsLsaWLsLsabababLsLsabababababababababababababababababababababababababababababaaaa aaaaabababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababLsLsabLsLsLsLsLsababababababababababababababababababababababababababababababababababababababaaaa diff --git a/_maps/map_files/LayeniaStation/LayeniaStation.dmm b/_maps/map_files/LayeniaStation/LayeniaStation.dmm index 56a6154a..b7bba568 100644 --- a/_maps/map_files/LayeniaStation/LayeniaStation.dmm +++ b/_maps/map_files/LayeniaStation/LayeniaStation.dmm @@ -254,7 +254,7 @@ "aIp" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 6; name = "scrubbers pipe"},/turf/open/floor/plasteel,/area/crew_quarters/fitness/pool) "aIr" = (/obj/effect/turf_decal/stripes/line{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 5; name = "air supply pipe"},/turf/open/floor/plasteel{dir = 8; icon_state = "floor_trim"},/area/ai_monitored/security/armory) "aIB" = (/obj/machinery/chem_heater,/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/yellow{dir = 1},/turf/open/floor/plasteel/white,/area/medical/chemistry) -"aIE" = (/obj/machinery/door/airlock/public/glass{name = "Abandon Maintenance Pool"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel/dark,/area/maintenance/fore) +"aIE" = (/obj/machinery/door/airlock/public/glass{name = "Abandoned Maintenance Pool"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel/dark,/area/maintenance/fore) "aIJ" = (/obj/effect/spawner/structure/window/reinforced,/turf/open/floor/plating,/area/medical/virology) "aIK" = (/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer3{dir = 1; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer1{dir = 1; name = "scrubbers pipe"},/obj/structure/cable{icon_state = "2-8"},/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 1; icon_plating = "floor"; icon_state = "floor_whole"},/area/hallway/secondary/exit) "aIT" = (/obj/machinery/atm{pixel_y = 30},/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/brown,/turf/open/floor/plasteel,/area/hallway/primary/aft) @@ -1603,7 +1603,7 @@ "evB" = (/obj/machinery/door/window/eastleft{dir = 2; name = "Monkey Pen"; req_one_access_txt = "9"},/obj/machinery/atmospherics/components/unary/vent_pump/on/layer3{name = "air vent"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/turf/open/floor/grass,/area/medical/genetics) "evI" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 9},/turf/closed/wall/r_wall,/area/science/mixing) "evK" = (/obj/machinery/light{pixel_y = -1},/turf/open/floor/plasteel,/area/security/prison) -"evQ" = (/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 1},/turf/open/floor/plasteel/dark,/area/security/brig) +"evQ" = (/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark,/area/security/brig) "evR" = (/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/incinerator_output{dir = 8},/turf/open/floor/engine,/area/maintenance/disposal/incinerator) "evT" = (/obj/structure/cable{icon_state = "0-4"},/obj/machinery/power/apc{areastring = "/area/maintenance/solars/port/aft"; dir = 8; name = "Port Quarter Solar APC"; pixel_x = -25; pixel_y = 3},/turf/open/floor/plating,/area/maintenance/solars/port/aft) "evV" = (/obj/structure/trash_pile,/obj/effect/decal/cleanable/dirt,/obj/effect/decal/cleanable/dirt,/turf/open/floor/plasteel/dark,/area/maintenance/fore) @@ -2953,7 +2953,7 @@ "iqp" = (/obj/structure/table,/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral,/obj/item/clothing/glasses/meson{pixel_x = 2; pixel_y = 4},/obj/item/clothing/glasses/meson,/turf/open/floor/plasteel,/area/engine/engineering) "iqt" = (/obj/effect/turf_decal/tile/blue{dir = 1},/obj/effect/turf_decal/tile/blue{dir = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/obj/machinery/atmospherics/components/unary/vent_pump/on/layer3{name = "air vent"},/obj/structure/cable{icon_state = "2-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/newscaster{pixel_y = 32},/turf/open/floor/plasteel/white,/area/medical/sleeper) "iqu" = (/obj/structure/table,/turf/open/floor/plasteel/freezer,/area/medical/sleeper) -"iqD" = (/obj/structure/flora/crystal/medium/growth,/turf/open/indestructible/layenia/crystal/garden,/area/layenia) +"iqD" = (/obj/structure/flora/crystal/medium/growth,/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hop) "iqP" = (/obj/structure/flora/junglebush,/obj/structure/window/reinforced{dir = 8},/turf/open/floor/grass,/area/medical/sleeper) "ire" = (/obj/machinery/light{dir = 4; pixel_x = 7; pixel_y = 0},/obj/machinery/porta_turret/ai{dir = 8},/turf/open/floor/circuit,/area/ai_monitored/turret_protected/ai_upload) "irn" = (/obj/structure/chair{dir = 8},/obj/structure/window{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 4; icon_state = "floor_plate"},/area/hallway/secondary/exit) @@ -3236,7 +3236,7 @@ "jax" = (/obj/machinery/meter/atmos/atmos_waste_loop,/obj/machinery/camera{c_tag = "Atmospherics North East"},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/machinery/atmospherics/pipe/manifold/scrubbers/visible{dir = 1},/obj/structure/cable{icon_state = "2-4"},/turf/open/floor/plasteel,/area/engine/atmos) "jaB" = (/obj/item/twohanded/required/kirbyplants/random,/turf/open/floor/wood,/area/lawoffice) "jaD" = (/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral,/turf/open/floor/plasteel/dark,/area/security/main) -"jaH" = (/obj/structure/cable/yellow{icon_state = "1-4"},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat_interior"; name = "Antechamber Turret Control"; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat_interior) +"jaH" = (/obj/structure/cable/yellow{icon_state = "1-4"},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat/hallway"; name = "Antechamber Turret Control"; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat_interior) "jaR" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/machinery/light{pixel_y = -1},/obj/structure/sign/departments/restroom{pixel_y = -32},/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/hallway/primary/fore) "jaX" = (/obj/effect/baseturf_helper/asteroid/layenia,/turf/closed/wall/r_wall,/area/science/xenobiology) "jaZ" = (/obj/machinery/vending/wardrobe/law_wardrobe,/obj/machinery/light{dir = 4; pixel_x = 7; pixel_y = 0},/turf/open/floor/wood,/area/lawoffice) @@ -3526,7 +3526,7 @@ "jUE" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/obj/effect/turf_decal/tile/purple{dir = 8},/turf/open/floor/plasteel/white/corner,/area/hallway/primary/aft) "jUP" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/obj/structure/cable{icon_state = "4-8"},/obj/structure/cable{icon_state = "1-4"},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable{icon_state = "2-4"},/turf/open/floor/plasteel/white,/area/medical/genetics) "jUT" = (/obj/structure/table,/obj/item/stack/ore/iron,/turf/open/floor/plating,/area/maintenance/starboard) -"jUU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 6; name = "air supply pipe"},/turf/open/floor/plasteel/dark,/area/security/prison) +"jUU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 6; name = "air supply pipe"},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark,/area/security/prison) "jUY" = (/turf/open/floor/plating/asteroid/layenia,/area/layenia/cloudlayer) "jVg" = (/obj/structure/railing{dir = 8},/turf/open/floor/plasteel/dark,/area/hallway/primary/starboard) "jVq" = (/obj/effect/spawner/structure/window,/obj/machinery/door/firedoor,/turf/open/floor/plating,/area/medical/chemistry) @@ -4361,7 +4361,7 @@ "mwm" = (/obj/machinery/atmospherics/pipe/manifold/general/visible{dir = 8},/obj/effect/turf_decal/stripes/line{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/effect/turf_decal/tile/neutral,/obj/effect/turf_decal/tile/neutral{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/landmark/start/scientist,/turf/open/floor/plasteel/dark,/area/science/mixing) "mwz" = (/obj/machinery/door/airlock/maintenance{name = "Bar Maintenance"; req_access_txt = "25"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/structure/cable{icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/open/floor/plasteel/dark,/area/maintenance/fore/secondary) "mwC" = (/obj/effect/turf_decal/tile/blue{dir = 8},/obj/effect/turf_decal/tile/blue{dir = 1},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/structure/disposalpipe/segment{dir = 4},/obj/item/radio/intercom{frequency = 1485; name = "Station Intercom (Medbay)"; pixel_x = -30},/turf/open/floor/plasteel/white,/area/medical/sleeper) -"mwT" = (/obj/effect/turf_decal/tile/red{dir = 1},/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral,/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1{name = "air scrubber"},/turf/open/floor/plasteel/dark/side,/area/security/main) +"mwT" = (/obj/effect/turf_decal/tile/red{dir = 1},/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral,/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer1{name = "air scrubber"},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel/dark/side,/area/security/main) "mwV" = (/turf/open/floor/plasteel/stairs/medium,/area/hallway/primary/port) "mxe" = (/obj/structure/closet/secure_closet/detective,/turf/open/floor/wood,/area/security/detectives_office) "mxg" = (/obj/machinery/light{pixel_y = -1},/turf/open/chasm/cloud,/area/layenia/cloudlayer) @@ -6365,7 +6365,7 @@ "rNe" = (/obj/effect/turf_decal/tile/red,/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/neutral{dir = 8},/obj/effect/turf_decal/tile/neutral{dir = 1},/obj/machinery/door/firedoor,/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/turf/open/floor/plasteel/dark/side{dir = 8},/area/security/main) "rNg" = (/obj/machinery/atmospherics/pipe/simple/cyan/visible,/obj/structure/cable{icon_state = "1-2"},/turf/open/floor/plasteel{dir = 8; icon_state = "floor_trim"},/area/engine/atmos) "rNj" = (/obj/machinery/power/apc{areastring = "/area/crew_quarters/fitness"; name = "Fitness Room APC"; pixel_y = -24},/obj/structure/cable,/turf/open/floor/wood,/area/crew_quarters/fitness) -"rNv" = (/obj/structure/flora/crystal/small/pile,/obj/structure/flora/crystal/small/growth{icon_state = "crystalgrowth3"},/turf/open/indestructible/layenia/crystal/garden,/area/layenia) +"rNv" = (/obj/structure/flora/crystal/small/pile,/obj/structure/flora/crystal/small/growth{icon_state = "crystalgrowth3"},/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hop) "rNy" = (/obj/structure/toilet{dir = 4},/obj/machinery/light{dir = 8; pixel_x = -7; pixel_y = 0},/turf/open/floor/plasteel/freezer,/area/crew_quarters/toilet) "rNz" = (/obj/structure/table/reinforced,/obj/machinery/keycard_auth{pixel_x = 3; pixel_y = 5},/obj/effect/turf_decal/tile/green,/obj/effect/turf_decal/tile/green{dir = 4},/obj/effect/turf_decal/tile/blue{dir = 1},/turf/open/floor/plasteel/white/corner{dir = 8},/area/bridge) "rNF" = (/obj/effect/turf_decal/loading_area{icon_state = "drain"; name = "drain"},/turf/open/floor/plasteel/white/corner{dir = 1},/area/science/research) @@ -7304,7 +7304,7 @@ "ulb" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8; layer = 2.9},/obj/machinery/conveyor{id = "gasstor"},/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/open/floor/plating,/area/engine/engineering) "ulm" = (/obj/structure/flora/crystal/medium/growth{icon_state = "crystalgrowth1"},/turf/open/indestructible/layenia/crystal/garden,/area/crew_quarters/heads/hor) "ulp" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/visible,/obj/structure/cable{icon_state = "4-8"},/turf/open/floor/plasteel/dark,/area/maintenance/disposal/incinerator) -"ulL" = (/obj/structure/cable/yellow{icon_state = "1-2"},/obj/structure/cable/yellow{icon_state = "1-8"},/obj/machinery/atmospherics/components/unary/vent_pump/on{dir = 8},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/item/twohanded/required/kirbyplants/photosynthetic{pixel_y = 10},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat/hallway"; name = "Chamber Hallway Turret Control"; pixel_x = 32; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/structure/extinguisher_cabinet{pixel_x = 27},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat/hallway) +"ulL" = (/obj/structure/cable/yellow{icon_state = "1-2"},/obj/structure/cable/yellow{icon_state = "1-8"},/obj/machinery/atmospherics/components/unary/vent_pump/on{dir = 8},/obj/machinery/light{dir = 1; pixel_y = 16},/obj/item/twohanded/required/kirbyplants/photosynthetic{pixel_y = 10},/obj/machinery/turretid{control_area = "/area/ai_monitored/turret_protected/aisat_interior"; name = "Chamber Hallway Turret Control"; pixel_x = 32; pixel_y = 24; req_access = null; req_access_txt = "65"},/obj/structure/extinguisher_cabinet{pixel_x = 27},/obj/effect/turf_decal/tile/blue{dir = 4},/turf/open/floor/plasteel/dark,/area/ai_monitored/turret_protected/aisat/hallway) "ulM" = (/obj/machinery/vending/wardrobe/chem_wardrobe,/obj/effect/turf_decal/tile/yellow{dir = 1},/obj/effect/turf_decal/tile/yellow{dir = 8},/obj/effect/turf_decal/tile/yellow,/turf/open/floor/plasteel/white,/area/medical/chemistry) "umu" = (/obj/effect/turf_decal/loading_area{dir = 1; icon_state = "drain"; name = "drain"},/turf/open/floor/plasteel/white,/area/medical/medbay/central) "umv" = (/obj/structure/cable{icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{name = "scrubbers pipe"},/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{name = "air supply pipe"},/turf/open/floor/plasteel,/area/security/main) @@ -8537,7 +8537,7 @@ "xxr" = (/obj/effect/turf_decal/stripes/line,/obj/docking_port/stationary/random{dir = 2; id = "pod_lavaland4"; name = "lavaland"},/turf/open/indestructible/concrete,/area/layenia/cloudlayer) "xxA" = (/turf/open/floor/plasteel/yellowsiding{dir = 4},/area/maintenance/fore) "xxF" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer3{dir = 8; name = "air supply pipe"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer1{dir = 4; name = "scrubbers pipe"},/turf/open/floor/plasteel,/area/security/main) -"xxL" = (/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/red{dir = 1},/obj/machinery/computer/lore_terminal,/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/security/brig) +"xxL" = (/obj/effect/turf_decal/tile/red{dir = 4},/obj/effect/turf_decal/tile/red{dir = 1},/obj/machinery/computer/lore_terminal/security,/turf/open/floor/plasteel{icon_state = "floor_plate"},/area/security/brig) "xxU" = (/obj/item/twohanded/required/fuel_rod,/obj/effect/turf_decal/stripes/line{dir = 4},/turf/open/pool,/area/engine/engineering/reactor_core) "xxV" = (/obj/structure/closet/secure_closet/medical1,/obj/effect/turf_decal/stripes/line{dir = 1},/obj/machinery/light{pixel_y = -1},/turf/open/floor/plasteel/dark,/area/gateway) "xxW" = (/turf/open/floor/plasteel/stairs/medium{dir = 4},/area/security/main) diff --git a/_maps/shuttles/emergency_imfedupwiththisworld.dmm b/_maps/shuttles/emergency_imfedupwiththisworld.dmm index e0e86815..b025f092 100644 --- a/_maps/shuttles/emergency_imfedupwiththisworld.dmm +++ b/_maps/shuttles/emergency_imfedupwiththisworld.dmm @@ -20,8 +20,8 @@ "t" = (/obj/structure/table/reinforced,/obj/effect/turf_decal/tile/bar,/obj/effect/turf_decal/tile/bar{dir = 1},/turf/open/floor/plasteel,/area/shuttle/escape) "u" = (/obj/machinery/light{dir = 8},/turf/open/floor/wood,/area/shuttle/escape) "v" = (/obj/structure/chair/office/dark,/turf/open/floor/wood,/area/shuttle/escape) -"w" = (/obj/effect/decal/cleanable/blood,/obj/effect/decal/cleanable/blood/drip,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/mob_spawn/human/corpse,/obj/item/gun/ballistic/automatic/pistol/m1911,/obj/machinery/light/small{dir = 8},/obj/item/reagent_containers/food/snacks/cakeslice/birthday,/turf/open/floor/carpet,/area/shuttle/escape) -"x" = (/obj/structure/bed,/obj/item/bedsheet/red,/obj/item/paper/fluff/shuttles/daniel,/turf/open/floor/carpet,/area/shuttle/escape) +"w" = (/obj/machinery/light/small{dir = 8},/mob/living/simple_animal/bot/hugbot,/turf/open/floor/carpet,/area/shuttle/escape) +"x" = (/obj/structure/bed,/obj/item/bedsheet/red,/turf/open/floor/carpet,/area/shuttle/escape) "y" = (/obj/item/twohanded/required/kirbyplants,/turf/open/floor/wood,/area/shuttle/escape) "z" = (/obj/structure/table/wood,/obj/item/papercutter,/turf/open/floor/wood,/area/shuttle/escape) "A" = (/obj/structure/table/wood,/obj/machinery/computer/libraryconsole/bookmanagement,/turf/open/floor/wood,/area/shuttle/escape) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 24d381d1..eb9ed377 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -28,7 +28,9 @@ #define ITEM_SLOT_POCKET (1<<11) // this is to allow items with a w_class of WEIGHT_CLASS_NORMAL or WEIGHT_CLASS_BULKY to fit in pockets. #define ITEM_SLOT_DENYPOCKET (1<<12) // this is to deny items with a w_class of WEIGHT_CLASS_SMALL or WEIGHT_CLASS_TINY to fit in pockets. #define ITEM_SLOT_NECK (1<<13) -#define ITEM_SLOT_SUITSTORE (1<<14) +#define ITEM_SLOT_HANDS (1<<14) +#define ITEM_SLOT_BACKPACK (1<<15) +#define ITEM_SLOT_SUITSTORE (1<<16) //SLOTS #define SLOT_BACK 1 @@ -86,6 +88,10 @@ . = ITEM_SLOT_ICLOTHING if(SLOT_L_STORE, SLOT_R_STORE) . = ITEM_SLOT_POCKET + if(SLOT_HANDS) + . = ITEM_SLOT_HANDS + if(SLOT_IN_BACKPACK) + . = ITEM_SLOT_BACKPACK if(SLOT_S_STORE) . = ITEM_SLOT_SUITSTORE diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 7a09f40c..96190e6d 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -157,6 +157,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isclown(A) (istype(A, /mob/living/simple_animal/hostile/retaliate/clown)) +#define ismimic(A) (istype(A, /mob/living/simple_animal/hostile/hs13mimic)) + GLOBAL_LIST_INIT(shoefootmob, typecacheof(list( /mob/living/carbon/human/, /mob/living/simple_animal/cow, diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 160151f1..22bdc0ff 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -65,6 +65,9 @@ if (CONFIG_GET(flag/log_virus)) WRITE_LOG(GLOB.world_virus_log, "VIRUS: [text]") +/proc/log_asset(text) + WRITE_LOG(GLOB.world_asset_log, "ASSET: [text]") + /proc/log_access(text) if (CONFIG_GET(flag/log_access)) WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]") diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index e0d54c9e..ec59dd69 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -23,6 +23,9 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_records_dsc(datum/data/record/a, datum/data/record/b) return sorttext(a.fields[GLOB.cmp_field], b.fields[GLOB.cmp_field]) +/proc/cmp_filter_data_priority(list/A, list/B) + return A["priority"] - B["priority"] + /proc/cmp_ckey_asc(client/a, client/b) return sorttext(b.ckey, a.ckey) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 7bfd0ff1..291ed19c 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1128,9 +1128,10 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 if (!isicon(I)) if (isfile(thing)) //special snowflake var/name = sanitize_filename("[generate_asset_name(thing)].png") - register_asset(name, thing) + if(!SSassets.cache[name]) + register_asset(name, thing) for (var/thing2 in targets) - send_asset(thing2, key, FALSE) + send_asset(thing2, key) return "" var/atom/A = thing if (isnull(dir)) @@ -1152,9 +1153,10 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0 I = icon(I, icon_state, dir, frame, moving) key = "[generate_asset_name(I)].png" - register_asset(key, I) + if(!SSassets.cache[key]) + register_asset(key, I) for (var/thing2 in targets) - send_asset(thing2, key, FALSE) + send_asset(thing2, key) return "" diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index 5354a6e0..0d370545 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -28,6 +28,8 @@ GLOBAL_VAR(world_job_debug_log) GLOBAL_PROTECT(world_job_debug_log) GLOBAL_VAR(world_virus_log) GLOBAL_PROTECT(world_virus_log) +GLOBAL_VAR(world_asset_log) +GLOBAL_PROTECT(world_asset_log) GLOBAL_VAR(world_map_error_log) GLOBAL_PROTECT(world_map_error_log) diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 7b6554bd..72852982 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -6,17 +6,7 @@ SUBSYSTEM_DEF(assets) var/list/preload = list() /datum/controller/subsystem/assets/Initialize(timeofday) - - var/list/priority_assets = list( - /datum/asset/simple/oui_theme_nano, - /datum/asset/simple/goonchat - ) - - for(var/type in priority_assets) - var/datum/asset/A = new type() - A.register() - - for(var/type in typesof(/datum/asset) - (priority_assets | list(/datum/asset, /datum/asset/simple))) + for(var/type in typesof(/datum/asset)) var/datum/asset/A = type if (type != initial(A._abstract)) get_asset_datum(type) diff --git a/code/controllers/subsystem/minimaps.dm b/code/controllers/subsystem/minimaps.dm index 75de71ca..c25036a4 100644 --- a/code/controllers/subsystem/minimaps.dm +++ b/code/controllers/subsystem/minimaps.dm @@ -1,8 +1,8 @@ SUBSYSTEM_DEF(minimaps) name = "Minimaps" flags = SS_NO_FIRE - var/list/station_minimaps - var/datum/minimap_group/station_minimap + var/list/station_minimaps = list() + var/datum/minimap_group/station_minimap = null /datum/controller/subsystem/minimaps/Initialize() if(!CONFIG_GET(flag/minimaps_enabled)) @@ -12,9 +12,9 @@ SUBSYSTEM_DEF(minimaps) return ..() /datum/controller/subsystem/minimaps/proc/build_minimaps() - station_minimaps = list() for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) var/datum/space_level/SL = SSmapping.get_level(z) var/name = (SL.name == initial(SL.name))? "[z] - Station" : "[z] - [SL.name]" station_minimaps += new /datum/minimap(z, name = name) + station_minimap = new(station_minimaps, "Station") diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index 07c786b1..fe433c3e 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -7,12 +7,10 @@ SUBSYSTEM_DEF(vis_overlays) var/list/vis_overlay_cache var/list/unique_vis_overlays var/list/currentrun - var/datum/callback/rotate_cb /datum/controller/subsystem/vis_overlays/Initialize() vis_overlay_cache = list() unique_vis_overlays = list() - rotate_cb = CALLBACK(src, .proc/rotate_vis_overlay) return ..() /datum/controller/subsystem/vis_overlays/fire(resumed = FALSE) @@ -57,7 +55,7 @@ SUBSYSTEM_DEF(vis_overlays) if(!thing.managed_vis_overlays) thing.managed_vis_overlays = list(overlay) - RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, rotate_cb) + RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_vis_overlay) else thing.managed_vis_overlays += overlay diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index a6c3e787..d0d228ac 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -1,6 +1,6 @@ #define DYNAMIC_DEFAULT_CHAOS 1.0 //The default chaos value for low pop low vote rounds #define DYNAMIC_VOTE_NORMALIZATION 8 //If there are fewer than this many votes, the average will be skewed towards the default -#define DYNAMIC_NONVOTER_FACTOR 0.6 // 1 means they count for a full vote +#define DYNAMIC_NONVOTER_FACTOR 1 // 1 means they count for a full vote #define DYNAMIC_NONVOTER_VALUE 1.5 // The chaos value that non-voters should account for. SUBSYSTEM_DEF(vote) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index a43adbfc..f0d9b996 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -43,8 +43,10 @@ var/datum/asset/spritesheet/sheet = name stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]" else - stylesheets["[ckey(name)].css"] = file - register_asset("[ckey(name)].css", file) + var/asset_name = "[name].css" + stylesheets[asset_name] = file + if(!SSassets.cache[asset_name]) + register_asset(asset_name, file) /datum/browser/proc/set_content(ncontent) content = ncontent @@ -91,20 +93,20 @@ [get_footer()] "} -/datum/browser/proc/open(use_onclose = 1) +/datum/browser/proc/open(use_onclose = TRUE) if(isnull(window_id)) //null check because this can potentially nuke goonchat WARNING("Browser [title] tried to open with a null ID") to_chat(user, "The [title] browser you tried to open failed a sanity check! Please report this on github!") return var/window_size = "" - if (width && height) + if(width && height) window_size = "size=[width]x[height];" - if (stylesheets.len) - send_asset_list(user, stylesheets, verify=FALSE) - if (scripts.len) - send_asset_list(user, scripts, verify=FALSE) + if(stylesheets.len) + send_asset_list(user, stylesheets) + if(scripts.len) + send_asset_list(user, scripts) user << browse(get_content(), "window=[window_id];[window_size][window_options]") - if (use_onclose) + if(use_onclose) setup_onclose() /datum/browser/proc/setup_onclose() @@ -151,7 +153,7 @@ close() //designed as a drop in replacement for alert(); functions the same. (outside of needing User specified) -/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) +/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) if (!User) User = usr switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)) diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index ab0f7584..6c74f973 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -1,318 +1,315 @@ -/datum/component - var/dupe_mode = COMPONENT_DUPE_HIGHLANDER - var/dupe_type - var/datum/parent - //only set to true if you are able to properly transfer this component - //At a minimum RegisterWithParent and UnregisterFromParent should be used - //Make sure you also implement PostTransfer for any post transfer handling - var/can_transfer = FALSE - -/datum/component/New(datum/P, ...) - parent = P - var/list/arguments = args.Copy(2) - if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE) - qdel(src, TRUE, TRUE) - CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]") - - _JoinParent(P) - -/datum/component/proc/_JoinParent() - var/datum/P = parent - //lazy init the parent's dc list - var/list/dc = P.datum_components - if(!dc) - P.datum_components = dc = list() - - //set up the typecache - var/our_type = type - for(var/I in _GetInverseTypeList(our_type)) - var/test = dc[I] - if(test) //already another component of this type here - var/list/components_of_type - if(!length(test)) - components_of_type = list(test) - dc[I] = components_of_type - else - components_of_type = test - if(I == our_type) //exact match, take priority - var/inserted = FALSE - for(var/J in 1 to components_of_type.len) - var/datum/component/C = components_of_type[J] - if(C.type != our_type) //but not over other exact matches - components_of_type.Insert(J, I) - inserted = TRUE - break - if(!inserted) - components_of_type += src - else //indirect match, back of the line with ya - components_of_type += src - else //only component of this type, no list - dc[I] = src - - RegisterWithParent() - -// If you want/expect to be moving the component around between parents, use this to register on the parent for signals -/datum/component/proc/RegisterWithParent() - return - -/datum/component/proc/Initialize(...) - return - -/datum/component/Destroy(force=FALSE, silent=FALSE) - if(!force && parent) - _RemoveFromParent() - if(!silent) - SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src) - parent = null - return ..() - -/datum/component/proc/_RemoveFromParent() - var/datum/P = parent - var/list/dc = P.datum_components - for(var/I in _GetInverseTypeList()) - var/list/components_of_type = dc[I] - if(length(components_of_type)) // - var/list/subtracted = components_of_type - src - if(subtracted.len == 1) //only 1 guy left - dc[I] = subtracted[1] //make him special - else - dc[I] = subtracted - else //just us - dc -= I - if(!dc.len) - P.datum_components = null - - UnregisterFromParent() - -/datum/component/proc/UnregisterFromParent() - return - -/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proc_or_callback, override = FALSE) - if(QDELETED(src) || QDELETED(target)) - return - - var/list/procs = signal_procs - if(!procs) - signal_procs = procs = list() - if(!procs[target]) - procs[target] = list() - var/list/lookup = target.comp_lookup - if(!lookup) - target.comp_lookup = lookup = list() - - if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now - proc_or_callback = CALLBACK(src, proc_or_callback) - - var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types) - for(var/sig_type in sig_types) - if(!override && procs[target][sig_type]) - stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning") - - procs[target][sig_type] = proc_or_callback - - if(!lookup[sig_type]) // Nothing has registered here yet - lookup[sig_type] = src - else if(lookup[sig_type] == src) // We already registered here - continue - else if(!length(lookup[sig_type])) // One other thing registered here - lookup[sig_type] = list(lookup[sig_type]=TRUE) - lookup[sig_type][src] = TRUE - else // Many other things have registered here - lookup[sig_type][src] = TRUE - - signal_enabled = TRUE - -/datum/proc/UnregisterSignal(datum/target, sig_type_or_types) - if(!target) - CRASH("[src] tried to unregister a signal without having a target.") - var/list/lookup = target.comp_lookup - if(!signal_procs || !signal_procs[target] || !lookup) - return - if(!islist(sig_type_or_types)) - sig_type_or_types = list(sig_type_or_types) - for(var/sig in sig_type_or_types) - switch(length(lookup[sig])) - if(2) - lookup[sig] = (lookup[sig]-src)[1] - if(1) - stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup") - if(src in lookup[sig]) - lookup -= sig - if(!length(lookup)) - target.comp_lookup = null - break - if(0) - lookup -= sig - if(!length(lookup)) - target.comp_lookup = null - break - else - lookup[sig] -= src - - signal_procs[target] -= sig_type_or_types - if(!signal_procs[target].len) - signal_procs -= target - -/datum/component/proc/InheritComponent(datum/component/C, i_am_original) - return - -/datum/component/proc/PreTransfer() - return - -/datum/component/proc/PostTransfer() - return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it - -/datum/component/proc/_GetInverseTypeList(our_type = type) - //we can do this one simple trick - var/current_type = parent_type - . = list(our_type, current_type) - //and since most components are root level + 1, this won't even have to run - while (current_type != /datum/component) - current_type = type2parent(current_type) - . += current_type - -/datum/proc/_SendSignal(sigtype, list/arguments) - var/target = comp_lookup[sigtype] - if(!length(target)) - var/datum/C = target - if(!C.signal_enabled) - return NONE - var/datum/callback/CB = C.signal_procs[src][sigtype] - return CB.InvokeAsync(arglist(arguments)) - . = NONE - for(var/I in target) - var/datum/C = I - if(!C.signal_enabled) - continue - var/datum/callback/CB = C.signal_procs[src][sigtype] - . |= CB.InvokeAsync(arglist(arguments)) - -/datum/proc/GetComponent(c_type) - var/list/dc = datum_components - if(!dc) - return null - . = dc[c_type] - if(length(.)) - return .[1] - -/datum/proc/GetExactComponent(c_type) - var/list/dc = datum_components - if(!dc) - return null - var/datum/component/C = dc[c_type] - if(C) - if(length(C)) - C = C[1] - if(C.type == c_type) - return C - return null - -/datum/proc/GetComponents(c_type) - var/list/dc = datum_components - if(!dc) - return null - . = dc[c_type] - if(!length(.)) - return list(.) - -/datum/proc/AddComponent(new_type, ...) - var/datum/component/nt = new_type - var/dm = initial(nt.dupe_mode) - var/dt = initial(nt.dupe_type) - - var/datum/component/old_comp - var/datum/component/new_comp - - if(ispath(nt)) - if(nt == /datum/component) - CRASH("[nt] attempted instantiation!") - if(!isnum(dm)) - CRASH("[nt]: Invalid dupe_mode ([dm])!") - if(dt && !ispath(dt)) - CRASH("[nt]: Invalid dupe_type ([dt])!") - else - new_comp = nt - nt = new_comp.type - - args[1] = src - - if(dm != COMPONENT_DUPE_ALLOWED) - if(!dt) - old_comp = GetExactComponent(nt) - else - old_comp = GetComponent(dt) - if(old_comp) - switch(dm) - if(COMPONENT_DUPE_UNIQUE) - if(!new_comp) - new_comp = new nt(arglist(args)) - if(!QDELETED(new_comp)) - old_comp.InheritComponent(new_comp, TRUE) - QDEL_NULL(new_comp) - if(COMPONENT_DUPE_HIGHLANDER) - if(!new_comp) - new_comp = new nt(arglist(args)) - if(!QDELETED(new_comp)) - new_comp.InheritComponent(old_comp, FALSE) - QDEL_NULL(old_comp) - if(COMPONENT_DUPE_UNIQUE_PASSARGS) - if(!new_comp) - var/list/arguments = args.Copy(2) - old_comp.InheritComponent(null, TRUE, arguments) - else - old_comp.InheritComponent(new_comp, TRUE) - else if(!new_comp) - new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal - else if(!new_comp) - new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal - - if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy - SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp) - return new_comp - return old_comp - -/datum/proc/LoadComponent(component_type, ...) - . = GetComponent(component_type) - if(!.) - return AddComponent(arglist(args)) - -/datum/component/proc/RemoveComponent() - if(!parent) - return - var/datum/old_parent = parent - PreTransfer() - _RemoveFromParent() - parent = null - SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src) - -/datum/proc/TakeComponent(datum/component/target) - if(!target || target.parent == src) - return - if(target.parent) - target.RemoveComponent() - target.parent = src - var/result = target.PostTransfer() - switch(result) - if(COMPONENT_INCOMPATIBLE) - var/c_type = target.type - qdel(target) - CRASH("Incompatible [c_type] transfer attempt to a [type]!") - if(target == AddComponent(target)) - target._JoinParent() - -/datum/proc/TransferComponents(datum/target) - var/list/dc = datum_components - if(!dc) - return - var/comps = dc[/datum/component] - if(islist(comps)) - for(var/datum/component/I in comps) - if(I.can_transfer) - target.TakeComponent(I) - else - var/datum/component/C = comps - if(C.can_transfer) - target.TakeComponent(comps) - -/datum/component/ui_host() - return parent +/datum/component + var/dupe_mode = COMPONENT_DUPE_HIGHLANDER + var/dupe_type + var/datum/parent + //only set to true if you are able to properly transfer this component + //At a minimum RegisterWithParent and UnregisterFromParent should be used + //Make sure you also implement PostTransfer for any post transfer handling + var/can_transfer = FALSE + +/datum/component/New(datum/P, ...) + parent = P + var/list/arguments = args.Copy(2) + if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE) + qdel(src, TRUE, TRUE) + CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]") + + _JoinParent(P) + +/datum/component/proc/_JoinParent() + var/datum/P = parent + //lazy init the parent's dc list + var/list/dc = P.datum_components + if(!dc) + P.datum_components = dc = list() + + //set up the typecache + var/our_type = type + for(var/I in _GetInverseTypeList(our_type)) + var/test = dc[I] + if(test) //already another component of this type here + var/list/components_of_type + if(!length(test)) + components_of_type = list(test) + dc[I] = components_of_type + else + components_of_type = test + if(I == our_type) //exact match, take priority + var/inserted = FALSE + for(var/J in 1 to components_of_type.len) + var/datum/component/C = components_of_type[J] + if(C.type != our_type) //but not over other exact matches + components_of_type.Insert(J, I) + inserted = TRUE + break + if(!inserted) + components_of_type += src + else //indirect match, back of the line with ya + components_of_type += src + else //only component of this type, no list + dc[I] = src + + RegisterWithParent() + +// If you want/expect to be moving the component around between parents, use this to register on the parent for signals +/datum/component/proc/RegisterWithParent() + return + +/datum/component/proc/Initialize(...) + return + +/datum/component/Destroy(force=FALSE, silent=FALSE) + if(!force && parent) + _RemoveFromParent() + if(!silent) + SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src) + parent = null + return ..() + +/datum/component/proc/_RemoveFromParent() + var/datum/P = parent + var/list/dc = P.datum_components + for(var/I in _GetInverseTypeList()) + var/list/components_of_type = dc[I] + if(length(components_of_type)) // + var/list/subtracted = components_of_type - src + if(subtracted.len == 1) //only 1 guy left + dc[I] = subtracted[1] //make him special + else + dc[I] = subtracted + else //just us + dc -= I + if(!dc.len) + P.datum_components = null + + UnregisterFromParent() + +/datum/component/proc/UnregisterFromParent() + return + +/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE) + if(QDELETED(src) || QDELETED(target)) + return + + var/list/procs = signal_procs + if(!procs) + signal_procs = procs = list() + if(!procs[target]) + procs[target] = list() + var/list/lookup = target.comp_lookup + if(!lookup) + target.comp_lookup = lookup = list() + + var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types) + for(var/sig_type in sig_types) + if(!override && procs[target][sig_type]) + stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning") + + procs[target][sig_type] = proctype + + if(!lookup[sig_type]) // Nothing has registered here yet + lookup[sig_type] = src + else if(lookup[sig_type] == src) // We already registered here + continue + else if(!length(lookup[sig_type])) // One other thing registered here + lookup[sig_type] = list(lookup[sig_type]=TRUE) + lookup[sig_type][src] = TRUE + else // Many other things have registered here + lookup[sig_type][src] = TRUE + + signal_enabled = TRUE + +/datum/proc/UnregisterSignal(datum/target, sig_type_or_types) + if(!target) + CRASH("[src] tried to unregister a signal without having a target.") + var/list/lookup = target.comp_lookup + if(!signal_procs || !signal_procs[target] || !lookup) + return + if(!islist(sig_type_or_types)) + sig_type_or_types = list(sig_type_or_types) + for(var/sig in sig_type_or_types) + switch(length(lookup[sig])) + if(2) + lookup[sig] = (lookup[sig]-src)[1] + if(1) + stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup") + if(src in lookup[sig]) + lookup -= sig + if(!length(lookup)) + target.comp_lookup = null + break + if(0) + lookup -= sig + if(!length(lookup)) + target.comp_lookup = null + break + else + lookup[sig] -= src + + signal_procs[target] -= sig_type_or_types + if(!signal_procs[target].len) + signal_procs -= target + +/datum/component/proc/InheritComponent(datum/component/C, i_am_original) + return + +/datum/component/proc/PreTransfer() + return + +/datum/component/proc/PostTransfer() + return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it + +/datum/component/proc/_GetInverseTypeList(our_type = type) + //we can do this one simple trick + var/current_type = parent_type + . = list(our_type, current_type) + //and since most components are root level + 1, this won't even have to run + while (current_type != /datum/component) + current_type = type2parent(current_type) + . += current_type + +/datum/proc/_SendSignal(sigtype, list/arguments) + var/target = comp_lookup[sigtype] + if(!length(target)) + var/datum/C = target + if(!C.signal_enabled) + return NONE + var/proctype = C.signal_procs[src][sigtype] + return NONE | CallAsync(C, proctype, arguments) + . = NONE + for(var/I in target) + var/datum/C = I + if(!C.signal_enabled) + continue + var/proctype = C.signal_procs[src][sigtype] + . |= CallAsync(C, proctype, arguments) + +// The type arg is casted so initial works, you shouldn't be passing a real instance into this +/datum/proc/GetComponent(datum/component/c_type) + if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED) + stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]") + var/list/dc = datum_components + if(!dc) + return null + . = dc[c_type] + if(length(.)) + return .[1] + +/datum/proc/GetExactComponent(c_type) + var/list/dc = datum_components + if(!dc) + return null + var/datum/component/C = dc[c_type] + if(C) + if(length(C)) + C = C[1] + if(C.type == c_type) + return C + return null + +/datum/proc/GetComponents(c_type) + var/list/dc = datum_components + if(!dc) + return null + . = dc[c_type] + if(!length(.)) + return list(.) + +/datum/proc/AddComponent(new_type, ...) + var/datum/component/nt = new_type + var/dm = initial(nt.dupe_mode) + var/dt = initial(nt.dupe_type) + + var/datum/component/old_comp + var/datum/component/new_comp + + if(ispath(nt)) + if(nt == /datum/component) + CRASH("[nt] attempted instantiation!") + else + new_comp = nt + nt = new_comp.type + + args[1] = src + + if(dm != COMPONENT_DUPE_ALLOWED) + if(!dt) + old_comp = GetExactComponent(nt) + else + old_comp = GetComponent(dt) + if(old_comp) + switch(dm) + if(COMPONENT_DUPE_UNIQUE) + if(!new_comp) + new_comp = new nt(arglist(args)) + if(!QDELETED(new_comp)) + old_comp.InheritComponent(new_comp, TRUE) + QDEL_NULL(new_comp) + if(COMPONENT_DUPE_HIGHLANDER) + if(!new_comp) + new_comp = new nt(arglist(args)) + if(!QDELETED(new_comp)) + new_comp.InheritComponent(old_comp, FALSE) + QDEL_NULL(old_comp) + if(COMPONENT_DUPE_UNIQUE_PASSARGS) + if(!new_comp) + var/list/arguments = args.Copy(2) + old_comp.InheritComponent(null, TRUE, arguments) + else + old_comp.InheritComponent(new_comp, TRUE) + else if(!new_comp) + new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal + else if(!new_comp) + new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal + + if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy + SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp) + return new_comp + return old_comp + +/datum/proc/LoadComponent(component_type, ...) + . = GetComponent(component_type) + if(!.) + return AddComponent(arglist(args)) + +/datum/component/proc/RemoveComponent() + if(!parent) + return + var/datum/old_parent = parent + PreTransfer() + _RemoveFromParent() + parent = null + SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src) + +/datum/proc/TakeComponent(datum/component/target) + if(!target || target.parent == src) + return + if(target.parent) + target.RemoveComponent() + target.parent = src + var/result = target.PostTransfer() + switch(result) + if(COMPONENT_INCOMPATIBLE) + var/c_type = target.type + qdel(target) + CRASH("Incompatible [c_type] transfer attempt to a [type]!") + + if(target == AddComponent(target)) + target._JoinParent() + +/datum/proc/TransferComponents(datum/target) + var/list/dc = datum_components + if(!dc) + return + var/comps = dc[/datum/component] + if(islist(comps)) + for(var/datum/component/I in comps) + if(I.can_transfer) + target.TakeComponent(I) + else + var/datum/component/C = comps + if(C.can_transfer) + target.TakeComponent(comps) + +/datum/component/ui_host() + return parent diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm index e9133244..6f289af1 100644 --- a/code/datums/components/anti_magic.dm +++ b/code/datums/components/anti_magic.dm @@ -2,12 +2,13 @@ var/magic = FALSE var/holy = FALSE var/psychic = FALSE + var/allowed_slots = ~ITEM_SLOT_BACKPACK var/charges = INFINITY var/blocks_self = TRUE var/datum/callback/reaction var/datum/callback/expire -/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire) +/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire) if(isitem(parent)) RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip) RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop) @@ -19,6 +20,8 @@ magic = _magic holy = _holy psychic = _psychic + if(_allowed_slots) + allowed_slots = _allowed_slots if(!isnull(_charges)) charges = _charges blocks_self = _blocks_self @@ -26,6 +29,9 @@ expire = _expire /datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot) + if(!CHECK_BITFIELD(allowed_slots, slotdefine2slotbit(slot))) //Check that the slot is valid for antimagic + UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC) + return RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE) /datum/component/anti_magic/proc/on_drop(datum/source, mob/user) diff --git a/code/datums/components/earprotection.dm b/code/datums/components/earprotection.dm index 20849437..9256c431 100644 --- a/code/datums/components/earprotection.dm +++ b/code/datums/components/earprotection.dm @@ -1,11 +1,11 @@ /datum/component/wearertargeting/earprotection signals = list(COMSIG_CARBON_SOUNDBANG) mobtype = /mob/living/carbon + proctype = .proc/reducebang /datum/component/wearertargeting/earprotection/Initialize(_valid_slots) . = ..() valid_slots = _valid_slots - callback = CALLBACK(src, .proc/reducebang) /datum/component/wearertargeting/earprotection/proc/reducebang(datum/source, list/reflist) reflist[1]-- diff --git a/code/datums/components/lockon_aiming.dm b/code/datums/components/lockon_aiming.dm index 1cf42496..045611ab 100644 --- a/code/datums/components/lockon_aiming.dm +++ b/code/datums/components/lockon_aiming.dm @@ -4,7 +4,7 @@ /datum/component/lockon_aiming dupe_mode = COMPONENT_DUPE_ALLOWED - var/lock_icon = 'icons/mob/blob.dmi' + var/lock_icon = 'icons/mob/cameramob.dmi' var/lock_icon_state = "marker" var/mutable_appearance/lock_appearance var/list/image/lock_images diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 43d13380..7297e8b7 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -261,8 +261,6 @@ if(the_event.timeout) addtimer(CALLBACK(src, .proc/clear_event, null, category), the_event.timeout, TIMER_UNIQUE|TIMER_OVERRIDE) - return the_event - /datum/component/mood/proc/clear_event(datum/source, category) var/datum/mood_event/event = mood_events[category] if(!event) diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm index a9d2c73b..b23fe362 100644 --- a/code/datums/components/orbiter.dm +++ b/code/datums/components/orbiter.dm @@ -1,8 +1,7 @@ /datum/component/orbiter + can_transfer = TRUE dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS var/list/orbiters - var/datum/callback/orbiter_spy - var/datum/callback/orbited_spy //radius: range to orbit at, radius of the circle formed by orbiting (in pixels) //clockwise: whether you orbit clockwise or anti clockwise @@ -14,8 +13,6 @@ return COMPONENT_INCOMPATIBLE orbiters = list() - orbiter_spy = CALLBACK(src, .proc/orbiter_move_react) - orbited_spy = CALLBACK(src, .proc/move_react) var/atom/master = parent master.orbiters = src @@ -25,7 +22,7 @@ /datum/component/orbiter/RegisterWithParent() var/atom/target = parent while(ismovableatom(target)) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react) target = target.loc RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, .proc/orbiter_glide_size_update) @@ -44,8 +41,6 @@ for(var/i in orbiters) end_orbit(i) orbiters = null - QDEL_NULL(orbiter_spy) - QDEL_NULL(orbited_spy) return ..() /datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, list/arguments) @@ -69,7 +64,7 @@ orbiter.orbiting.end_orbit(orbiter) orbiters[orbiter] = TRUE orbiter.orbiting = src - RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, orbiter_spy) + RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, .proc/orbiter_move_react) var/matrix/initial_transform = matrix(orbiter.transform) orbiters[orbiter] = initial_transform @@ -137,7 +132,7 @@ if(orbited?.loc && orbited.loc != newturf) // We want to know when anything holding us moves too var/atom/target = orbited.loc while(ismovableatom(target)) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy, TRUE) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react, TRUE) target = target.loc var/atom/curloc = master.loc diff --git a/code/datums/components/phantomthief.dm b/code/datums/components/phantomthief.dm new file mode 100644 index 00000000..7afe6499 --- /dev/null +++ b/code/datums/components/phantomthief.dm @@ -0,0 +1,30 @@ +//This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack. + +/datum/component/wearertargeting/phantomthief + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + signals = list(COMSIG_COMBAT_TOGGLED) + proctype = .proc/handlefilterstuff + var/filter_x + var/filter_y + var/filter_size + var/filter_color + +/datum/component/wearertargeting/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _color = "#E62111", list/_valid_slots = list(SLOT_GLASSES)) + . = ..() + if(. == COMPONENT_INCOMPATIBLE) + return + filter_x = _x + filter_y = _y + filter_size = _size + filter_color = _color + valid_slots = _valid_slots + +/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(datum/source, mob/user, combatmodestate) + if(!combatmodestate) + user.remove_filter("phantomthief") + else + user.add_filter("phantomthief", 4, list(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, color = filter_color)) + +/datum/component/wearertargeting/phantomthief/on_drop(datum/source, mob/user) + . = ..() + user.remove_filter("phantomthief") diff --git a/code/datums/components/signal_redirect.dm b/code/datums/components/signal_redirect.dm deleted file mode 100644 index db98d566..00000000 --- a/code/datums/components/signal_redirect.dm +++ /dev/null @@ -1,33 +0,0 @@ -// This should only be used by non components trying to listen to a signal -// If you use this inside a component I will replace your eyes with lemons ~ninjanomnom - -/datum/component/redirect - dupe_mode = COMPONENT_DUPE_ALLOWED - var/list/signals - var/datum/callback/turfchangeCB - -/datum/component/redirect/Initialize(list/_signals, flags=NONE) - //It's not our job to verify the right signals are registered here, just do it. - if(!LAZYLEN(_signals)) - return COMPONENT_INCOMPATIBLE - if(flags & REDIRECT_TRANSFER_WITH_TURF && isturf(parent)) - // If they also want to listen to the turf change then we need to set it up so both callbacks run - if(_signals[COMSIG_TURF_CHANGE]) - turfchangeCB = _signals[COMSIG_TURF_CHANGE] - if(!istype(turfchangeCB)) - . = COMPONENT_INCOMPATIBLE - CRASH("Redirect components must be given instanced callbacks, not proc paths.") - _signals[COMSIG_TURF_CHANGE] = CALLBACK(src, .proc/turf_change) - - signals = _signals - -/datum/component/redirect/RegisterWithParent() - for(var/signal in signals) - RegisterSignal(parent, signal, signals[signal]) - -/datum/component/redirect/UnregisterFromParent() - UnregisterSignal(parent, signals) - -/datum/component/redirect/proc/turf_change(datum/source, path, new_baseturfs, flags, list/transfers) - transfers += src - return turfchangeCB?.InvokeAsync(arglist(args)) diff --git a/code/datums/components/wearertargeting.dm b/code/datums/components/wearertargeting.dm index 0aa08311..feaa88f9 100644 --- a/code/datums/components/wearertargeting.dm +++ b/code/datums/components/wearertargeting.dm @@ -3,7 +3,7 @@ /datum/component/wearertargeting var/list/valid_slots = list() var/list/signals = list() - var/datum/callback/callback = CALLBACK(GLOBAL_PROC, .proc/pass) + var/proctype = .proc/pass var/mobtype = /mob/living /datum/component/wearertargeting/Initialize() @@ -14,13 +14,9 @@ /datum/component/wearertargeting/proc/on_equip(datum/source, mob/equipper, slot) if((slot in valid_slots) && istype(equipper, mobtype)) - RegisterSignal(equipper, signals, callback, TRUE) + RegisterSignal(equipper, signals, proctype, TRUE) else UnregisterSignal(equipper, signals) /datum/component/wearertargeting/proc/on_drop(datum/source, mob/user) - UnregisterSignal(user, signals) - -/datum/component/wearertargeting/Destroy() - QDEL_NULL(callback) //is likely to ourselves. - return ..() \ No newline at end of file + UnregisterSignal(user, signals) \ No newline at end of file diff --git a/code/datums/components/wet_floor.dm b/code/datums/components/wet_floor.dm index 526d482e..84b03203 100644 --- a/code/datums/components/wet_floor.dm +++ b/code/datums/components/wet_floor.dm @@ -1,206 +1,206 @@ -/datum/component/wet_floor - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS - can_transfer = TRUE - var/highest_strength = TURF_DRY - var/lube_flags = NONE //why do we have this? - var/list/time_left_list //In deciseconds. - var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor") - var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor") - var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static") - var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static") - var/current_overlay - var/permanent = FALSE - var/last_process = 0 - -/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist) - if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component - add_wet(arglist(argslist)) - else //We are being passed in a full blown component - var/datum/component/wet_floor/WF = newcomp //Lets make an assumption - if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us. - CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!") - return - for(var/i in WF.time_left_list) - add_wet(text2num(i), WF.time_left_list[i]) - -/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE) - if(!isopenturf(parent)) - return COMPONENT_INCOMPATIBLE - add_wet(strength, duration_minimum, duration_add, duration_maximum) - permanent = _permanent - if(!permanent) - START_PROCESSING(SSwet_floors, src) - addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization. - last_process = world.time - -/datum/component/wet_floor/RegisterWithParent() - RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet) - RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry) - -/datum/component/wet_floor/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY)) - -/datum/component/wet_floor/Destroy() - STOP_PROCESSING(SSwet_floors, src) - var/turf/T = parent - qdel(T.GetComponent(/datum/component/slippery)) - if(istype(T)) //If this is false there is so many things wrong with it. - T.cut_overlay(current_overlay) - else - stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!") - return ..() - -/datum/component/wet_floor/proc/update_overlay() - var/intended - if(!istype(parent, /turf/open/floor)) - intended = generic_turf_overlay - else - switch(highest_strength) - if(TURF_WET_PERMAFROST) - intended = permafrost_overlay - if(TURF_WET_ICE) - intended = ice_overlay - else - intended = water_overlay - if(current_overlay != intended) - var/turf/T = parent - T.cut_overlay(current_overlay) - T.add_overlay(intended) - current_overlay = intended - -/datum/component/wet_floor/proc/AfterSlip(mob/living/L) - if(highest_strength == TURF_WET_LUBE) - L.confused = max(L.confused, 8) - -/datum/component/wet_floor/proc/update_flags() - var/intensity - lube_flags = NONE - switch(highest_strength) - if(TURF_WET_WATER) - intensity = 60 - lube_flags = NO_SLIP_WHEN_WALKING - if(TURF_WET_LUBE) - intensity = 80 - lube_flags = SLIDE | GALOSHES_DONT_HELP - if(TURF_WET_ICE) - intensity = 120 - lube_flags = SLIDE | GALOSHES_DONT_HELP - if(TURF_WET_PERMAFROST) - intensity = 120 - lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP - else - qdel(parent.GetComponent(/datum/component/slippery)) - return - - var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip)) - S.intensity = intensity - S.lube_flags = lube_flags - -/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY) - for(var/i in time_left_list) - if(text2num(i) <= strength) - time_left_list[i] = max(0, time_left_list[i] - duration_decrease) - if(immediate) - check() - -/datum/component/wet_floor/proc/max_time_left() - . = 0 - for(var/i in time_left_list) - . = max(., time_left_list[i]) - -/datum/component/wet_floor/process() - var/turf/open/T = parent - var/diff = world.time - last_process - var/decrease = 0 - var/t = T.GetTemperature() - switch(t) - if(-INFINITY to T0C) - add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice! - if(T0C to T0C + 100) - decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio) - if(T0C + 100 to INFINITY) - decrease = INFINITY - decrease = max(0, decrease) - if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water! - for(var/obj/O in T.contents) - if(O.obj_flags & FROZEN) - O.make_unfrozen() - add_wet(TURF_WET_WATER, max_time_left()) - dry(null, TURF_WET_ICE) - dry(null, ALL, FALSE, decrease) - check() - last_process = world.time - -/datum/component/wet_floor/proc/update_strength() - highest_strength = 0 //Not bitflag. - for(var/i in time_left_list) - highest_strength = max(highest_strength, text2num(i)) - -/datum/component/wet_floor/proc/is_wet() - . = 0 - for(var/i in time_left_list) - . |= text2num(i) - -/datum/component/wet_floor/PreTransfer() - var/turf/O = parent - O.cut_overlay(current_overlay) - //That turf is no longer slippery, we're out of here - //Slippery components don't transfer due to callbacks - qdel(O.GetComponent(/datum/component/slippery)) - -/datum/component/wet_floor/PostTransfer() - if(!isopenturf(parent)) - return COMPONENT_INCOMPATIBLE - var/turf/T = parent - T.add_overlay(current_overlay) - //Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent) - update_flags() - - //NB it's possible we get deleted after this, due to inherit - -/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE) - var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST) - if(duration_minimum <= 0 || !type) - return FALSE - if(type in allowed_types) - return _do_add_wet(type, duration_minimum, duration_add, duration_maximum) - else - . = NONE - for(var/i in allowed_types) - if(!(type & i)) - continue - . |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum) - if(_permanent) - permanent = TRUE - STOP_PROCESSING(SSwet_floors, src) - -/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum) - var/time = 0 - if(LAZYACCESS(time_left_list, "[type]")) - time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum) - else - time = min(duration_minimum, duration_maximum) - LAZYSET(time_left_list, "[type]", time) - check(TRUE) - return TRUE - -/datum/component/wet_floor/proc/gc(on_init = FALSE) - if(!LAZYLEN(time_left_list)) - if(on_init) - var/turf/T = parent - stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].") - qdel(src) - return TRUE - return FALSE - -/datum/component/wet_floor/proc/check(force_update = FALSE) - var/changed = FALSE - for(var/i in time_left_list) - if(time_left_list[i] <= 0) - time_left_list -= i - changed = TRUE - if(changed || force_update) - update_strength() - update_overlay() - update_flags() - gc() +/datum/component/wet_floor + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + can_transfer = TRUE + var/highest_strength = TURF_DRY + var/lube_flags = NONE //why do we have this? + var/list/time_left_list //In deciseconds. + var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor") + var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor") + var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static") + var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static") + var/current_overlay + var/permanent = FALSE + var/last_process = 0 + +/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist) + if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component + add_wet(arglist(argslist)) + else //We are being passed in a full blown component + var/datum/component/wet_floor/WF = newcomp //Lets make an assumption + if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us. + CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!") + return + for(var/i in WF.time_left_list) + add_wet(text2num(i), WF.time_left_list[i]) + +/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE) + if(!isopenturf(parent)) + return COMPONENT_INCOMPATIBLE + add_wet(strength, duration_minimum, duration_add, duration_maximum) + permanent = _permanent + if(!permanent) + START_PROCESSING(SSwet_floors, src) + addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization. + last_process = world.time + +/datum/component/wet_floor/RegisterWithParent() + RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet) + RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry) + +/datum/component/wet_floor/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY)) + +/datum/component/wet_floor/Destroy() + STOP_PROCESSING(SSwet_floors, src) + var/turf/T = parent + qdel(T.GetComponent(/datum/component/slippery)) + if(istype(T)) //If this is false there is so many things wrong with it. + T.cut_overlay(current_overlay) + else + stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!") + return ..() + +/datum/component/wet_floor/proc/update_overlay() + var/intended + if(!istype(parent, /turf/open/floor)) + intended = generic_turf_overlay + else + switch(highest_strength) + if(TURF_WET_PERMAFROST) + intended = permafrost_overlay + if(TURF_WET_ICE) + intended = ice_overlay + else + intended = water_overlay + if(current_overlay != intended) + var/turf/T = parent + T.cut_overlay(current_overlay) + T.add_overlay(intended) + current_overlay = intended + +/datum/component/wet_floor/proc/AfterSlip(mob/living/L) + if(highest_strength == TURF_WET_LUBE) + L.confused = max(L.confused, 8) + +/datum/component/wet_floor/proc/update_flags() + var/intensity + lube_flags = NONE + switch(highest_strength) + if(TURF_WET_WATER) + intensity = 60 + lube_flags = NO_SLIP_WHEN_WALKING + if(TURF_WET_LUBE) + intensity = 80 + lube_flags = SLIDE | GALOSHES_DONT_HELP + if(TURF_WET_ICE) + intensity = 120 + lube_flags = SLIDE | GALOSHES_DONT_HELP + if(TURF_WET_PERMAFROST) + intensity = 120 + lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP + else + qdel(parent.GetComponent(/datum/component/slippery)) + return + + var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip)) + S.intensity = intensity + S.lube_flags = lube_flags + +/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY) + for(var/i in time_left_list) + if(text2num(i) <= strength) + time_left_list[i] = max(0, time_left_list[i] - duration_decrease) + if(immediate) + check() + +/datum/component/wet_floor/proc/max_time_left() + . = 0 + for(var/i in time_left_list) + . = max(., time_left_list[i]) + +/datum/component/wet_floor/process() + var/turf/open/T = parent + var/diff = world.time - last_process + var/decrease = 0 + var/t = T.GetTemperature() + switch(t) + if(-INFINITY to T0C) + add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice! + if(T0C to T0C + 100) + decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio) + if(T0C + 100 to INFINITY) + decrease = INFINITY + decrease = max(0, decrease) + if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water! + for(var/obj/O in T.contents) + if(O.obj_flags & FROZEN) + O.make_unfrozen() + add_wet(TURF_WET_WATER, max_time_left()) + dry(null, TURF_WET_ICE) + dry(null, ALL, FALSE, decrease) + check() + last_process = world.time + +/datum/component/wet_floor/proc/update_strength() + highest_strength = 0 //Not bitflag. + for(var/i in time_left_list) + highest_strength = max(highest_strength, text2num(i)) + +/datum/component/wet_floor/proc/is_wet() + . = 0 + for(var/i in time_left_list) + . |= text2num(i) + +/datum/component/wet_floor/PreTransfer() + var/turf/O = parent + O.cut_overlay(current_overlay) + //That turf is no longer slippery, we're out of here + //Slippery components don't transfer due to callbacks + qdel(O.GetComponent(/datum/component/slippery)) + +/datum/component/wet_floor/PostTransfer() + if(!isopenturf(parent)) + return COMPONENT_INCOMPATIBLE + var/turf/T = parent + T.add_overlay(current_overlay) + //Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent) + update_flags() + + //NB it's possible we get deleted after this, due to inherit + +/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE) + var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST) + if(duration_minimum <= 0 || !type) + return FALSE + if(type in allowed_types) + return _do_add_wet(type, duration_minimum, duration_add, duration_maximum) + else + . = NONE + for(var/i in allowed_types) + if(!(type & i)) + continue + . |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum) + if(_permanent) + permanent = TRUE + STOP_PROCESSING(SSwet_floors, src) + +/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum) + var/time = 0 + if(LAZYACCESS(time_left_list, "[type]")) + time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum) + else + time = min(duration_minimum, duration_maximum) + LAZYSET(time_left_list, "[type]", time) + check(TRUE) + return TRUE + +/datum/component/wet_floor/proc/gc(on_init = FALSE) + if(!LAZYLEN(time_left_list)) + if(on_init) + var/turf/T = parent + stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].") + qdel(src) + return TRUE + return FALSE + +/datum/component/wet_floor/proc/check(force_update = FALSE) + var/changed = FALSE + for(var/i in time_left_list) + if(time_left_list[i] <= 0) + time_left_list -= i + changed = TRUE + if(changed || force_update) + update_strength() + update_overlay() + update_flags() + gc() diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 9f9fe9de..65b1ce35 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -26,10 +26,10 @@ /datum/proc/vv_get_dropdown() . = list() . += "---" - .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=[REF(src)]" - .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=[REF(src)]" - .["Delete"] = "?_src_=vars;[HrefToken()];delete=[REF(src)]" - .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=[REF(src)]" + .["Call Proc"] = "?_src_=vars;[HrefToken()];proc_call=\ref[src]" + .["Mark Object"] = "?_src_=vars;[HrefToken()];mark_object=\ref[src]" + .["Delete"] = "?_src_=vars;[HrefToken()];delete=\ref[src]" + .["Show VV To Player"] = "?_src_=vars;[HrefToken(TRUE)];expose=\ref[src]" /datum/proc/on_reagent_change(changetype) @@ -54,7 +54,7 @@ return var/title = "" - var/refid = REF(D) + var/refid = "\ref[D]" var/icon/sprite var/hash @@ -62,8 +62,6 @@ if (!islist) type = D.type - - if(istype(D, /atom)) var/atom/AT = D if(AT.icon && AT.icon_state) @@ -411,7 +409,7 @@ /client/proc/vv_update_display(datum/D, span, content) - src << output("[span]:[content]", "variables[REF(D)].browser:replace_span") + src << output("[span]:[content]", "variables\ref[D].browser:replace_span") #define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing ) @@ -424,9 +422,9 @@ name = DA[name] //name is really the index until this line else value = DA[name] - header = "
  • (E) (C) (-) " + header = "
  • (E) (C) (-) " else - header = "
  • (E) (C) (M) " + header = "
  • (E) (C) (M) " else header = "
  • " @@ -441,7 +439,7 @@ #ifdef VARSICON var/icon/I = new/icon(value) var/rnd = rand(1,10000) - var/rname = "tmp[REF(I)][rnd].png" + var/rname = "tmp\ref[I][rnd].png" usr << browse_rsc(I, rname) item = "[VV_HTML_ENCODE(name)] = ([value]) " #else @@ -454,9 +452,9 @@ else if (istype(value, /datum)) var/datum/D = value if ("[D]" != "[D.type]") //if the thing as a name var, lets use it. - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]" + item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D] [D.type]" else - item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]" + item = "[VV_HTML_ENCODE(name)] [REF(value)] = [D.type]" else if (islist(value)) var/list/L = value @@ -474,9 +472,9 @@ items += debug_variable(key, val, level + 1, sanitize = sanitize) - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" else - item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" + item = "[VV_HTML_ENCODE(name)] = /list ([L.len])" else if (name in GLOB.bitfields) var/list/flags = list() @@ -588,7 +586,7 @@ var/prompt = alert("Do you want to grant [C] access to view this VV window? (they will not be able to edit or change anything nor open nested vv windows unless they themselves are an admin)", "Confirm", "Yes", "No") if (prompt != "Yes" || !usr.client) return - message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") + message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a VV window") log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [thing]") to_chat(C, "[usr.client.holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window") C.debug_variables(thing) diff --git a/code/datums/elements/squish.dm b/code/datums/elements/squish.dm new file mode 100644 index 00000000..823d391e --- /dev/null +++ b/code/datums/elements/squish.dm @@ -0,0 +1,28 @@ +#define SHORT 5/7 +#define TALL 7/5 + +/datum/element/squish + element_flags = ELEMENT_DETACH + +/datum/element/squish/Attach(datum/target, duration) + . = ..() + if(!iscarbon(target)) + return ELEMENT_INCOMPATIBLE + + var/mob/living/carbon/C = target + var/was_lying = (C.lying != 0) + addtimer(CALLBACK(src, .proc/Detach, C, was_lying), duration) + + C.transform = C.transform.Scale(TALL, SHORT) + +/datum/element/squish/Detach(mob/living/carbon/C, was_lying) + . = ..() + if(istype(C)) + var/is_lying = (C.lying != 0) + if(was_lying == is_lying) + C.transform = C.transform.Scale(SHORT, TALL) + else + C.transform = C.transform.Scale(TALL, SHORT) + +#undef SHORT +#undef TALL diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 237afdd5..86145409 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -223,7 +223,7 @@ /datum/status_effect/belligerent/proc/do_movement_toggle(force_damage) var/number_legs = owner.get_num_legs(FALSE) - if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check() && number_legs) + if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.anti_magic_check(chargecost = 0) && number_legs) if(force_damage || owner.m_intent != MOVE_INTENT_WALK) if(GLOB.ratvar_awakens) owner.Knockdown(20) @@ -316,7 +316,7 @@ if(owner.confused) owner.confused = 0 severity = 0 - else if(!owner.anti_magic_check() && owner.stat != DEAD && severity) + else if(!owner.anti_magic_check(chargecost = 0) && owner.stat != DEAD && severity) var/static/hum = get_sfx('sound/effects/screech.ogg') //same sound for every proc call if(owner.getToxLoss() > MANIA_DAMAGE_TO_CONVERT) if(is_eligible_servant(owner)) diff --git a/code/datums/status_effects/gas.dm b/code/datums/status_effects/gas.dm index dfe0a1d9..00417993 100644 --- a/code/datums/status_effects/gas.dm +++ b/code/datums/status_effects/gas.dm @@ -5,7 +5,6 @@ alert_type = /obj/screen/alert/status_effect/freon var/icon/cube var/can_melt = TRUE - var/datum/weakref/redirect_component /obj/screen/alert/status_effect/freon name = "Frozen Solid" @@ -13,7 +12,7 @@ icon_state = "frozen" /datum/status_effect/freon/on_apply() - redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) + RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) if(!owner.stat) to_chat(owner, "You become frozen in a cube!") cube = icon('icons/effects/freeze.dmi', "ice_cube") @@ -40,8 +39,7 @@ owner.cut_overlay(cube) owner.adjust_bodytemperature(100) owner.update_canmove() - qdel(redirect_component.resolve()) - redirect_component = null + UnregisterSignal(owner, COMSIG_LIVING_RESIST) /datum/status_effect/freon/watcher duration = 8 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5661ad71..f89d5e87 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -877,8 +877,7 @@ Proc for attack log creation, because really why not // Filter stuff /atom/movable/proc/add_filter(name,priority,list/params) - if(!filter_data) - filter_data = list() + LAZYINITLIST(filter_data) var/list/p = params.Copy() p["priority"] = priority filter_data[name] = p @@ -886,7 +885,7 @@ Proc for attack log creation, because really why not /atom/movable/proc/update_filters() filters = null - sortTim(filter_data,associative = TRUE) + filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE) for(var/f in filter_data) var/list/data = filter_data[f] var/list/arguments = data.Copy() diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm index 839cb035..efaa5eff 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_events.dm @@ -376,10 +376,11 @@ typepath = /datum/round_event/ghost_role/operative required_enemies = list(0,0,0,0,0,0,0,0,0,0) weight = 0 //This is changed in nuclearbomb.dm - occurances_max = 1 + occurances_max = 0 //Turned off. For now. requirements = list(10,10,10,10,10,10,10,10,10,10) //SECURE THAT DISK cost = 50 - chaos_min = 0.5 + chaos_min = 3 + map_blacklist = list("LayeniaStation.dmm") /datum/dynamic_ruleset/event/operative/get_weight() var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index ad563635..320dff0d 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -288,9 +288,9 @@ /obj/machinery/computer/camera_advanced/ratvar/CreateEye() ..() - eyeobj.visible_icon = 1 - eyeobj.icon = 'icons/obj/abductor.dmi' //in case you still had any doubts - eyeobj.icon_state = "camera_target" + eyeobj.visible_icon = TRUE + eyeobj.icon = 'icons/mob/cameramob.dmi' //in case you still had any doubts + eyeobj.icon_state = "generic_camera" /obj/machinery/computer/camera_advanced/ratvar/GrantActions(mob/living/carbon/user) ..() diff --git a/code/game/objects/effects/proximity.dm b/code/game/objects/effects/proximity.dm index 23977746..34d6497d 100644 --- a/code/game/objects/effects/proximity.dm +++ b/code/game/objects/effects/proximity.dm @@ -1,112 +1,112 @@ -/datum/proximity_monitor - var/atom/host //the atom we are tracking - var/atom/hasprox_receiver //the atom that will receive HasProximity calls. - var/atom/last_host_loc - var/list/checkers //list of /obj/effect/abstract/proximity_checkers - var/current_range - var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf - var/datum/component/movement_tracker - -/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) - checkers = list() - last_host_loc = _host.loc - ignore_if_not_on_turf = _ignore_if_not_on_turf - current_range = range - SetHost(_host) - -/datum/proximity_monitor/proc/SetHost(atom/H,atom/R) - if(R) - hasprox_receiver = R - else if(hasprox_receiver == host) //Default case - hasprox_receiver = H - host = H - last_host_loc = host.loc - if(movement_tracker) - QDEL_NULL(movement_tracker) - movement_tracker = host.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/HandleMove))) - SetRange(current_range,TRUE) - -/datum/proximity_monitor/Destroy() - host = null - last_host_loc = null - hasprox_receiver = null - QDEL_LIST(checkers) - QDEL_NULL(movement_tracker) - return ..() - -/datum/proximity_monitor/proc/HandleMove() - var/atom/_host = host - var/atom/new_host_loc = _host.loc - if(last_host_loc != new_host_loc) - last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers - var/curr_range = current_range - SetRange(curr_range, TRUE) - if(curr_range) - testing("HasProx: [host] -> [host]") - hasprox_receiver.HasProximity(host) //if we are processing, we're guaranteed to be a movable - -/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE) - if(!force_rebuild && range == current_range) - return FALSE - . = TRUE - - current_range = range - - var/list/checkers_local = checkers - var/old_checkers_len = checkers_local.len - - var/atom/_host = host - - var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host) - if(!isturf(loc_to_use)) //only check the host's loc - if(range) - var/obj/effect/abstract/proximity_checker/pc - if(old_checkers_len) - pc = checkers_local[old_checkers_len] - --checkers_local.len - QDEL_LIST(checkers_local) - else - pc = new(loc_to_use, src) - - checkers_local += pc //only check the host's loc - return - - var/list/turfs = RANGE_TURFS(range, loc_to_use) - var/turfs_len = turfs.len - var/old_checkers_used = min(turfs_len, old_checkers_len) - - //reuse what we can - for(var/I in 1 to old_checkers_len) - if(I <= old_checkers_used) - var/obj/effect/abstract/proximity_checker/pc = checkers_local[I] - pc.forceMove(turfs[I]) - else - qdel(checkers_local[I]) //delete the leftovers - - if(old_checkers_len < turfs_len) - //create what we lack - for(var/I in (old_checkers_used + 1) to turfs_len) - checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src) - else - checkers_local.Cut(old_checkers_used + 1, old_checkers_len) - -/obj/effect/abstract/proximity_checker - invisibility = INVISIBILITY_ABSTRACT - anchored = TRUE - var/datum/proximity_monitor/monitor - -/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor) - . = ..() - if(_monitor) - monitor = _monitor - else - stack_trace("proximity_checker created without host") - return INITIALIZE_HINT_QDEL - -/obj/effect/abstract/proximity_checker/Destroy() - monitor = null - return ..() - -/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM) - set waitfor = FALSE - monitor?.hasprox_receiver.HasProximity(AM) +/datum/proximity_monitor + var/atom/host //the atom we are tracking + var/atom/hasprox_receiver //the atom that will receive HasProximity calls. + var/atom/last_host_loc + var/list/checkers //list of /obj/effect/abstract/proximity_checkers + var/current_range + var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf + +/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) + checkers = list() + last_host_loc = _host.loc + ignore_if_not_on_turf = _ignore_if_not_on_turf + current_range = range + SetHost(_host) + +/datum/proximity_monitor/proc/SetHost(atom/H,atom/R) + if(H == host) + return + if(host) + UnregisterSignal(host, COMSIG_MOVABLE_MOVED) + if(R) + hasprox_receiver = R + else if(hasprox_receiver == host) //Default case + hasprox_receiver = H + host = H + RegisterSignal(host, COMSIG_MOVABLE_MOVED, .proc/HandleMove) + last_host_loc = host.loc + SetRange(current_range,TRUE) + +/datum/proximity_monitor/Destroy() + host = null + last_host_loc = null + hasprox_receiver = null + QDEL_LIST(checkers) + return ..() + +/datum/proximity_monitor/proc/HandleMove() + var/atom/_host = host + var/atom/new_host_loc = _host.loc + if(last_host_loc != new_host_loc) + last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers + var/curr_range = current_range + SetRange(curr_range, TRUE) + if(curr_range) + testing("HasProx: [host] -> [host]") + hasprox_receiver.HasProximity(host) //if we are processing, we're guaranteed to be a movable + +/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE) + if(!force_rebuild && range == current_range) + return FALSE + . = TRUE + + current_range = range + + var/list/checkers_local = checkers + var/old_checkers_len = checkers_local.len + + var/atom/_host = host + + var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host) + if(!isturf(loc_to_use)) //only check the host's loc + if(range) + var/obj/effect/abstract/proximity_checker/pc + if(old_checkers_len) + pc = checkers_local[old_checkers_len] + --checkers_local.len + QDEL_LIST(checkers_local) + else + pc = new(loc_to_use, src) + + checkers_local += pc //only check the host's loc + return + + var/list/turfs = RANGE_TURFS(range, loc_to_use) + var/turfs_len = turfs.len + var/old_checkers_used = min(turfs_len, old_checkers_len) + + //reuse what we can + for(var/I in 1 to old_checkers_len) + if(I <= old_checkers_used) + var/obj/effect/abstract/proximity_checker/pc = checkers_local[I] + pc.forceMove(turfs[I]) + else + qdel(checkers_local[I]) //delete the leftovers + + if(old_checkers_len < turfs_len) + //create what we lack + for(var/I in (old_checkers_used + 1) to turfs_len) + checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src) + else + checkers_local.Cut(old_checkers_used + 1, old_checkers_len) + +/obj/effect/abstract/proximity_checker + invisibility = INVISIBILITY_ABSTRACT + anchored = TRUE + var/datum/proximity_monitor/monitor + +/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor) + . = ..() + if(_monitor) + monitor = _monitor + else + stack_trace("proximity_checker created without host") + return INITIALIZE_HINT_QDEL + +/obj/effect/abstract/proximity_checker/Destroy() + monitor = null + return ..() + +/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM) + set waitfor = FALSE + monitor?.hasprox_receiver.HasProximity(AM) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 3bc00c84..a11eae78 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -78,6 +78,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/strip_delay = 40 //In deciseconds, how long an item takes to remove from another person var/breakouttime = 0 var/list/materials + var/reskinned = FALSE var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" var/list/species_exception = null // list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index 16104f0b..0eb97a8d 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -20,8 +20,8 @@ var/ghetto = FALSE lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - var/datum/component/mobhook var/datum/radial_menu/persistent/wiring_gui_menu + var/mob/listeningTo /obj/item/twohanded/rcl/attackby(obj/item/W, mob/user) if(istype(W, /obj/item/stack/cable_coil)) @@ -86,7 +86,7 @@ /obj/item/twohanded/rcl/Destroy() QDEL_NULL(loaded) last = null - QDEL_NULL(mobhook) + listeningTo = null QDEL_NULL(wiring_gui_menu) return ..() @@ -141,9 +141,8 @@ /obj/item/twohanded/rcl/dropped(mob/wearer) ..() - if(mobhook) - active = FALSE - QDEL_NULL(mobhook) + UnregisterSignal(wearer, COMSIG_MOVABLE_MOVED) + listeningTo = null last = null /obj/item/twohanded/rcl/attack_self(mob/user) @@ -158,13 +157,12 @@ break obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook) - if(to_hook) - if(mobhook && mobhook.parent != to_hook) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = to_hook.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger))) - else - QDEL_NULL(mobhook) + if(listeningTo == to_hook) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + RegisterSignal(to_hook, COMSIG_MOVABLE_MOVED, .proc/trigger) + listeningTo = to_hook /obj/item/twohanded/rcl/proc/trigger(mob/user) if(active) diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index e3752ab4..f3efb52d 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -39,7 +39,6 @@ /obj/item/defibrillator/loaded/Initialize() //starts with hicap . = ..() - paddles = make_paddles() cell = new(src) update_icon() return @@ -204,8 +203,8 @@ var/M = get(paddles, /mob) remove_paddles(M) QDEL_NULL(paddles) - . = ..() - update_icon() + QDEL_NULL(cell) + return ..() /obj/item/defibrillator/proc/deductcharge(chrgdeductamt) if(cell) @@ -246,7 +245,6 @@ /obj/item/defibrillator/compact/loaded/Initialize() . = ..() - paddles = make_paddles() cell = new(src) update_icon() @@ -258,7 +256,6 @@ /obj/item/defibrillator/compact/combat/loaded/Initialize() . = ..() - paddles = make_paddles() cell = new /obj/item/stock_parts/cell/infinite(src) update_icon() @@ -293,31 +290,28 @@ var/grab_ghost = FALSE var/tlimit = DEFIB_TIME_LIMIT * 10 - var/datum/component/mobhook + var/mob/listeningTo /obj/item/twohanded/shockpaddles/equipped(mob/user, slot) . = ..() - if(req_defib) - if (mobhook && mobhook.parent != user) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/check_range))) + if(!req_defib) + return + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/check_range) /obj/item/twohanded/shockpaddles/Moved() . = ..() check_range() /obj/item/twohanded/shockpaddles/proc/check_range() - if(!req_defib) + if(!req_defib || !defib) return if(!in_range(src,defib)) var/mob/living/L = loc if(istype(L)) to_chat(L, "[defib]'s paddles overextend and come out of your hands!") - L.temporarilyRemoveItemFromInventory(src,TRUE) else visible_message("[src] snap back into [defib].") - snap_back() + snap_back() /obj/item/twohanded/shockpaddles/proc/recharge(var/time) if(req_defib || !time) @@ -358,14 +352,14 @@ /obj/item/twohanded/shockpaddles/dropped(mob/user) if(!req_defib) return ..() - if (mobhook) - QDEL_NULL(mobhook) if(user) + UnregisterSignal(user, COMSIG_MOVABLE_MOVED) var/obj/item/twohanded/offhand/O = user.get_inactive_held_item() if(istype(O)) O.unwield() - to_chat(user, "The paddles snap back into the main unit.") - snap_back() + if(user != loc) + to_chat(user, "The paddles snap back into the main unit.") + snap_back() return unwield(user) /obj/item/twohanded/shockpaddles/proc/snap_back() diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index 0dbede18..8d386842 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -205,21 +205,25 @@ obj_flags |= EMAGGED /obj/item/geiger_counter/cyborg - var/datum/component/mobhook + var/mob/listeningTo /obj/item/geiger_counter/cyborg/equipped(mob/user) . = ..() - if (mobhook && mobhook.parent != user) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_RAD_ACT = CALLBACK(src, .proc/redirect_rad_act))) + if(listeningTo == user) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT) + RegisterSignal(user, COMSIG_ATOM_RAD_ACT, .proc/redirect_rad_act) + listeningTo = user /obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount) rad_act(amount) /obj/item/geiger_counter/cyborg/dropped() . = ..() - QDEL_NULL(mobhook) + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT) + listeningTo = null #undef RAD_LEVEL_NORMAL #undef RAD_LEVEL_MODERATE diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 463bc809..4a0fa867 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -35,6 +35,24 @@ drop_sound = 'sound/items/handling/multitool_drop.ogg' pickup_sound = 'sound/items/handling/multitool_pickup.ogg' +/obj/item/multitool/chaplain + name = "\improper hypertool" + desc = "Used for pulsing wires to test which to cut. Also emits microwaves to fry some brains!" + damtype = BRAIN + force = 18 + armour_penetration = 35 + hitsound = 'sound/effects/sparks4.ogg' + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + throw_speed = 3 + throw_range = 4 + throwforce = 10 + obj_flags = UNIQUE_RENAME + +/obj/item/multitool/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) + /obj/item/multitool/examine(mob/user) . = ..() if(selected_io) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 56237527..6a144a01 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -547,7 +547,9 @@ GENE SCANNER var/turf/location = user.loc if(!istype(location)) return + scan_turf(user, location) +/obj/item/analyzer/proc/scan_turf(mob/user, turf/location) var/datum/gas_mixture/environment = location.return_air() var/pressure = environment.return_pressure() @@ -658,6 +660,20 @@ GENE SCANNER amount += inaccurate return DisplayTimeText(max(1,amount)) +/obj/item/analyzer/ranged + desc = "A hand-held scanner which uses advanced spectroscopy and infrared readings to analyze gases as a distance. Alt-Click to use the built in barometer function." + name = "long-range analyzer" + icon = 'icons/obj/device.dmi' + icon_state = "ranged_analyzer" + +/obj/item/analyzer/ranged/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + . = ..() + if(target.tool_act(user, src, tool_behaviour)) + return + // Tool act didn't scan it, so let's get it's turf. + var/turf/location = get_turf(target) + scan_turf(user, location) + /proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src) var/icon = target user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].") diff --git a/code/game/objects/items/grenades/spawnergrenade.dm b/code/game/objects/items/grenades/spawnergrenade.dm index 466caf93..52ebe761 100644 --- a/code/game/objects/items/grenades/spawnergrenade.dm +++ b/code/game/objects/items/grenades/spawnergrenade.dm @@ -48,4 +48,10 @@ icon_state = "clustaur" item_state = "clustaur" deliveryamt = 5 - spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur \ No newline at end of file + spawner_type = /obj/item/reagent_containers/glass/beaker/waterbottle/wataur + +/obj/item/grenade/spawnergrenade/mimics + desc = "Months after their first arrival, compression tests were already successful and thus Kinaris created the first mimic bioweapon, a simple payload to quickly release a cluster of them." + name = "mimic delivery grenade" + spawner_type = /mob/living/simple_animal/hostile/hs13mimic + deliveryamt = 10 diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm index b5c7af4b..ce5810f5 100644 --- a/code/game/objects/items/his_grace.dm +++ b/code/game/objects/items/his_grace.dm @@ -29,7 +29,7 @@ . = ..() START_PROCESSING(SSprocessing, src) GLOB.poi_list += src - AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_POST_THROW = CALLBACK(src, .proc/move_gracefully))) + RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, .proc/move_gracefully) /obj/item/his_grace/Destroy() STOP_PROCESSING(SSprocessing, src) diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 93da4a30..9c597187 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -229,12 +229,12 @@ throwforce = 10 w_class = WEIGHT_CLASS_TINY obj_flags = UNIQUE_RENAME - var/reskinned = FALSE var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/nullrod/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/nullrod/suicide_act(mob/user) user.visible_message("[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!") @@ -248,7 +248,12 @@ if(GLOB.holy_weapon_type) return var/obj/item/holy_weapon - var/list/holy_weapons_list = subtypesof(/obj/item/nullrod) + var/list/holy_weapons_list = subtypesof(/obj/item/nullrod) + list( + /obj/item/twohanded/dualsaber/hypereutactic/chaplain, + /obj/item/gun/energy/laser/redtag/hitscan/chaplain, + /obj/item/multitool/chaplain, + /obj/item/melee/baseball_bat/chaplain + ) var/list/display_names = list() var/list/nullrod_icons = list() for(var/V in holy_weapons_list) @@ -289,6 +294,13 @@ return FALSE return TRUE +/obj/item/nullrod/proc/jedi_spin(mob/living/user) + for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH)) + user.setDir(i) + if(i == WEST) + user.emote("flip") + sleep(1) + /obj/item/nullrod/godhand icon_state = "disintegrate" item_state = "disintegrate" @@ -344,7 +356,6 @@ sharpness = IS_SHARP hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) if(attack_type == PROJECTILE_ATTACK) @@ -541,7 +552,6 @@ slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_HUGE attack_verb = list("smashed", "bashed", "hammered", "crunched") - total_mass = TOTAL_MASS_MEDIEVAL_WEAPON /obj/item/nullrod/chainsaw name = "chainsaw hand" @@ -606,6 +616,7 @@ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' slot_flags = ITEM_SLOT_BELT + force = 12 reach = 2 attack_verb = list("whipped", "lashed") hitsound = 'sound/weapons/chainhit.ogg' @@ -682,6 +693,44 @@ lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' +/obj/item/nullrod/claymore/bostaff/attack(mob/target, mob/living/user) + add_fingerprint(user) + if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) + to_chat(user, "You club yourself over the head with [src].") + user.Knockdown(60) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD) + else + user.take_bodypart_damage(2*force) + return + if(iscyborg(target)) + return ..() + if(!isliving(target)) + return ..() + var/mob/living/carbon/C = target + if(C.stat || C.health < 0 || C.staminaloss > 130 ) + to_chat(user, "It would be dishonorable to attack a foe while they cannot retaliate.") + return + if(user.a_intent == INTENT_DISARM) + if(!ishuman(target)) + return ..() + var/mob/living/carbon/human/H = target + var/list/fluffmessages = list("[user] clubs [H] with [src]!", \ + "[user] smacks [H] with the butt of [src]!", \ + "[user] broadsides [H] with [src]!", \ + "[user] smashes [H]'s head with [src]!", \ + "[user] beats [H] with front of [src]!", \ + "[user] twirls and slams [H] with [src]!") + H.visible_message("[pick(fluffmessages)]", \ + "[pick(fluffmessages)]") + playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, 1, -1) + H.adjustStaminaLoss(rand(12,18)) + if(prob(25)) + (INVOKE_ASYNC(src, .proc/jedi_spin, user)) + else + return ..() + /obj/item/nullrod/tribal_knife icon_state = "crysknife" item_state = "crysknife" @@ -695,7 +744,6 @@ hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") item_flags = SLOWS_WHILE_IN_HAND - total_mass = TOTAL_MASS_NORMAL_ITEM /obj/item/nullrod/tribal_knife/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index f74929ed..e6f03aaa 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -223,6 +223,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("sauna oven", /obj/structure/sauna_oven, 30, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 10, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 50, one_per_turf = TRUE, on_floor = TRUE),\ diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 14a8d793..6c3dbee7 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -1,439 +1,441 @@ -/* - * These absorb the functionality of the plant bag, ore satchel, etc - * They use the use_to_pickup, quick_gather, and quick_empty functions - * that were already defined in weapon/storage, but which had been - * re-implemented in other classes. - * - * Contains: - * Trash Bag - * Mining Satchel - * Plant Bag - * Sheet Snatcher - * Book Bag - * Biowaste Bag - * - * -Sayu - */ - -// Generic non-item -/obj/item/storage/bag - slot_flags = ITEM_SLOT_BELT - -/obj/item/storage/bag/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.allow_quick_gather = TRUE - STR.allow_quick_empty = TRUE - STR.display_numerical_stacking = TRUE - STR.click_gather = TRUE - -// ----------------------------- -// Trash bag -// ----------------------------- -/obj/item/storage/bag/trash - name = "trash bag" - desc = "It's the heavy-duty black polymer kind. Time to take out the trash!" - icon = 'icons/obj/janitor.dmi' - icon_state = "trashbag" - item_state = "trashbag" - lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' - - w_class = WEIGHT_CLASS_BULKY - var/insertable = TRUE - -/obj/item/storage/bag/trash/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_SMALL - STR.max_combined_w_class = 30 - STR.max_items = 30 - STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear)) - -/obj/item/storage/bag/trash/suicide_act(mob/user) - user.visible_message("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!") - playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1) - return (TOXLOSS) - -/obj/item/storage/bag/trash/update_icon() - if(contents.len == 0) - icon_state = "[initial(icon_state)]" - else if(contents.len < 12) - icon_state = "[initial(icon_state)]1" - else if(contents.len < 21) - icon_state = "[initial(icon_state)]2" - else icon_state = "[initial(icon_state)]3" - -/obj/item/storage/bag/trash/cyborg - insertable = FALSE - -/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) - if(insertable) - J.put_in_cart(src, user) - J.mybag=src - J.update_icon() - else - to_chat(user, "You are unable to fit your [name] into the [J.name].") - return - -/obj/item/storage/bag/trash/bluespace - name = "trash bag of holding" - desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage." - icon_state = "bluetrashbag" - item_flags = NO_MAT_REDEMPTION - -/obj/item/storage/bag/trash/bluespace/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 60 - STR.max_items = 60 - -/obj/item/storage/bag/trash/bluespace/cyborg - insertable = FALSE - -// ----------------------------- -// Mining Satchel -// ----------------------------- - -/obj/item/storage/bag/ore - name = "mining satchel" - desc = "This little bugger can be used to store and transport ores." - icon = 'icons/obj/mining.dmi' - icon_state = "satchel" - slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET - w_class = WEIGHT_CLASS_NORMAL - component_type = /datum/component/storage/concrete/stack - var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it - var/datum/component/mobhook - -/obj/item/storage/bag/ore/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.allow_quick_empty = TRUE - STR.can_hold = typecacheof(list(/obj/item/stack/ore)) - STR.max_w_class = WEIGHT_CLASS_HUGE - STR.max_combined_stack_amount = 50 - -/obj/item/storage/bag/ore/equipped(mob/user) - . = ..() - if (mobhook && mobhook.parent != user) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/Pickup_ores))) - -/obj/item/storage/bag/ore/dropped() - . = ..() - if (mobhook) - QDEL_NULL(mobhook) - -/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user) - var/show_message = FALSE - var/obj/structure/ore_box/box - var/turf/tile = user.loc - if (!isturf(tile)) - return - if (istype(user.pulling, /obj/structure/ore_box)) - box = user.pulling - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - if(STR) - for(var/A in tile) - if (!is_type_in_typecache(A, STR.can_hold)) - continue - if (box) - user.transferItemToLoc(A, box) - show_message = TRUE - else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE)) - show_message = TRUE - else - if(!spam_protection) - to_chat(user, "Your [name] is full and can't hold any more!") - spam_protection = TRUE - continue - if(show_message) - playsound(user, "rustle", 50, TRUE) - if (box) - user.visible_message("[user] offloads the ores beneath [user.p_them()] into [box].", \ - "You offload the ores beneath you into your [box].") - else - user.visible_message("[user] scoops up the ores beneath [user.p_them()].", \ - "You scoop up the ores beneath you with your [name].") - spam_protection = FALSE - -/obj/item/storage/bag/ore/cyborg - name = "cyborg mining satchel" - -/obj/item/storage/bag/ore/cyborg/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.allow_quick_empty = TRUE - STR.can_hold = typecacheof(list(/obj/item/stack/ore)) - STR.max_w_class = WEIGHT_CLASS_HUGE - STR.max_combined_stack_amount = 150 - -/obj/item/storage/bag/ore/large - name = "large mining satchel" - desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume." - -/obj/item/storage/bag/ore/large/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.allow_quick_empty = TRUE - STR.can_hold = typecacheof(list(/obj/item/stack/ore)) - STR.max_w_class = WEIGHT_CLASS_HUGE - STR.max_combined_stack_amount = 150 - -/obj/item/storage/bag/ore/holding //miners, your messiah has arrived - name = "mining satchel of holding" - desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures." - icon_state = "satchel_bspace" - -/obj/item/storage/bag/ore/holding/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.max_items = INFINITY - STR.max_combined_w_class = INFINITY - STR.max_combined_stack_amount = INFINITY - -// ----------------------------- -// Plant bag -// ----------------------------- - -/obj/item/storage/bag/plants - name = "plant bag" - icon = 'icons/obj/hydroponics/equipment.dmi' - icon_state = "plantbag" - w_class = WEIGHT_CLASS_TINY - resistance_flags = FLAMMABLE - -/obj/item/storage/bag/plants/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_NORMAL - STR.max_combined_w_class = 100 - STR.max_items = 100 - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)) - -//////// - -/obj/item/storage/bag/plants/portaseeder - name = "portable seed extractor" - desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant." - icon_state = "portaseeder" - -/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents() - set name = "Activate Seed Extraction" - set category = "Object" - set desc = "Activate to convert your plants into plantable seeds." - if(usr.stat || !usr.canmove || usr.restrained()) - return - for(var/obj/item/O in contents) - seedify(O, 1) - -// ----------------------------- -// Sheet Snatcher -// ----------------------------- -// Because it stacks stacks, this doesn't operate normally. -// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu - -/obj/item/storage/bag/sheetsnatcher - name = "sheet snatcher" - desc = "A patented Kinaris storage system designed for any kind of mineral sheet." - icon = 'icons/obj/mining.dmi' - icon_state = "sheetsnatcher" - - var/capacity = 300; //the number of sheets it can carry. - w_class = WEIGHT_CLASS_NORMAL - component_type = /datum/component/storage/concrete/stack - -/obj/item/storage/bag/sheetsnatcher/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.allow_quick_empty = TRUE - STR.can_hold = typecacheof(list(/obj/item/stack/sheet)) - STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood)) - STR.max_combined_stack_amount = 300 - -// ----------------------------- -// Sheet Snatcher (Cyborg) -// ----------------------------- - -/obj/item/storage/bag/sheetsnatcher/borg - name = "sheet snatcher 9000" - desc = "" - capacity = 500//Borgs get more because >specialization - -/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize() - . = ..() - var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) - STR.max_combined_stack_amount = 500 - -// ----------------------------- -// Book bag -// ----------------------------- - -/obj/item/storage/bag/books - name = "book bag" - desc = "A bag for books." - icon = 'icons/obj/library.dmi' - icon_state = "bookbag" - w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics - resistance_flags = FLAMMABLE - -/obj/item/storage/bag/books/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_NORMAL - STR.max_combined_w_class = 21 - STR.max_items = 7 - STR.display_numerical_stacking = FALSE - STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook)) - -/* - * Trays - Agouri - */ -/obj/item/storage/bag/tray - name = "tray" - icon = 'icons/obj/food/containers.dmi' - icon_state = "tray" - desc = "A metal tray to lay food on." - force = 5 - throwforce = 10 - throw_speed = 3 - throw_range = 5 - w_class = WEIGHT_CLASS_BULKY - flags_1 = CONDUCT_1 - materials = list(MAT_METAL=3000) - -/obj/item/storage/bag/tray/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_items = 15 //I want my sushi god damn it - STR.insert_preposition = "on" - STR.can_hold = typecacheof(list( - /obj/item/reagent_containers/food, - /obj/item/kitchen, - /obj/item/storage/box/donkpockets)) - -/obj/item/storage/bag/tray/pre_attack(atom/A, mob/living/user, params) - if(istype(A, /obj/structure/table) && user.a_intent == INTENT_HELP) //I want my tray god damn it - if(user.transferItemToLoc(src, get_turf(A))) - var/list/click_params = params2list(params) - if(!click_params || !click_params["icon-x"] || !click_params["icon-y"]) - return - pixel_x = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2) - pixel_y = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2) - return - ..() - -/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user) - . = ..() - // Drop all the things. All of them. - var/list/obj/item/oldContents = contents.Copy() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.quick_empty() - // Make each item scatter a bit - for(var/obj/item/I in oldContents) - spawn() - for(var/i = 1, i <= rand(1,2), i++) - if(I) - step(I, pick(NORTH,SOUTH,EAST,WEST)) - sleep(rand(2,4)) - - if(prob(50)) - playsound(M, 'sound/items/trayhit1.ogg', 50, 1) - else - playsound(M, 'sound/items/trayhit2.ogg', 50, 1) - - if(ishuman(M) || ismonkey(M)) - if(prob(10)) - M.Knockdown(40) - update_icon() - -/obj/item/storage/bag/tray/update_icon() - cut_overlays() - for(var/obj/item/I in contents) - var/mutable_appearance/MA = new (I) //I want my icons god damn it - MA.pixel_x = rand(-6, 6) - MA.pixel_y = rand(-6, 6) - add_overlay(MA) - -/obj/item/storage/bag/tray/Entered() - . = ..() - update_icon() - -/obj/item/storage/bag/tray/Exited() - . = ..() - update_icon() - -/* - * Chemistry bag - */ - -/obj/item/storage/bag/chemistry - name = "chemistry bag" - icon = 'icons/obj/chemical.dmi' - icon_state = "bag" - desc = "A bag for storing pills, patches, and bottles." - w_class = WEIGHT_CLASS_TINY - resistance_flags = FLAMMABLE - -/obj/item/storage/bag/chemistry/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 200 - STR.max_items = 50 - STR.insert_preposition = "in" - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack)) - -/* - * Biowaste bag (mostly for xenobiologists) - */ - -/obj/item/storage/bag/bio - name = "bio bag" - icon = 'icons/obj/chemical.dmi' - icon_state = "biobag" - desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." - w_class = WEIGHT_CLASS_TINY - resistance_flags = FLAMMABLE - -/obj/item/storage/bag/bio/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 200 - STR.max_items = 25 - STR.insert_preposition = "in" - STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)) - -/obj/item/storage/bag/bio/holding - name = "bio bag of holding" - icon = 'icons/obj/chemical.dmi' - icon_state = "bspace_biobag" - desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." - -/obj/item/storage/bag/bio/holding/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = INFINITY - STR.max_items = 100 - -/* - * Construction bag (for engineering, holds stock parts and electronics) - */ - -/obj/item/storage/bag/construction - name = "construction bag" - icon = 'icons/obj/tools.dmi' - icon_state = "construction_bag" - desc = "A bag for storing small construction components." - w_class = WEIGHT_CLASS_TINY - resistance_flags = FLAMMABLE - -/obj/item/storage/bag/construction/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 100 - STR.max_items = 50 - STR.max_w_class = WEIGHT_CLASS_SMALL - STR.insert_preposition = "in" - STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics)) +/* + * These absorb the functionality of the plant bag, ore satchel, etc + * They use the use_to_pickup, quick_gather, and quick_empty functions + * that were already defined in weapon/storage, but which had been + * re-implemented in other classes. + * + * Contains: + * Trash Bag + * Mining Satchel + * Plant Bag + * Sheet Snatcher + * Book Bag + * Biowaste Bag + * + * -Sayu + */ + +// Generic non-item +/obj/item/storage/bag + slot_flags = ITEM_SLOT_BELT + +/obj/item/storage/bag/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.allow_quick_gather = TRUE + STR.allow_quick_empty = TRUE + STR.display_numerical_stacking = TRUE + STR.click_gather = TRUE + +// ----------------------------- +// Trash bag +// ----------------------------- +/obj/item/storage/bag/trash + name = "trash bag" + desc = "It's the heavy-duty black polymer kind. Time to take out the trash!" + icon = 'icons/obj/janitor.dmi' + icon_state = "trashbag" + item_state = "trashbag" + lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' + + w_class = WEIGHT_CLASS_BULKY + var/insertable = TRUE + +/obj/item/storage/bag/trash/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_SMALL + STR.max_combined_w_class = 30 + STR.max_items = 30 + STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear)) + +/obj/item/storage/bag/trash/suicide_act(mob/user) + user.visible_message("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!") + playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1) + return (TOXLOSS) + +/obj/item/storage/bag/trash/update_icon() + if(contents.len == 0) + icon_state = "[initial(icon_state)]" + else if(contents.len < 12) + icon_state = "[initial(icon_state)]1" + else if(contents.len < 21) + icon_state = "[initial(icon_state)]2" + else icon_state = "[initial(icon_state)]3" + +/obj/item/storage/bag/trash/cyborg + insertable = FALSE + +/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) + if(insertable) + J.put_in_cart(src, user) + J.mybag=src + J.update_icon() + else + to_chat(user, "You are unable to fit your [name] into the [J.name].") + return + +/obj/item/storage/bag/trash/bluespace + name = "trash bag of holding" + desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage." + icon_state = "bluetrashbag" + item_flags = NO_MAT_REDEMPTION + +/obj/item/storage/bag/trash/bluespace/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = 60 + STR.max_items = 60 + +/obj/item/storage/bag/trash/bluespace/cyborg + insertable = FALSE + +// ----------------------------- +// Mining Satchel +// ----------------------------- + +/obj/item/storage/bag/ore + name = "mining satchel" + desc = "This little bugger can be used to store and transport ores." + icon = 'icons/obj/mining.dmi' + icon_state = "satchel" + slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET + w_class = WEIGHT_CLASS_NORMAL + component_type = /datum/component/storage/concrete/stack + var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it + var/mob/listeningTo + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE + +/obj/item/storage/bag/ore/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/ore)) + STR.max_w_class = WEIGHT_CLASS_HUGE + STR.max_combined_stack_amount = 50 + +/obj/item/storage/bag/ore/equipped(mob/user) + . = ..() + if(listeningTo == user) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores) + listeningTo = user + +/obj/item/storage/bag/ore/dropped() + . = ..() + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null + +/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user) + var/show_message = FALSE + var/obj/structure/ore_box/box + var/turf/tile = user.loc + if (!isturf(tile)) + return + if (istype(user.pulling, /obj/structure/ore_box)) + box = user.pulling + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + if(STR) + for(var/A in tile) + if (!is_type_in_typecache(A, STR.can_hold)) + continue + if (box) + user.transferItemToLoc(A, box) + show_message = TRUE + else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE)) + show_message = TRUE + else + if(!spam_protection) + to_chat(user, "Your [name] is full and can't hold any more!") + spam_protection = TRUE + continue + if(show_message) + playsound(user, "rustle", 50, TRUE) + if (box) + user.visible_message("[user] offloads the ores beneath [user.p_them()] into [box].", \ + "You offload the ores beneath you into your [box].") + else + user.visible_message("[user] scoops up the ores beneath [user.p_them()].", \ + "You scoop up the ores beneath you with your [name].") + spam_protection = FALSE + +/obj/item/storage/bag/ore/cyborg + name = "cyborg mining satchel" + +/obj/item/storage/bag/ore/cyborg/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/ore)) + STR.max_w_class = WEIGHT_CLASS_HUGE + STR.max_combined_stack_amount = 150 + +/obj/item/storage/bag/ore/large + name = "large mining satchel" + desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume." + +/obj/item/storage/bag/ore/large/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/ore)) + STR.max_w_class = WEIGHT_CLASS_HUGE + STR.max_combined_stack_amount = 150 + +/obj/item/storage/bag/ore/holding //miners, your messiah has arrived + name = "mining satchel of holding" + desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures." + icon_state = "satchel_bspace" + +/obj/item/storage/bag/ore/holding/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.max_items = INFINITY + STR.max_combined_w_class = INFINITY + STR.max_combined_stack_amount = INFINITY + +// ----------------------------- +// Plant bag +// ----------------------------- + +/obj/item/storage/bag/plants + name = "plant bag" + icon = 'icons/obj/hydroponics/equipment.dmi' + icon_state = "plantbag" + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + +/obj/item/storage/bag/plants/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 100 + STR.max_items = 100 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)) + +//////// + +/obj/item/storage/bag/plants/portaseeder + name = "portable seed extractor" + desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant." + icon_state = "portaseeder" + +/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents() + set name = "Activate Seed Extraction" + set category = "Object" + set desc = "Activate to convert your plants into plantable seeds." + if(usr.stat || !usr.canmove || usr.restrained()) + return + for(var/obj/item/O in contents) + seedify(O, 1) + +// ----------------------------- +// Sheet Snatcher +// ----------------------------- +// Because it stacks stacks, this doesn't operate normally. +// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu + +/obj/item/storage/bag/sheetsnatcher + name = "sheet snatcher" + desc = "A patented Kinaris storage system designed for any kind of mineral sheet." + icon = 'icons/obj/mining.dmi' + icon_state = "sheetsnatcher" + + var/capacity = 300; //the number of sheets it can carry. + w_class = WEIGHT_CLASS_NORMAL + component_type = /datum/component/storage/concrete/stack + +/obj/item/storage/bag/sheetsnatcher/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/sheet)) + STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood)) + STR.max_combined_stack_amount = 300 + +// ----------------------------- +// Sheet Snatcher (Cyborg) +// ----------------------------- + +/obj/item/storage/bag/sheetsnatcher/borg + name = "sheet snatcher 9000" + desc = "" + capacity = 500//Borgs get more because >specialization + +/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize() + . = ..() + var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack) + STR.max_combined_stack_amount = 500 + +// ----------------------------- +// Book bag +// ----------------------------- + +/obj/item/storage/bag/books + name = "book bag" + desc = "A bag for books." + icon = 'icons/obj/library.dmi' + icon_state = "bookbag" + w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics + resistance_flags = FLAMMABLE + +/obj/item/storage/bag/books/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 21 + STR.max_items = 7 + STR.display_numerical_stacking = FALSE + STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook)) + +/* + * Trays - Agouri + */ +/obj/item/storage/bag/tray + name = "serving tray" + icon = 'icons/obj/food/containers.dmi' + icon_state = "tray" + desc = "A metal tray to lay food on." + force = 5 + throwforce = 10 + throw_speed = 3 + throw_range = 5 + w_class = WEIGHT_CLASS_BULKY + flags_1 = CONDUCT_1 + materials = list(MAT_METAL=3000) + +/obj/item/storage/bag/tray/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows stuff such as Bowls, and normal sized foods, to fit. + STR.can_hold = typecacheof(list( + /obj/item/reagent_containers/food, + /obj/item/reagent_containers/glass, + /obj/item/clothing/mask/cigarette, + /obj/item/storage/fancy, + /obj/item/storage/box/matches, + /obj/item/trash, + /obj/item/lighter, + /obj/item/rollingpaper, + /obj/item/kitchen, + /obj/item/organ, + )) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools. + STR.insert_preposition = "on" + STR.max_items = 10 + +/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user) + . = ..() + // Drop all the things. All of them. + var/list/obj/item/oldContents = contents.Copy() + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY) + // Make each item scatter a bit + for(var/obj/item/I in oldContents) + INVOKE_ASYNC(src, .proc/do_scatter, I) + + if(prob(50)) + playsound(M, 'sound/items/trayhit1.ogg', 50, TRUE) + else + playsound(M, 'sound/items/trayhit2.ogg', 50, TRUE) + + if(ishuman(M)) + if(prob(10)) + M.Knockdown(40) + update_icon() + +/obj/item/storage/bag/tray/proc/do_scatter(obj/item/I) + for(var/i in 1 to rand(1,2)) + if(I) + step(I, pick(NORTH,SOUTH,EAST,WEST)) + sleep(rand(2,4)) + +/obj/item/storage/bag/tray/update_overlays() + . = ..() + for(var/obj/item/I in contents) + var/mutable_appearance/I_copy = new(I) + I_copy.plane = FLOAT_PLANE + I_copy.layer = FLOAT_LAYER + . += I_copy + +/obj/item/storage/bag/tray/Entered() + . = ..() + update_icon() + +/obj/item/storage/bag/tray/Exited() + . = ..() + update_icon() + +/* + * Chemistry bag + */ + +/obj/item/storage/bag/chemistry + name = "chemistry bag" + icon = 'icons/obj/chemical.dmi' + icon_state = "bag" + desc = "A bag for storing pills, patches, and bottles." + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + +/obj/item/storage/bag/chemistry/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = 200 + STR.max_items = 50 + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack)) + +/* + * Biowaste bag (mostly for xenobiologists) + */ + +/obj/item/storage/bag/bio + name = "bio bag" + icon = 'icons/obj/chemical.dmi' + icon_state = "biobag" + desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + +/obj/item/storage/bag/bio/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = 200 + STR.max_items = 25 + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)) + +/obj/item/storage/bag/bio/holding + name = "bio bag of holding" + icon = 'icons/obj/chemical.dmi' + icon_state = "bspace_biobag" + desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." + +/obj/item/storage/bag/bio/holding/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = INFINITY + STR.max_items = 100 + +/* + * Construction bag (for engineering, holds stock parts and electronics) + */ + +/obj/item/storage/bag/construction + name = "construction bag" + icon = 'icons/obj/tools.dmi' + icon_state = "construction_bag" + desc = "A bag for storing small construction components." + w_class = WEIGHT_CLASS_TINY + resistance_flags = FLAMMABLE + +/obj/item/storage/bag/construction/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_combined_w_class = 100 + STR.max_items = 50 + STR.max_w_class = WEIGHT_CLASS_SMALL + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics)) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index f76c1a27..0196daee 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -86,7 +86,7 @@ new /obj/item/multitool(src) new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange")) new /obj/item/extinguisher/mini(src) - new /obj/item/analyzer(src) + new /obj/item/analyzer/ranged(src) //much roomier now that we've managed to remove two tools /obj/item/storage/belt/utility/full/PopulateContents() diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index 0b6bc6af..bbfa5c29 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -849,18 +849,20 @@ righthand_file = 'icons/mob/inhands/items_righthand.dmi' slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_SMALL - var/datum/component/mobhook + var/mob/listeningTo var/zoom_out_amt = 6 var/zoom_amt = 10 +/obj/item/twohanded/binoculars/Destroy() + listeningTo = null + return ..() + /obj/item/twohanded/binoculars/wield(mob/user) . = ..() if(!wielded) return - if(QDELETED(mobhook)) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/unwield))) - else - user.TakeComponent(mobhook) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/unwield) + listeningTo = user user.visible_message("[user] holds [src] up to [user.p_their()] eyes.","You hold [src] up to your eyes.") item_state = "binoculars_wielded" user.regenerate_icons() @@ -884,7 +886,8 @@ /obj/item/twohanded/binoculars/unwield(mob/user) . = ..() - mobhook.RemoveComponent() + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null user.visible_message("[user] lowers [src].","You lower [src].") item_state = "binoculars" user.regenerate_icons() diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index e3861fda..4f64d825 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -531,6 +531,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 var/homerun_able = 0 total_mass = 2.7 //a regular wooden major league baseball bat weighs somewhere between 2 to 3.4 pounds, according to google +/obj/item/melee/baseball_bat/chaplain + name = "blessed baseball bat" + desc = "There ain't a cult in the league that can withstand a swatter." + force = 14 + throwforce = 14 + obj_flags = UNIQUE_RENAME + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + +/obj/item/melee/baseball_bat/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) + /obj/item/melee/baseball_bat/homerun name = "home run bat" desc = "This thing looks dangerous... Dangerously good at baseball, that is." diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index b194548f..e359325d 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -271,7 +271,7 @@ icon_state = "sandstone" mineral = /obj/item/stack/sheet/mineral/sandstone walltype = /turf/closed/wall/mineral/sandstone - canSmoothWith = list(/obj/structure/falsewall/sandstone, /turf/closed/wall/mineral/sandstone) + canSmoothWith = list(/obj/structure/falsewall/sandstone, /turf/closed/wall/mineral/sandstone, /obj/structure/window/fulltile) /obj/structure/falsewall/wood name = "wooden wall" diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 07d4801b..92210c43 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -290,6 +290,14 @@ icon = 'icons/obj/statuelarge.dmi' icon_state = "venus" +/obj/structure/statue/sandstone/abs + max_integrity = 300 + anchored = TRUE + name = "ancient statue" + desc = "An ancient statue, representing one of the gods. It almost seems like it's alive." + icon = 'icons/obj/statue_egypty.dmi' + icon_state = "abs" + /////////////////////snow///////////////////////////////////////// /obj/structure/statue/snow diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index b3c19334..9c1859df 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -65,6 +65,8 @@ var/mob/M = AM if(M.mind in immune_minds) return + if(M.anti_magic_check()) + flare() if(charges <= 0) return flare() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 4b6b0689..ca698d44 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -516,7 +516,9 @@ /obj/machinery/door/airlock/hatch, /obj/machinery/door/airlock/engineering/glass/critical, /obj/machinery/door/airlock/atmos, - /obj/machinery/door/airlock/highsecurity,) + /obj/machinery/door/airlock/highsecurity, + /turf/closed/wall/mineral/sandstone, + /obj/structure/falsewall/sandstone,) // canSmoothWith = list(/obj/structure/window/fulltile, /obj/structure/window/reinforced/fulltile, /obj/structure/window/reinforced/tinted/fulltile, /obj/structure/window/plasma/fulltile, /obj/structure/window/plasma/reinforced/fulltile) glass_amount = 2 diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index f75772a2..11850f81 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -260,3 +260,29 @@ icon = 'icons/obj/clockwork_objects.dmi' icon_state = "clockwork_floor" floor_tile = /obj/item/stack/tile/bronze + +/turf/open/floor/concrete/ + name = "concrete" + icon = 'icons/turf/floors.dmi' + icon_state = "concrete" + baseturfs = /turf/open/floor/plating/asteroid + +/turf/open/floor/concrete/smooth + icon_state = "concrete2" + +/turf/open/floor/cobble/side + icon_state = "cobble_side" + +/turf/open/floor/cobble/corner + icon_state = "cobble_corner" + +/turf/open/floor/cobble + name = "cobblestone path" + desc = "A simple but beautiful path made of various sized stones." + icon = 'icons/turf/floors.dmi' + icon_state = "cobble" + baseturfs = /turf/open/floor/plating/asteroid + footstep = FOOTSTEP_FLOOR + barefootstep = FOOTSTEP_HARD_BAREFOOT + clawfootstep = FOOTSTEP_HARD_CLAW + heavyfootstep = FOOTSTEP_GENERIC_HEAVY \ No newline at end of file diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm index b37b5ec6..1e994b01 100644 --- a/code/game/turfs/simulated/wall/mineral_walls.dm +++ b/code/game/turfs/simulated/wall/mineral_walls.dm @@ -49,7 +49,7 @@ icon_state = "sandstone" sheet_type = /obj/item/stack/sheet/mineral/sandstone explosion_block = 0 - canSmoothWith = list(/turf/closed/wall/mineral/sandstone, /obj/structure/falsewall/sandstone) + canSmoothWith = list(/turf/closed/wall/mineral/sandstone, /obj/structure/falsewall/sandstone, /obj/structure/window/fulltile) /turf/closed/wall/mineral/uranium article = "a" diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index d415e230..dba5bd75 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -72,6 +72,9 @@ /turf/open/space/Assimilate_Air() return +/turf/open/space/remove_air(amount) + return null + /turf/open/space/proc/update_starlight() if(CONFIG_GET(flag/starlight)) for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm diff --git a/code/game/world.dm b/code/game/world.dm index 5bd39779..8ef4d371 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -108,6 +108,7 @@ GLOBAL_VAR(restart_counter) GLOB.world_game_log = "[GLOB.log_directory]/game.log" GLOB.world_virus_log = "[GLOB.log_directory]/virus.log" + GLOB.world_asset_log = "[GLOB.log_directory]/asset.log" GLOB.world_attack_log = "[GLOB.log_directory]/attack.log" GLOB.world_pda_log = "[GLOB.log_directory]/pda.log" GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log" diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 13ee6a08..17b7668e 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -107,7 +107,7 @@ if(text2num(duration) > 0) expires = " The ban is for [duration] minutes and expires on [expiration] (server time)." else - expires = " The is a permanent ban." + expires = " This is a permanent ban." var/desc = "\nReason: You, or another user of this computer or connection ([pkey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban (BanID #[banid]) was applied by [akey] on [bantime] during round ID [ban_round_id], [expires]" diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 3f1c437f..40fbeb1f 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -110,7 +110,7 @@ if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)) to_chat(user, "AUTHENTICATION FAILURE. ACCESS DENIED.") return FALSE - if(!user.onSyndieBase()) + if(!user.onSyndieBase() && !user.mind.has_antag_datum(/datum/antagonist/nukeop/lone,TRUE)) to_chat(user, "[src] is out of range! It can only be used at your base!") return FALSE return TRUE diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index 603dd433..ca336db4 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -343,8 +343,8 @@ if(QDELETED(G)) return - if(istype(C.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "Your target seems to have some sort of protective headgear on, blocking the message from being sent!") + if(C.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "Your target seems to have some sort of tinfoil protection on, blocking the message from being sent!") return G.mind_control(command, user) @@ -520,10 +520,10 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user) if(L.incapacitated(TRUE, TRUE)) - if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "The specimen's protective headgear is interfering with the sleep inducement!") - L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] headgear protected [L.p_them()]!", \ - "You feel a strange wave of heavy drowsiness wash over you, but your headgear deflects most of it!") + if(L.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "The specimen's tinfoil protection is interfering with the sleep inducement!") + L.visible_message("[user] tried to induced sleep in [L] with [src], but [L.p_their()] tinfoil protected [L.p_them()]!", \ + "You feel a strange wave of heavy drowsiness wash over you, but your tinfoil protection deflects most of it!") L.drowsyness += 2 return L.visible_message("[user] has induced sleep in [L] with [src]!", \ @@ -532,10 +532,10 @@ Congratulations! You are now trained for invasive xenobiology research!"} L.Sleeping(1200) log_combat(user, L, "put to sleep") else - if(istype(L.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - to_chat(user, "The specimen's protective headgear is completely blocking our sleep inducement methods!") - L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] headgear completely protected [L.p_them()]!", \ - "Any sense of drowsiness is quickly diminished as your headgear deflects the effects!") + if(L.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "The specimen's tinfoil protection is completely blocking our sleep inducement methods!") + L.visible_message("[user] tried to induce sleep in [L] with [src], but [L.p_their()] tinfoil completely protected [L.p_them()]!", \ + "Any sense of drowsiness is quickly diminished as your tinfoil protection deflects the effects!") return L.drowsyness += 1 to_chat(user, "Sleep inducement works fully only on stunned specimens! ") diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 00e48cb1..9e0a2b46 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -17,9 +17,9 @@ /obj/machinery/computer/camera_advanced/abductor/CreateEye() ..() - eyeobj.visible_icon = 1 - eyeobj.icon = 'icons/obj/abductor.dmi' - eyeobj.icon_state = "camera_target" + eyeobj.visible_icon = TRUE + eyeobj.icon = 'icons/mob/cameramob.dmi' + eyeobj.icon_state = "generic_camera" /obj/machinery/computer/camera_advanced/abductor/GrantActions(mob/living/carbon/user) ..() diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index 30b82398..6ab1e58c 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -178,8 +178,8 @@ c.console = src /obj/machinery/abductor/console/proc/AddSnapshot(mob/living/carbon/human/target) - if(istype(target.get_item_by_slot(SLOT_HEAD), /obj/item/clothing/head/foilhat)) - say("Subject wearing specialized protective headgear, unable to get a proper scan!") + if(target.anti_magic_check(FALSE, FALSE, TRUE, 0)) + say("Subject wearing specialized protective tinfoil gear, unable to get a proper scan!") return var/datum/icon_snapshot/entry = new entry.name = target.name diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index 57ae1d4c..8bcf019a 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -9,7 +9,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) name = "Blob Overmind" real_name = "Blob Overmind" desc = "The overmind. It controls the blob." - icon = 'icons/mob/blob.dmi' + icon = 'icons/mob/cameramob.dmi' icon_state = "marker" mouse_opacity = MOUSE_OPACITY_ICON move_on_shuttle = 1 diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm index 386a463a..93d1e2af 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_spear.dm @@ -35,7 +35,7 @@ /obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user) . = ..() - if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check() && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead + if(!QDELETED(target) && target.stat != DEAD && !target.anti_magic_check(chargecost = 0) && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar if(issilicon(target)) target.visible_message("[target] shudders violently at [src]'s touch!", "ERROR: Temperature rising!") diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm index f44f67e9..fe6fe72d 100644 --- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm +++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm @@ -190,8 +190,8 @@ for(var/mob/living/L in range(1, src)) if(is_servant_of_ratvar(L)) continue - if(L.anti_magic_check()) - var/atom/I = L.anti_magic_check() + var/atom/I = L.anti_magic_check() + if(I) if(isitem(I)) L.visible_message("Strange energy flows into [L]'s [I.name]!", \ "Your [I.name] shields you from [src]!") diff --git a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm index bf50ed2b..31632b22 100644 --- a/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm +++ b/code/modules/antagonists/clockcult/clock_structures/ocular_warden.dm @@ -60,7 +60,7 @@ else if(isliving(target)) var/mob/living/L = target - if(!L.anti_magic_check()) + if(!L.anti_magic_check(chargecost = 0)) if(isrevenant(L)) var/mob/living/simple_animal/revenant/R = L if(R.revealed) diff --git a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm index 10c68b60..1158b02a 100644 --- a/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm +++ b/code/modules/antagonists/clockcult/clock_structures/taunting_trail.dm @@ -53,7 +53,7 @@ /obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L) if(istype(L) && !is_servant_of_ratvar(L)) - if(!L.anti_magic_check()) + if(!L.anti_magic_check(chargecost = 0)) L.confused = min(L.confused + 15, 50) L.dizziness = min(L.dizziness + 15, 50) if(L.confused >= 25) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 48a9879c..82d78480 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -62,8 +62,8 @@ Runes can either be invoked by one's self or with many different cultists. Each if(do_after(user, 15, target = src)) to_chat(user, "You carefully erase the [lowertext(cultist_name)] rune.") qdel(src) - else if(istype(I, /obj/item/nullrod)) - user.say("BEGONE FOUL MAGIKS!!", forced = "nullrod") + else if(istype(I, /obj/item/storage/book/bible) || istype(I, /obj/item/nullrod)) + user.say("BEGONE FOUL MAGICKS!!", forced = "bible") to_chat(user, "You disrupt the magic of [src] with [I].") qdel(src) @@ -238,7 +238,7 @@ structure_check() searches for nearby cultist structures required for the invoca to_chat(M, "You need at least two invokers to convert [convertee]!") log_game("Offer rune failed - tried conversion with one invoker") return 0 - if(convertee.anti_magic_check(TRUE, TRUE, FALSE, 0)) //Not chargecost because it can be spammed + if(convertee.anti_magic_check(TRUE, TRUE, chargecost = 0)) //Not major because it can be spammed for(var/M in invokers) to_chat(M, "Something is shielding [convertee]'s mind!") log_game("Offer rune failed - convertee had anti-magic") @@ -772,7 +772,7 @@ structure_check() searches for nearby cultist structures required for the invoca set_light(6, 1, color) for(var/mob/living/L in viewers(T)) if(!iscultist(L) && L.blood_volume) - var/atom/I = L.anti_magic_check() + var/atom/I = L.anti_magic_check(chargecost = 0) if(I) if(isitem(I)) to_chat(L, "[I] suddenly burns hotly before returning to normal!") @@ -802,7 +802,7 @@ structure_check() searches for nearby cultist structures required for the invoca set_light(6, 1, color) for(var/mob/living/L in viewers(T)) if(!iscultist(L) && L.blood_volume) - if(L.anti_magic_check()) + if(L.anti_magic_check(chargecost = 0)) continue L.take_overall_damage(tick_damage*multiplier, tick_damage*multiplier) if(is_servant_of_ratvar(L)) diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm index 9be21053..a9992d05 100644 --- a/code/modules/antagonists/disease/disease_mob.dm +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -9,7 +9,7 @@ the new instance inside the host to be updated to the template's stats. name = "Sentient Disease" real_name = "Sentient Disease" desc = "" - icon = 'icons/mob/blob.dmi' + icon = 'icons/mob/cameramob.dmi' icon_state = "marker" mouse_opacity = MOUSE_OPACITY_ICON move_on_shuttle = FALSE @@ -31,7 +31,6 @@ the new instance inside the host to be updated to the template's stats. var/browser_open = FALSE var/mob/living/following_host - var/datum/component/redirect/move_listener var/list/disease_instances var/list/hosts //this list is associative, affected_mob -> disease_instance var/datum/disease/advance/sentient_disease/disease_template @@ -260,16 +259,10 @@ the new instance inside the host to be updated to the template's stats. refresh_adaptation_menu() /mob/camera/disease/proc/set_following(mob/living/L) + if(following_host) + UnregisterSignal(following_host, COMSIG_MOVABLE_MOVED) + RegisterSignal(L, COMSIG_MOVABLE_MOVED, .proc/follow_mob) following_host = L - if(!move_listener) - move_listener = L.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/follow_mob))) - else - if(L) - L.TakeComponent(move_listener) - if(QDELING(move_listener)) - move_listener = null - else - QDEL_NULL(move_listener) follow_mob() /mob/camera/disease/proc/follow_next(reverse = FALSE) diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index 2fa5306c..a3984803 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -65,7 +65,7 @@ if(target.anti_magic_check(FALSE, TRUE)) to_chat(src, "Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!") target.visible_message("[target] slumps onto the ground.", \ - "Violets lights, dancing in your vision, receding--") + "Violet lights, dancing in your vision, receding--") draining = FALSE return var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY) @@ -112,7 +112,8 @@ action_background_icon_state = "bg_revenant" notice = "revennotice" boldnotice = "revenboldnotice" - + holy_check = TRUE + tinfoil_check = FALSE /obj/effect/proc_holder/spell/aoe_turf/revenant clothes_req = 0 diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm index 89d8de28..3e05b8d9 100644 --- a/code/modules/antagonists/revenant/revenant_blight.dm +++ b/code/modules/antagonists/revenant/revenant_blight.dm @@ -12,8 +12,8 @@ disease_flags = CURABLE permeability_mod = 1 severity = DISEASE_SEVERITY_DANGEROUS - var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects. - var/datum/mood_event/revenant_blight/depression + var/finalstage = FALSE //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects. + var/depression = FALSE /datum/disease/revblight/cure() if(affected_mob) @@ -44,7 +44,8 @@ affected_mob.emote("pale") if(3) if(!depression) - depression = SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight) + SEND_SIGNAL(affected_mob, COMSIG_ADD_MOOD_EVENT, "rev_blight", /datum/mood_event/revenant_blight) + depression = TRUE SEND_SIGNAL(affected_mob, COMSIG_DECREASE_SANITY, 0.12, SANITY_CRAZY) if(prob(10)) affected_mob.emote(pick("pale","shiver")) diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index a023e0e3..2fbb1095 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -1,235 +1,239 @@ -/obj/item/assembly/infra - name = "infrared emitter" - desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted." - icon_state = "infrared" - materials = list(MAT_METAL=1000, MAT_GLASS=500) - is_position_sensitive = TRUE - - var/on = FALSE - var/visible = FALSE - var/maxlength = 8 - var/list/obj/effect/beam/i_beam/beams - var/olddir = 0 - var/datum/component/redirect/listener - var/hearing_range = 3 - -/obj/item/assembly/infra/Initialize() - . = ..() - beams = list() - START_PROCESSING(SSobj, src) - -/obj/item/assembly/infra/ComponentInitialize() - . = ..() - AddComponent( - /datum/component/simple_rotation, - ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS, - null, - null, - CALLBACK(src,.proc/after_rotation) - ) - -/obj/item/assembly/infra/proc/after_rotation() - refreshBeam() - -/obj/item/assembly/infra/Destroy() - STOP_PROCESSING(SSobj, src) - QDEL_NULL(listener) - QDEL_LIST(beams) - . = ..() - -/obj/item/assembly/infra/examine(mob/user) - . = ..() - . += "The infrared trigger is [on?"on":"off"]." - -/obj/item/assembly/infra/activate() - if(!..()) - return FALSE//Cooldown check - on = !on - refreshBeam() - update_icon() - return TRUE - -/obj/item/assembly/infra/toggle_secure() - secured = !secured - if(secured) - START_PROCESSING(SSobj, src) - refreshBeam() - else - QDEL_LIST(beams) - STOP_PROCESSING(SSobj, src) - update_icon() - return secured - -/obj/item/assembly/infra/update_icon() - cut_overlays() - attached_overlays = list() - if(on) - add_overlay("infrared_on") - attached_overlays += "infrared_on" - if(visible && secured) - add_overlay("infrared_visible") - attached_overlays += "infrared_visible" - - if(holder) - holder.update_icon() - return - -/obj/item/assembly/infra/dropped() - . = ..() - if(holder) - holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder - else - refreshBeam() - -/obj/item/assembly/infra/process() - if(!on || !secured) - refreshBeam() - return - -/obj/item/assembly/infra/proc/refreshBeam() - QDEL_LIST(beams) - if(throwing || !on || !secured) - return - if(holder) - if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb - if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc)) - return - else if(!isturf(holder.loc)) //else just check where the holder is - return - else if(!isturf(loc)) //or just where the fuck we are in general - return - var/turf/T = get_turf(src) - var/_dir = dir - var/turf/_T = get_step(T, _dir) - if(_T) - for(var/i in 1 to maxlength) - var/obj/effect/beam/i_beam/I = new(T) - if(istype(holder, /obj/item/assembly_holder)) - var/obj/item/assembly_holder/assembly_holder = holder - I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor. - else if(istype(holder, /obj/item/transfer_valve)) - I.icon_state = "[initial(I.icon_state)]_ttv" - I.density = TRUE - if(!I.Move(_T)) - qdel(I) - switchListener(_T) - break - I.density = FALSE - beams += I - I.master = src - I.setDir(_dir) - I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT - T = _T - _T = get_step(_T, _dir) - CHECK_TICK - -/obj/item/assembly/infra/on_detach() - . = ..() - if(!.) - return - refreshBeam() - -/obj/item/assembly/infra/attack_hand() - . = ..() - refreshBeam() - -/obj/item/assembly/infra/Moved() - var/t = dir - . = ..() - setDir(t) - -/obj/item/assembly/infra/throw_at() - . = ..() - olddir = dir - -/obj/item/assembly/infra/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - . = ..() - if(!olddir) - return - setDir(olddir) - olddir = null - -/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location) - refreshBeam() - switchListener(location) - if(!secured || !on || next_activate > world.time) - return FALSE - pulse(FALSE) - audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range) - for(var/CHM in get_hearers_in_view(hearing_range, src)) - if(ismob(CHM)) - var/mob/LM = CHM - LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) - next_activate = world.time + 30 - -/obj/item/assembly/infra/proc/switchListener(turf/newloc) - QDEL_NULL(listener) - listener = newloc.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_EXITED = CALLBACK(src, .proc/check_exit))) - -/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender) - if(QDELETED(src)) - return - if(offender == src || istype(offender,/obj/effect/beam/i_beam)) - return - if (offender && isitem(offender)) - var/obj/item/I = offender - if (I.item_flags & ABSTRACT) - return - return refreshBeam() - -/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel - . = ..() - if(is_secured(user)) - user.set_machine(src) - var/dat = "Infrared Laser" - dat += "
    Status: [on ? "On" : "Off"]" - dat += "
    Visibility: [visible ? "Visible" : "Invisible"]" - dat += "

    Refresh" - dat += "

    Close" - user << browse(dat, "window=infra") - onclose(user, "infra") - return - -/obj/item/assembly/infra/Topic(href, href_list) - ..() - if(usr.incapacitated() || !in_range(loc, usr)) - usr << browse(null, "window=infra") - onclose(usr, "infra") - return - if(href_list["state"]) - on = !(on) - update_icon() - refreshBeam() - if(href_list["visible"]) - visible = !(visible) - update_icon() - refreshBeam() - if(href_list["close"]) - usr << browse(null, "window=infra") - return - if(usr) - attack_self(usr) - -/obj/item/assembly/infra/setDir() - . = ..() - refreshBeam() - -/***************************IBeam*********************************/ - -/obj/effect/beam/i_beam - name = "infrared beam" - icon = 'icons/obj/projectiles.dmi' - icon_state = "ibeam" - var/obj/item/assembly/infra/master - anchored = TRUE - density = FALSE - pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW - -/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj) - if(istype(AM, /obj/effect/beam)) - return - if (isitem(AM)) - var/obj/item/I = AM - if (I.item_flags & ABSTRACT) - return - master.trigger_beam(AM, get_turf(src)) +/obj/item/assembly/infra + name = "infrared emitter" + desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted." + icon_state = "infrared" + materials = list(MAT_METAL=1000, MAT_GLASS=500) + is_position_sensitive = TRUE + + var/on = FALSE + var/visible = FALSE + var/maxlength = 8 + var/list/obj/effect/beam/i_beam/beams + var/olddir = 0 + var/turf/listeningTo + var/hearing_range = 3 + +/obj/item/assembly/infra/Initialize() + . = ..() + beams = list() + START_PROCESSING(SSobj, src) + +/obj/item/assembly/infra/ComponentInitialize() + . = ..() + AddComponent( + /datum/component/simple_rotation, + ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS, + null, + null, + CALLBACK(src,.proc/after_rotation) + ) + +/obj/item/assembly/infra/proc/after_rotation() + refreshBeam() + +/obj/item/assembly/infra/Destroy() + STOP_PROCESSING(SSobj, src) + listeningTo = null + QDEL_LIST(beams) + . = ..() + +/obj/item/assembly/infra/examine(mob/user) + . = ..() + . += "The infrared trigger is [on?"on":"off"]." + +/obj/item/assembly/infra/activate() + if(!..()) + return FALSE//Cooldown check + on = !on + refreshBeam() + update_icon() + return TRUE + +/obj/item/assembly/infra/toggle_secure() + secured = !secured + if(secured) + START_PROCESSING(SSobj, src) + refreshBeam() + else + QDEL_LIST(beams) + STOP_PROCESSING(SSobj, src) + update_icon() + return secured + +/obj/item/assembly/infra/update_icon() + cut_overlays() + attached_overlays = list() + if(on) + add_overlay("infrared_on") + attached_overlays += "infrared_on" + if(visible && secured) + add_overlay("infrared_visible") + attached_overlays += "infrared_visible" + + if(holder) + holder.update_icon() + return + +/obj/item/assembly/infra/dropped() + . = ..() + if(holder) + holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder + else + refreshBeam() + +/obj/item/assembly/infra/process() + if(!on || !secured) + refreshBeam() + return + +/obj/item/assembly/infra/proc/refreshBeam() + QDEL_LIST(beams) + if(throwing || !on || !secured) + return + if(holder) + if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb + if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc)) + return + else if(!isturf(holder.loc)) //else just check where the holder is + return + else if(!isturf(loc)) //or just where the fuck we are in general + return + var/turf/T = get_turf(src) + var/_dir = dir + var/turf/_T = get_step(T, _dir) + if(_T) + for(var/i in 1 to maxlength) + var/obj/effect/beam/i_beam/I = new(T) + if(istype(holder, /obj/item/assembly_holder)) + var/obj/item/assembly_holder/assembly_holder = holder + I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor. + else if(istype(holder, /obj/item/transfer_valve)) + I.icon_state = "[initial(I.icon_state)]_ttv" + I.density = TRUE + if(!I.Move(_T)) + qdel(I) + switchListener(_T) + break + I.density = FALSE + beams += I + I.master = src + I.setDir(_dir) + I.invisibility = visible? 0 : INVISIBILITY_ABSTRACT + T = _T + _T = get_step(_T, _dir) + CHECK_TICK + +/obj/item/assembly/infra/on_detach() + . = ..() + if(!.) + return + refreshBeam() + +/obj/item/assembly/infra/attack_hand() + . = ..() + refreshBeam() + +/obj/item/assembly/infra/Moved() + var/t = dir + . = ..() + setDir(t) + +/obj/item/assembly/infra/throw_at() + . = ..() + olddir = dir + +/obj/item/assembly/infra/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + . = ..() + if(!olddir) + return + setDir(olddir) + olddir = null + +/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location) + refreshBeam() + switchListener(location) + if(!secured || !on || next_activate > world.time) + return FALSE + pulse(FALSE) + audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range) + for(var/CHM in get_hearers_in_view(hearing_range, src)) + if(ismob(CHM)) + var/mob/LM = CHM + LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) + next_activate = world.time + 30 + +/obj/item/assembly/infra/proc/switchListener(turf/newloc) + if(listeningTo == newloc) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_ATOM_EXITED) + RegisterSignal(newloc, COMSIG_ATOM_EXITED, .proc/check_exit) + listeningTo = newloc + +/obj/item/assembly/infra/proc/check_exit(datum/source, atom/movable/offender) + if(QDELETED(src)) + return + if(offender == src || istype(offender,/obj/effect/beam/i_beam)) + return + if (offender && isitem(offender)) + var/obj/item/I = offender + if (I.item_flags & ABSTRACT) + return + return refreshBeam() + +/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel + . = ..() + if(is_secured(user)) + user.set_machine(src) + var/dat = "Infrared Laser" + dat += "
    Status: [on ? "On" : "Off"]" + dat += "
    Visibility: [visible ? "Visible" : "Invisible"]" + dat += "

    Refresh" + dat += "

    Close" + user << browse(dat, "window=infra") + onclose(user, "infra") + return + +/obj/item/assembly/infra/Topic(href, href_list) + ..() + if(usr.incapacitated() || !in_range(loc, usr)) + usr << browse(null, "window=infra") + onclose(usr, "infra") + return + if(href_list["state"]) + on = !(on) + update_icon() + refreshBeam() + if(href_list["visible"]) + visible = !(visible) + update_icon() + refreshBeam() + if(href_list["close"]) + usr << browse(null, "window=infra") + return + if(usr) + attack_self(usr) + +/obj/item/assembly/infra/setDir() + . = ..() + refreshBeam() + +/***************************IBeam*********************************/ + +/obj/effect/beam/i_beam + name = "infrared beam" + icon = 'icons/obj/projectiles.dmi' + icon_state = "ibeam" + var/obj/item/assembly/infra/master + anchored = TRUE + density = FALSE + pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW + +/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj) + if(istype(AM, /obj/effect/beam)) + return + if (isitem(AM)) + var/obj/item/I = AM + if (I.item_flags & ABSTRACT) + return + master.trigger_beam(AM, get_turf(src)) diff --git a/code/modules/asset_cache/asset_cache.dm b/code/modules/asset_cache/asset_cache.dm new file mode 100644 index 00000000..7a12e5e9 --- /dev/null +++ b/code/modules/asset_cache/asset_cache.dm @@ -0,0 +1,100 @@ +/* +Asset cache quick users guide: +Make a datum in asset_list_items.dm with your assets for your thing. +Checkout asset_list.dm for the helper subclasses +The simple subclass will most like be of use for most cases. +Then call get_asset_datum() with the type of the datum you created and store the return +Then call .send(client) on that stored return value. +Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE +*/ + +//When sending mutiple assets, how many before we give the client a quaint little sending resources message +#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 + +//This proc sends the asset to the client, but only if it needs it. +//This proc blocks(sleeps) unless verify is set to false +/proc/send_asset(client/client, asset_name) + return send_asset_list(client, list(asset_name)) + +/// Sends a list of assets to a client +/// This proc will no longer block, use client.asset_flush() if you to need know when the client has all assets (such as for output()). (This is not required for browse() calls as they use the same message queue as asset sends) +/// client - a client or mob +/// asset_list - A list of asset filenames to be sent to the client. +/// Returns TRUE if any assets were sent. +/proc/send_asset_list(client/client, list/asset_list) + if(!istype(client)) + if(ismob(client)) + var/mob/M = client + if(M.client) + client = M.client + else + return + else + return + + var/list/unreceived = list() + + for (var/asset_name in asset_list) + var/datum/asset_cache_item/asset = SSassets.cache[asset_name] + if (!asset) + continue + var/asset_file = asset.resource + if (!asset_file) + continue + + var/asset_md5 = asset.md5 + if (client.sent_assets[asset_name] == asset_md5) + continue + unreceived[asset_name] = asset_md5 + + if (unreceived.len) + if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT) + to_chat(client, "Sending Resources...") + + for(var/asset in unreceived) + var/datum/asset_cache_item/ACI + if ((ACI = SSassets.cache[asset])) + log_asset("Sending asset [asset] to client [client]") + client << browse_rsc(ACI.resource, asset) + + client.sent_assets |= unreceived + addtimer(CALLBACK(client, /client/proc/asset_cache_update_json), 1 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) + return TRUE + return FALSE + +//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start. +//The proc calls procs that sleep for long times. +/proc/getFilesSlow(client/client, list/files, register_asset = TRUE, filerate = 3) + var/startingfilerate = filerate + for(var/file in files) + if (!client) + break + if (register_asset) + register_asset(file, files[file]) + + if (send_asset(client, file)) + if (!(--filerate)) + filerate = startingfilerate + client.asset_flush() + stoplag(0) //queuing calls like this too quickly can cause issues in some client versions + +//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up. +//icons and virtual assets get copied to the dyn rsc before use +/proc/register_asset(asset_name, asset) + var/datum/asset_cache_item/ACI = new(asset_name, asset) + + //this is technically never something that was supported and i want metrics on how often it happens if at all. + if (SSassets.cache[asset_name]) + var/datum/asset_cache_item/OACI = SSassets.cache[asset_name] + if (OACI.md5 != ACI.md5) + stack_trace("ERROR: new asset added to the asset cache with the same name as another asset: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]") + else + var/list/stacktrace = gib_stack_trace() + log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]") + SSassets.cache[asset_name] = ACI + +//Generated names do not include file extention. +//Used mainly for code that deals with assets in a generic way +//The same asset will always lead to the same asset name +/proc/generate_asset_name(file) + return "asset.[md5(fcopy_rsc(file))]" diff --git a/code/modules/asset_cache/asset_cache_client.dm b/code/modules/asset_cache/asset_cache_client.dm new file mode 100644 index 00000000..f9b3752b --- /dev/null +++ b/code/modules/asset_cache/asset_cache_client.dm @@ -0,0 +1,50 @@ +/// Process asset cache client topic calls for "asset_cache_confirm_arrival=[INT]" +/client/proc/asset_cache_confirm_arrival(job_id) + var/asset_cache_job = round(text2num(job_id)) + //because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us into letting them append to a list without limit. + if (asset_cache_job > 0 && asset_cache_job <= last_asset_job && !(completed_asset_jobs["[asset_cache_job]"])) + completed_asset_jobs["[asset_cache_job]"] = TRUE + last_completed_asset_job = max(last_completed_asset_job, asset_cache_job) + else + return asset_cache_job || TRUE + + +/// Process asset cache client topic calls for "asset_cache_preload_data=[HTML+JSON_STRING] +/client/proc/asset_cache_preload_data(data) + /*var/jsonend = findtextEx(data, "{{{ENDJSONDATA}}}") + if (!jsonend) + CRASH("invalid asset_cache_preload_data, no jsonendmarker")*/ + //var/json = html_decode(copytext(data, 1, jsonend)) + var/json = data + var/list/preloaded_assets = json_decode(json) + + for (var/preloaded_asset in preloaded_assets) + if (copytext(preloaded_asset, findlasttext(preloaded_asset, ".")+1) in list("js", "jsm", "htm", "html")) + preloaded_assets -= preloaded_asset + continue + sent_assets |= preloaded_assets + + +/// Updates the client side stored html/json combo file used to keep track of what assets the client has between restarts/reconnects. +/client/proc/asset_cache_update_json(verify = FALSE, list/new_assets = list()) + if (world.time - connection_time < 10 SECONDS) //don't override the existing data file on a new connection + return + if (!islist(new_assets)) + new_assets = list("[new_assets]" = md5(SSassets.cache[new_assets])) + + src << browse(json_encode(new_assets|sent_assets), "file=asset_data.json&display=0") + +/// Blocks until all currently sending browser assets have been sent. +/// Due to byond limitations, this proc will sleep for 1 client round trip even if the client has no pending asset sends. +/// This proc will return an untrue value if it had to return before confirming the send, such as timeout or the client going away. +/client/proc/asset_flush(timeout = 50) + var/job = ++last_asset_job + var/t = 0 + var/timeout_time = timeout + src << browse({""}, "window=asset_cache_browser&file=asset_cache_send_verify.htm") + + while(!completed_asset_jobs["[job]"] && t < timeout_time) // Reception is handled in Topic() + stoplag(1) // Lock up the caller until this is received. + t++ + if (t < timeout_time) + return TRUE diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm new file mode 100644 index 00000000..0e7d44a7 --- /dev/null +++ b/code/modules/asset_cache/asset_cache_item.dm @@ -0,0 +1,21 @@ +/** + * # asset_cache_item + * + * An internal datum containing info on items in the asset cache. Mainly used to cache md5 info for speed. +**/ +/datum/asset_cache_item + var/name + var/md5 + var/resource + +/datum/asset_cache_item/New(name, file) + if (!isfile(file)) + file = fcopy_rsc(file) + md5 = md5(file) + if (!md5) + md5 = md5(fcopy_rsc(file)) + if (!md5) + CRASH("invalid asset sent to asset cache") + debug_world_log("asset cache unexpected success of second fcopy_rsc") + src.name = name + resource = file diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm new file mode 100644 index 00000000..fe9859f2 --- /dev/null +++ b/code/modules/asset_cache/asset_list.dm @@ -0,0 +1,228 @@ + +//These datums are used to populate the asset cache, the proc "register()" does this. +//Place any asset datums you create in asset_list_items.dm + +//all of our asset datums, used for referring to these later +GLOBAL_LIST_EMPTY(asset_datums) + +//get an assetdatum or make a new one +/proc/get_asset_datum(type) + return GLOB.asset_datums[type] || new type() + +/datum/asset + var/_abstract = /datum/asset + +/datum/asset/New() + GLOB.asset_datums[type] = src + register() + +/datum/asset/proc/register() + return + +/datum/asset/proc/send(client) + return + + +//If you don't need anything complicated. +/datum/asset/simple + _abstract = /datum/asset/simple + var/assets = list() + +/datum/asset/simple/register() + for(var/asset_name in assets) + register_asset(asset_name, assets[asset_name]) + +/datum/asset/simple/send(client) + . = send_asset_list(client, assets) + + +// For registering or sending multiple others at once +/datum/asset/group + _abstract = /datum/asset/group + var/list/children + +/datum/asset/group/register() + for(var/type in children) + get_asset_datum(type) + +/datum/asset/group/send(client/C) + for(var/type in children) + var/datum/asset/A = get_asset_datum(type) + . = A.send(C) || . + + +// spritesheet implementation - coalesces various icons into a single .png file +// and uses CSS to select icons out of that file - saves on transferring some +// 1400-odd individual PNG files +#define SPR_SIZE 1 +#define SPR_IDX 2 +#define SPRSZ_COUNT 1 +#define SPRSZ_ICON 2 +#define SPRSZ_STRIPPED 3 + +/datum/asset/spritesheet + _abstract = /datum/asset/spritesheet + var/name + var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped) + var/list/sprites = list() // "foo_bar" -> list("32x32", 5) + +/datum/asset/spritesheet/register() + if (!name) + CRASH("spritesheet [type] cannot register without a name") + ensure_stripped() + + var/res_name = "spritesheet_[name].css" + var/fname = "data/spritesheets/[res_name]" + fdel(fname) + text2file(generate_css(), fname) + register_asset(res_name, fcopy_rsc(fname)) + fdel(fname) + + for(var/size_id in sizes) + var/size = sizes[size_id] + register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED]) + +/datum/asset/spritesheet/send(client/C) + if (!name) + return + var/all = list("spritesheet_[name].css") + for(var/size_id in sizes) + all += "[name]_[size_id].png" + . = send_asset_list(C, all) + +/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes) + for(var/size_id in sizes_to_strip) + var/size = sizes[size_id] + if (size[SPRSZ_STRIPPED]) + continue + + // save flattened version + var/fname = "data/spritesheets/[name]_[size_id].png" + fcopy(size[SPRSZ_ICON], fname) + var/error = rustg_dmi_strip_metadata(fname) + if(length(error)) + stack_trace("Failed to strip [name]_[size_id].png: [error]") + size[SPRSZ_STRIPPED] = icon(fname) + fdel(fname) + +/datum/asset/spritesheet/proc/generate_css() + var/list/out = list() + + for (var/size_id in sizes) + var/size = sizes[size_id] + var/icon/tiny = size[SPRSZ_ICON] + out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}" + + for (var/sprite_id in sprites) + var/sprite = sprites[sprite_id] + var/size_id = sprite[SPR_SIZE] + var/idx = sprite[SPR_IDX] + var/size = sizes[size_id] + + var/icon/tiny = size[SPRSZ_ICON] + var/icon/big = size[SPRSZ_STRIPPED] + var/per_line = big.Width() / tiny.Width() + var/x = (idx % per_line) * tiny.Width() + var/y = round(idx / per_line) * tiny.Height() + + out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}" + + return out.Join("\n") + +/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE) + I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving) + if (!I || !length(icon_states(I))) // that direction or state doesn't exist + return + var/size_id = "[I.Width()]x[I.Height()]" + var/size = sizes[size_id] + + if (sprites[sprite_name]) + CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])") + + if (size) + var/position = size[SPRSZ_COUNT]++ + var/icon/sheet = size[SPRSZ_ICON] + size[SPRSZ_STRIPPED] = null + sheet.Insert(I, icon_state=sprite_name) + sprites[sprite_name] = list(size_id, position) + else + sizes[size_id] = size = list(1, I, null) + sprites[sprite_name] = list(size_id, 0) + +/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions) + if (length(prefix)) + prefix = "[prefix]-" + + if (!directions) + directions = list(SOUTH) + + for (var/icon_state_name in icon_states(I)) + for (var/direction in directions) + var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : "" + Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction) + +/datum/asset/spritesheet/proc/css_tag() + return {""} + +/datum/asset/spritesheet/proc/icon_tag(sprite_name) + var/sprite = sprites[sprite_name] + if (!sprite) + return null + var/size_id = sprite[SPR_SIZE] + return {""} + +/datum/asset/spritesheet/proc/icon_class_name(sprite_name) + var/sprite = sprites[sprite_name] + if (!sprite) + return null + var/size_id = sprite[SPR_SIZE] + return {"[name][size_id] [sprite_name]"} + +#undef SPR_SIZE +#undef SPR_IDX +#undef SPRSZ_COUNT +#undef SPRSZ_ICON +#undef SPRSZ_STRIPPED + + +/datum/asset/spritesheet/simple + _abstract = /datum/asset/spritesheet/simple + var/list/assets + +/datum/asset/spritesheet/simple/register() + for (var/key in assets) + Insert(key, assets[key]) + ..() + +//Generates assets based on iconstates of a single icon +/datum/asset/simple/icon_states + _abstract = /datum/asset/simple/icon_states + var/icon + var/list/directions = list(SOUTH) + var/frame = 1 + var/movement_states = FALSE + + var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png" + var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format + +/datum/asset/simple/icon_states/register(_icon = icon) + for(var/icon_state_name in icon_states(_icon)) + for(var/direction in directions) + var/asset = icon(_icon, icon_state_name, direction, frame, movement_states) + if (!asset) + continue + asset = fcopy_rsc(asset) //dedupe + var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : "" + var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png") + if (generic_icon_names) + asset_name = "[generate_asset_name(asset)].png" + + register_asset(asset_name, asset) + +/datum/asset/simple/icon_states/multiple_icons + _abstract = /datum/asset/simple/icon_states/multiple_icons + var/list/icons + +/datum/asset/simple/icon_states/multiple_icons/register() + for(var/i in icons) + ..(i) diff --git a/code/modules/client/asset_cache.dm b/code/modules/asset_cache/asset_list_items.dm similarity index 51% rename from code/modules/client/asset_cache.dm rename to code/modules/asset_cache/asset_list_items.dm index 959f2baa..f38c40dc 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -1,399 +1,22 @@ -/* -Asset cache quick users guide: - -Make a datum at the bottom of this file with your assets for your thing. -The simple subsystem will most like be of use for most cases. -Then call get_asset_datum() with the type of the datum you created and store the return -Then call .send(client) on that stored return value. - -You can set verify to TRUE if you want send() to sleep until the client has the assets. -*/ - - -// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping. -// This is doubled for the first asset, then added per asset after -#define ASSET_CACHE_SEND_TIMEOUT 7 - -//When sending mutiple assets, how many before we give the client a quaint little sending resources message -#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8 - -//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files -#define ASSET_CACHE_PRELOAD_CONCURRENT 3 - -/client - var/list/cache = list() // List of all assets sent to this client by the asset cache. - var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement. - var/list/sending = list() - var/last_asset_job = 0 // Last job done. - -//This proc sends the asset to the client, but only if it needs it. -//This proc blocks(sleeps) unless verify is set to false -/proc/send_asset(client/client, asset_name, verify = TRUE) - if(!istype(client)) - if(ismob(client)) - var/mob/M = client - if(M.client) - client = M.client - - else - return 0 - - else - return 0 - - if(client.cache.Find(asset_name) || client.sending.Find(asset_name)) - return 0 - - client << browse_rsc(SSassets.cache[asset_name], asset_name) - if(!verify) - client.cache += asset_name - return 1 - - client.sending |= asset_name - var/job = ++client.last_asset_job - - client << browse({" - - "}, "window=asset_cache_browser") - - var/t = 0 - var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT - while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() - stoplag(1) // Lock up the caller until this is received. - t++ - - if(client) - client.sending -= asset_name - client.cache |= asset_name - client.completed_asset_jobs -= job - - return 1 - -//This proc blocks(sleeps) unless verify is set to false -/proc/send_asset_list(client/client, list/asset_list, verify = TRUE) - if(!istype(client)) - if(ismob(client)) - var/mob/M = client - if(M.client) - client = M.client - - else - return 0 - - else - return 0 - - var/list/unreceived = asset_list - (client.cache + client.sending) - if(!unreceived || !unreceived.len) - return 0 - if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT) - to_chat(client, "Sending Resources...") - for(var/asset in unreceived) - if (asset in SSassets.cache) - client << browse_rsc(SSassets.cache[asset], asset) - - if(!verify) // Can't access the asset cache browser, rip. - client.cache += unreceived - return 1 - - client.sending |= unreceived - var/job = ++client.last_asset_job - - client << browse({" - - "}, "window=asset_cache_browser") - - var/t = 0 - var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len - while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic() - stoplag(1) // Lock up the caller until this is received. - t++ - - if(client) - client.sending -= unreceived - client.cache |= unreceived - client.completed_asset_jobs -= job - - return 1 - -//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start. -//The proc calls procs that sleep for long times. -/proc/getFilesSlow(client/client, list/files, register_asset = TRUE) - var/concurrent_tracker = 1 - for(var/file in files) - if (!client) - break - if (register_asset) - register_asset(file, files[file]) - if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT) - concurrent_tracker = 1 - send_asset(client, file) - else - concurrent_tracker++ - send_asset(client, file, verify=FALSE) - - stoplag(0) //queuing calls like this too quickly can cause issues in some client versions - -//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up. -//if it's an icon or something be careful, you'll have to copy it before further use. -/proc/register_asset(asset_name, asset) - SSassets.cache[asset_name] = asset - -//Generated names do not include file extention. -//Used mainly for code that deals with assets in a generic way -//The same asset will always lead to the same asset name -/proc/generate_asset_name(file) - return "asset.[md5(fcopy_rsc(file))]" - - -//These datums are used to populate the asset cache, the proc "register()" does this. - -//all of our asset datums, used for referring to these later -GLOBAL_LIST_EMPTY(asset_datums) - -//get an assetdatum or make a new one -/proc/get_asset_datum(type) - return GLOB.asset_datums[type] || new type() - -/datum/asset - var/_abstract = /datum/asset - -/datum/asset/New() - GLOB.asset_datums[type] = src - register() - -/datum/asset/proc/register() - return - -/datum/asset/proc/send(client) - return - - -//If you don't need anything complicated. -/datum/asset/simple - _abstract = /datum/asset/simple - var/assets = list() - var/verify = FALSE - -/datum/asset/simple/register() - for(var/asset_name in assets) - register_asset(asset_name, assets[asset_name]) - -/datum/asset/simple/send(client) - send_asset_list(client,assets,verify) - - -// For registering or sending multiple others at once -/datum/asset/group - _abstract = /datum/asset/group - var/list/children - -/datum/asset/group/register() - for(var/type in children) - get_asset_datum(type) - -/datum/asset/group/send(client/C) - for(var/type in children) - var/datum/asset/A = get_asset_datum(type) - A.send(C) - - -// spritesheet implementation - coalesces various icons into a single .png file -// and uses CSS to select icons out of that file - saves on transferring some -// 1400-odd individual PNG files -#define SPR_SIZE 1 -#define SPR_IDX 2 -#define SPRSZ_COUNT 1 -#define SPRSZ_ICON 2 -#define SPRSZ_STRIPPED 3 - -/datum/asset/spritesheet - _abstract = /datum/asset/spritesheet - var/name - var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped) - var/list/sprites = list() // "foo_bar" -> list("32x32", 5) - var/verify = FALSE - -/datum/asset/spritesheet/register() - if (!name) - CRASH("spritesheet [type] cannot register without a name") - ensure_stripped() - - var/res_name = "spritesheet_[name].css" - var/fname = "data/spritesheets/[res_name]" - fdel(fname) - text2file(generate_css(), fname) - register_asset(res_name, fcopy_rsc(fname)) - fdel(fname) - - for(var/size_id in sizes) - var/size = sizes[size_id] - register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED]) - -/datum/asset/spritesheet/send(client/C) - if (!name) - return - var/all = list("spritesheet_[name].css") - for(var/size_id in sizes) - all += "[name]_[size_id].png" - send_asset_list(C, all, verify) - -/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes) - for(var/size_id in sizes_to_strip) - var/size = sizes[size_id] - if (size[SPRSZ_STRIPPED]) - continue - - // save flattened version - var/fname = "data/spritesheets/[name]_[size_id].png" - fcopy(size[SPRSZ_ICON], fname) - var/error = rustg_dmi_strip_metadata(fname) - if(length(error)) - stack_trace("Failed to strip [name]_[size_id].png: [error]") - size[SPRSZ_STRIPPED] = icon(fname) - fdel(fname) - -/datum/asset/spritesheet/proc/generate_css() - var/list/out = list() - - for (var/size_id in sizes) - var/size = sizes[size_id] - var/icon/tiny = size[SPRSZ_ICON] - out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}" - - for (var/sprite_id in sprites) - var/sprite = sprites[sprite_id] - var/size_id = sprite[SPR_SIZE] - var/idx = sprite[SPR_IDX] - var/size = sizes[size_id] - - var/icon/tiny = size[SPRSZ_ICON] - var/icon/big = size[SPRSZ_STRIPPED] - var/per_line = big.Width() / tiny.Width() - var/x = (idx % per_line) * tiny.Width() - var/y = round(idx / per_line) * tiny.Height() - - out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}" - - return out.Join("\n") - -/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE) - I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving) - if (!I || !length(icon_states(I))) // that direction or state doesn't exist - return - var/size_id = "[I.Width()]x[I.Height()]" - var/size = sizes[size_id] - - if (sprites[sprite_name]) - CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])") - - if (size) - var/position = size[SPRSZ_COUNT]++ - var/icon/sheet = size[SPRSZ_ICON] - size[SPRSZ_STRIPPED] = null - sheet.Insert(I, icon_state=sprite_name) - sprites[sprite_name] = list(size_id, position) - else - sizes[size_id] = size = list(1, I, null) - sprites[sprite_name] = list(size_id, 0) - -/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions) - if (length(prefix)) - prefix = "[prefix]-" - - if (!directions) - directions = list(SOUTH) - - for (var/icon_state_name in icon_states(I)) - for (var/direction in directions) - var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : "" - Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction) - -/datum/asset/spritesheet/proc/css_tag() - return {""} - -/datum/asset/spritesheet/proc/icon_tag(sprite_name) - var/sprite = sprites[sprite_name] - if (!sprite) - return null - var/size_id = sprite[SPR_SIZE] - return {""} - -/datum/asset/spritesheet/proc/icon_class_name(sprite_name) - var/sprite = sprites[sprite_name] - if (!sprite) - return null - var/size_id = sprite[SPR_SIZE] - return {"[name][size_id] [sprite_name]"} - -#undef SPR_SIZE -#undef SPR_IDX -#undef SPRSZ_COUNT -#undef SPRSZ_ICON -#undef SPRSZ_STRIPPED - - -/datum/asset/spritesheet/simple - _abstract = /datum/asset/spritesheet/simple - var/list/assets - -/datum/asset/spritesheet/simple/register() - for (var/key in assets) - Insert(key, assets[key]) - ..() - -//Generates assets based on iconstates of a single icon -/datum/asset/simple/icon_states - _abstract = /datum/asset/simple/icon_states - var/icon - var/list/directions = list(SOUTH) - var/frame = 1 - var/movement_states = FALSE - - var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png" - var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format - - verify = FALSE - -/datum/asset/simple/icon_states/register(_icon = icon) - for(var/icon_state_name in icon_states(_icon)) - for(var/direction in directions) - var/asset = icon(_icon, icon_state_name, direction, frame, movement_states) - if (!asset) - continue - asset = fcopy_rsc(asset) //dedupe - var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : "" - var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png") - if (generic_icon_names) - asset_name = "[generate_asset_name(asset)].png" - - register_asset(asset_name, asset) - -/datum/asset/simple/icon_states/multiple_icons - _abstract = /datum/asset/simple/icon_states/multiple_icons - var/list/icons - -/datum/asset/simple/icon_states/multiple_icons/register() - for(var/i in icons) - ..(i) - - //DEFINITIONS FOR ASSET DATUMS START HERE. - +/* uncomment this and delete the tgui def bellow this for the new tgui /datum/asset/simple/tgui assets = list( - // tgui + "tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js', + "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css', + ) +*/ +/datum/asset/simple/tgui + assets = list( + // Old TGUI "tgui.css" = 'tgui/assets/tgui.css', "tgui.js" = 'tgui/assets/tgui.js', // tgui-next "tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html', - "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html', "tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js', "tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css', + // Old TGUI compatability + "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html', "shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js', "shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js', "shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js', @@ -434,8 +57,16 @@ GLOBAL_LIST_EMPTY(asset_datums) "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', "smmon_6.gif" = 'icons/program_icons/smmon_6.gif' + //"borg_mon.gif" = 'icons/program_icons/borg_mon.gif' ) - +/* uncomment if you're porting the new ntnet app +/datum/asset/simple/radar_assets + assets = list( + "ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png', + "ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png', + "ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png' + ) +*/ /datum/asset/spritesheet/simple/pda name = "pda" assets = list( @@ -464,6 +95,7 @@ GLOBAL_LIST_EMPTY(asset_datums) "refresh" = 'icons/pda_icons/pda_refresh.png', "scanner" = 'icons/pda_icons/pda_scanner.png', "signaler" = 'icons/pda_icons/pda_signaler.png', + //"skills" = 'icons/pda_icons/pda_skills.png', "status" = 'icons/pda_icons/pda_status.png', "dronephone" = 'icons/pda_icons/pda_dronephone.png' ) @@ -482,51 +114,10 @@ GLOBAL_LIST_EMPTY(asset_datums) "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', "stamp-law" = 'icons/stamp_icons/large_stamp-law.png' - ) - -/datum/asset/spritesheet/simple/minesweeper - name = "minesweeper" - assets = list( - "1" = 'icons/UI_Icons/minesweeper_tiles/one.png', - "2" = 'icons/UI_Icons/minesweeper_tiles/two.png', - "3" = 'icons/UI_Icons/minesweeper_tiles/three.png', - "4" = 'icons/UI_Icons/minesweeper_tiles/four.png', - "5" = 'icons/UI_Icons/minesweeper_tiles/five.png', - "6" = 'icons/UI_Icons/minesweeper_tiles/six.png', - "7" = 'icons/UI_Icons/minesweeper_tiles/seven.png', - "8" = 'icons/UI_Icons/minesweeper_tiles/eight.png', - "empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png', - "flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png', - "hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png', - "mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png', - "minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png' - ) - -/datum/asset/spritesheet/simple/pills - name = "pills" - assets = list( - "pill1" = 'icons/UI_Icons/Pills/pill1.png', - "pill2" = 'icons/UI_Icons/Pills/pill2.png', - "pill3" = 'icons/UI_Icons/Pills/pill3.png', - "pill4" = 'icons/UI_Icons/Pills/pill4.png', - "pill5" = 'icons/UI_Icons/Pills/pill5.png', - "pill6" = 'icons/UI_Icons/Pills/pill6.png', - "pill7" = 'icons/UI_Icons/Pills/pill7.png', - "pill8" = 'icons/UI_Icons/Pills/pill8.png', - "pill9" = 'icons/UI_Icons/Pills/pill9.png', - "pill10" = 'icons/UI_Icons/Pills/pill10.png', - "pill11" = 'icons/UI_Icons/Pills/pill11.png', - "pill12" = 'icons/UI_Icons/Pills/pill12.png', - "pill13" = 'icons/UI_Icons/Pills/pill13.png', - "pill14" = 'icons/UI_Icons/Pills/pill14.png', - "pill15" = 'icons/UI_Icons/Pills/pill15.png', - "pill16" = 'icons/UI_Icons/Pills/pill16.png', - "pill17" = 'icons/UI_Icons/Pills/pill17.png', - "pill18" = 'icons/UI_Icons/Pills/pill18.png', - "pill19" = 'icons/UI_Icons/Pills/pill19.png', - "pill20" = 'icons/UI_Icons/Pills/pill20.png', - "pill21" = 'icons/UI_Icons/Pills/pill21.png', - "pill22" = 'icons/UI_Icons/Pills/pill22.png', + //"stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png', + //"stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', + //"stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', + //"stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' ) /datum/asset/simple/IRV @@ -572,23 +163,20 @@ GLOBAL_LIST_EMPTY(asset_datums) ) /datum/asset/simple/jquery - verify = FALSE assets = list( "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js', ) /datum/asset/simple/goonchat - verify = FALSE assets = list( "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js', "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css', - "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', + "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', //dark theme, cit specific "browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css' ) /datum/asset/simple/fontawesome - verify = FALSE assets = list( "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', @@ -629,6 +217,90 @@ GLOBAL_LIST_EMPTY(asset_datums) "none_button.png" = 'html/none_button.png', ) +/datum/asset/spritesheet/simple/minesweeper + name = "minesweeper" + assets = list( + "1" = 'icons/UI_Icons/minesweeper_tiles/one.png', + "2" = 'icons/UI_Icons/minesweeper_tiles/two.png', + "3" = 'icons/UI_Icons/minesweeper_tiles/three.png', + "4" = 'icons/UI_Icons/minesweeper_tiles/four.png', + "5" = 'icons/UI_Icons/minesweeper_tiles/five.png', + "6" = 'icons/UI_Icons/minesweeper_tiles/six.png', + "7" = 'icons/UI_Icons/minesweeper_tiles/seven.png', + "8" = 'icons/UI_Icons/minesweeper_tiles/eight.png', + "empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png', + "flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png', + "hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png', + "mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png', + "minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png' + ) + +/* Port the app game thing +/datum/asset/simple/arcade + assets = list( + "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif', + "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif', + "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif', + "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif', + "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif', + "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif', + ) +*/ +/* +/datum/asset/spritesheet/simple/achievements + name ="achievements" + assets = list( + "default" = 'icons/UI_Icons/Achievements/default.png', + "basemisc" = 'icons/UI_Icons/Achievements/basemisc.png', + "baseboss" = 'icons/UI_Icons/Achievements/baseboss.png', + "baseskill" = 'icons/UI_Icons/Achievements/baseskill.png', + "bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png', + "colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png', + "hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png', + "legion" = 'icons/UI_Icons/Achievements/Boss/legion.png', + "miner" = 'icons/UI_Icons/Achievements/Boss/miner.png', + "swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png', + "tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png', + "featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png', + "helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png', + "jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png', + "meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png', + "timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png', + "upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png', + "clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png', + "clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png', + "rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png', + "snail" = 'icons/UI_Icons/Achievements/Misc/snail.png', + "mining" = 'icons/UI_Icons/Achievements/Skills/mining.png', + ) +*/ +/datum/asset/spritesheet/simple/pills + name ="pills" + assets = list( + "pill1" = 'icons/UI_Icons/Pills/pill1.png', + "pill2" = 'icons/UI_Icons/Pills/pill2.png', + "pill3" = 'icons/UI_Icons/Pills/pill3.png', + "pill4" = 'icons/UI_Icons/Pills/pill4.png', + "pill5" = 'icons/UI_Icons/Pills/pill5.png', + "pill6" = 'icons/UI_Icons/Pills/pill6.png', + "pill7" = 'icons/UI_Icons/Pills/pill7.png', + "pill8" = 'icons/UI_Icons/Pills/pill8.png', + "pill9" = 'icons/UI_Icons/Pills/pill9.png', + "pill10" = 'icons/UI_Icons/Pills/pill10.png', + "pill11" = 'icons/UI_Icons/Pills/pill11.png', + "pill12" = 'icons/UI_Icons/Pills/pill12.png', + "pill13" = 'icons/UI_Icons/Pills/pill13.png', + "pill14" = 'icons/UI_Icons/Pills/pill14.png', + "pill15" = 'icons/UI_Icons/Pills/pill15.png', + "pill16" = 'icons/UI_Icons/Pills/pill16.png', + "pill17" = 'icons/UI_Icons/Pills/pill17.png', + "pill18" = 'icons/UI_Icons/Pills/pill18.png', + "pill19" = 'icons/UI_Icons/Pills/pill19.png', + "pill20" = 'icons/UI_Icons/Pills/pill20.png', + "pill21" = 'icons/UI_Icons/Pills/pill21.png', + "pill22" = 'icons/UI_Icons/Pills/pill22.png', + ) + //this exists purely to avoid meta by pre-loading all language icons. /datum/asset/language/register() for(var/path in typesof(/datum/language)) @@ -639,7 +311,7 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/spritesheet/pipes name = "pipes" -/datum/asset/spritesheet/pipes/register() +/datum/asset/spritesheet/pipes/register() //we do not have chempipes for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi')) InsertAll("", each, GLOB.alldirs) ..() @@ -649,7 +321,7 @@ GLOBAL_LIST_EMPTY(asset_datums) name = "design" /datum/asset/spritesheet/research_designs/register() - for (var/path in subtypesof(/datum/design)) + for(var/path in subtypesof(/datum/design)) var/datum/design/D = path var/icon_file diff --git a/code/modules/asset_cache/validate_assets.html b/code/modules/asset_cache/validate_assets.html new file mode 100644 index 00000000..205a7f4d --- /dev/null +++ b/code/modules/asset_cache/validate_assets.html @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index c040d063..fe130349 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -208,7 +208,7 @@ /datum/supply_pack/science/hev name = "Hazard Suit Crate" desc = "A familiar suit from the times of interdimensional exploring. Research Directors might prefer these due to their superior radioactive protection over the standard RD suit." - cost = 10000 + cost = 15000 access = ACCESS_RD contains = list(/obj/item/clothing/suit/space/hardsuit/rd/hev) crate_name = "hazard suit crate" diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 792e40ad..00a6e281 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -94,3 +94,11 @@ /// Messages currently seen by this client var/list/seen_messages + + // List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s + var/list/sent_assets = list() + /// List of all completed blocking send jobs awaiting acknowledgement by send_asset + var/list/completed_asset_jobs = list() + /// Last asset send job id. + var/last_asset_job = 0 + var/last_completed_asset_job = 0 diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 69c52c91..96ba948b 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -36,29 +36,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null return - // asset_cache + var/asset_cache_job if(href_list["asset_cache_confirm_arrival"]) - var/job = text2num(href_list["asset_cache_confirm_arrival"]) - //because we skip the limiter, we have to make sure this is a valid arrival and not somebody tricking us - // into letting append to a list without limit. - if (job && job <= last_asset_job && !(job in completed_asset_jobs)) - completed_asset_jobs += job + asset_cache_job = asset_cache_confirm_arrival(href_list["asset_cache_confirm_arrival"]) + if (!asset_cache_job) return - else if (job in completed_asset_jobs) //byond bug ID:2256651 - to_chat(src, "An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)") - src << browse("...", "window=asset_cache_browser") - // Keypress passthrough - if(href_list["__keydown"]) - var/keycode = browser_keycode_to_byond(href_list["__keydown"]) - if(keycode) - keyDown(keycode) - return - if(href_list["__keyup"]) - var/keycode = browser_keycode_to_byond(href_list["__keyup"]) - if(keycode) - keyUp(keycode) - return - var/mtl = CONFIG_GET(number/minute_topic_limit) if (!holder && mtl) @@ -75,7 +57,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( topiclimiter[ADMINSWARNED_AT] = minute msg += " Administrators have been informed." log_game("[key_name(src)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute") - message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute") + message_admins("[ADMIN_LOOKUPFLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute") to_chat(src, "[msg]") return @@ -96,6 +78,27 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]") + //byond bug ID:2256651 + if (asset_cache_job && (asset_cache_job in completed_asset_jobs)) + to_chat(src, "An error has been detected in how your client is receiving resources. Attempting to correct.... (If you keep seeing these messages you might want to close byond and reconnect)") + src << browse("...", "window=asset_cache_browser") + return + if (href_list["asset_cache_preload_data"]) + asset_cache_preload_data(href_list["asset_cache_preload_data"]) + return + + // Keypress passthrough + if(href_list["__keydown"]) + var/keycode = browser_keycode_to_byond(href_list["__keydown"]) + if(keycode) + keyDown(keycode) + return + if(href_list["__keyup"]) + var/keycode = browser_keycode_to_byond(href_list["__keyup"]) + if(keycode) + keyUp(keycode) + return + // Admin PM if(href_list["priv_msg"]) cmd_admin_pm(href_list["priv_msg"],null) @@ -830,8 +833,14 @@ GLOBAL_LIST_EMPTY(external_rsc_urls) 'html/browser/playeroptions.css', ) spawn (10) //removing this spawn causes all clients to not get verbs. + + //load info on what assets the client has + src << browse('code/modules/asset_cache/validate_assets.html', "window=asset_cache_browser") + //Precache the client with all other assets slowly, so as to not block other browse() calls getFilesSlow(src, SSassets.preload, register_asset = FALSE) + addtimer(CALLBACK(GLOBAL_PROC, /proc/getFilesSlow, src, SSassets.preload, FALSE), 5 SECONDS) + #if (PRELOAD_RSC == 0) for (var/name in GLOB.vox_sounds) var/file = GLOB.vox_sounds[name] diff --git a/code/modules/client/verbs/minimap.dm b/code/modules/client/verbs/minimap.dm index 3d213dc2..3cdb1d57 100644 --- a/code/modules/client/verbs/minimap.dm +++ b/code/modules/client/verbs/minimap.dm @@ -6,5 +6,7 @@ if(!CONFIG_GET(flag/minimaps_enabled)) to_chat(usr, "Minimap generation is not enabled in the server's configuration.") return - + if(!SSminimaps.station_minimap) + to_chat(usr, "Minimap generation is in progress, please wait!") + return SSminimaps.station_minimap.show(src) diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 00cb9b1e..c7067c64 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -1,43 +1,43 @@ -/obj/item/clothing/gloves - name = "gloves" - gender = PLURAL //Carn: for grammarically correct text-parsing - w_class = WEIGHT_CLASS_SMALL - icon = 'icons/obj/clothing/gloves.dmi' - siemens_coefficient = 0.5 - body_parts_covered = HANDS - slot_flags = ITEM_SLOT_GLOVES - attack_verb = list("challenged") - var/transfer_prints = FALSE - var/transfer_blood = 0 - strip_delay = 20 - equip_delay_other = 40 - -/obj/item/clothing/gloves/ComponentInitialize() - . = ..() - AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/gloves/clean_blood))) - -/obj/item/clothing/gloves/clean_blood(datum/source, strength) - . = ..() - transfer_blood = 0 - -/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user) - user.visible_message("\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!") - return OXYLOSS - -/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE) - . = list() - if(!isinhands) - if(damaged_clothes) - . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") - if(blood_DNA) - . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color()) - -/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE) - ..() - if(ismob(loc)) - var/mob/M = loc - M.update_inv_gloves() - -// Called just before an attack_hand(), in mob/UnarmedAttack() -/obj/item/clothing/gloves/proc/Touch(atom/A, proximity) - return FALSE // return TRUE to cancel attack_hand() +/obj/item/clothing/gloves + name = "gloves" + gender = PLURAL //Carn: for grammarically correct text-parsing + w_class = WEIGHT_CLASS_SMALL + icon = 'icons/obj/clothing/gloves.dmi' + siemens_coefficient = 0.5 + body_parts_covered = HANDS + slot_flags = ITEM_SLOT_GLOVES + attack_verb = list("challenged") + var/transfer_prints = FALSE + var/transfer_blood = 0 + strip_delay = 20 + equip_delay_other = 40 + +/obj/item/clothing/gloves/ComponentInitialize() + . = ..() + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/gloves/clean_blood) + +/obj/item/clothing/gloves/clean_blood(datum/source, strength) + . = ..() + transfer_blood = 0 + +/obj/item/clothing/gloves/suicide_act(mob/living/carbon/user) + user.visible_message("\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!") + return OXYLOSS + +/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE) + . = list() + if(!isinhands) + if(damaged_clothes) + . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") + if(blood_DNA) + . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", color = blood_DNA_to_color()) + +/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE) + ..() + if(ismob(loc)) + var/mob/M = loc + M.update_inv_gloves() + +// Called just before an attack_hand(), in mob/UnarmedAttack() +/obj/item/clothing/gloves/proc/Touch(atom/A, proximity) + return FALSE // return TRUE to cancel attack_hand() diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 44644962..9b63fdef 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -238,26 +238,62 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = -5,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = -5, "fire" = 0, "acid" = 0) equip_delay_other = 140 var/datum/brain_trauma/mild/phobia/paranoia + var/warped = FALSE clothing_flags = IGNORE_HAT_TOSS +/obj/item/clothing/head/foilhat/Initialize(mapload) + . = ..() + if(!warped) + AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, 6, TRUE, null, CALLBACK(src, .proc/warp_up)) + else + warp_up() + /obj/item/clothing/head/foilhat/equipped(mob/living/carbon/human/user, slot) - ..() - if(slot == SLOT_HEAD) - if(paranoia) - QDEL_NULL(paranoia) - paranoia = new() - user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies") - to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ") + . = ..() + if(slot != SLOT_HEAD || warped) + return + if(paranoia) + QDEL_NULL(paranoia) + paranoia = new() + user.gain_trauma(paranoia, TRAUMA_RESILIENCE_MAGIC, "conspiracies") + to_chat(user, "As you don the foiled hat, an entire world of conspiracy theories and seemingly insane ideas suddenly rush into your mind. What you once thought unbelievable suddenly seems.. undeniable. Everything is connected and nothing happens just by accident. You know too much and now they're out to get you. ") + +/obj/item/clothing/head/foilhat/MouseDrop(atom/over_object) + //God Im sorry + if(!warped && iscarbon(usr)) + var/mob/living/carbon/C = usr + if(src == C.head) + to_chat(C, "Why would you want to take this off? Do you want them to get into your mind?!") + return + return ..() /obj/item/clothing/head/foilhat/dropped(mob/user) - ..() + . = ..() if(paranoia) QDEL_NULL(paranoia) +/obj/item/clothing/head/foilhat/proc/warp_up() + name = "scorched tinfoil hat" + desc = "A badly warped up hat. Quite unprobable this will still work against any of fictional and contemporary dangers it used to." + warped = TRUE + if(!isliving(loc) || !paranoia) + return + var/mob/living/target = loc + if(target.get_item_by_slot(SLOT_HEAD) != src) + return + QDEL_NULL(paranoia) + if(!target.IsUnconscious()) + to_chat(target, "Your zealous conspirationism rapidly dissipates as the donned hat warps up into a ruined mess. All those theories starting to sound like nothing but a ridicolous fanfare.") + /obj/item/clothing/head/foilhat/attack_hand(mob/user) - if(iscarbon(user)) + if(!warped && iscarbon(user)) var/mob/living/carbon/C = user if(src == C.head) to_chat(user, "Why would you want to take this off? Do you want them to get into your mind?!") return - ..() + return ..() + +/obj/item/clothing/head/foilhat/microwave_act(obj/machinery/microwave/M) + . = ..() + if(!warped) + warp_up() diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index b420ee67..7eaf05f2 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -1,113 +1,113 @@ -/obj/item/clothing/shoes - name = "shoes" - icon = 'icons/obj/clothing/shoes.dmi' - desc = "Comfortable-looking shoes." - gender = PLURAL //Carn: for grammarically correct text-parsing - var/chained = 0 - - body_parts_covered = FEET - slot_flags = ITEM_SLOT_FEET - - permeability_coefficient = 0.5 - slowdown = SHOES_SLOWDOWN - var/blood_state = BLOOD_STATE_NOT_BLOODY - var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) - var/offset = 0 - var/equipped_before_drop = FALSE - - //CITADEL EDIT Enables digitigrade shoe styles - var/adjusted = NORMAL_STYLE - mutantrace_variation = MUTANTRACE_VARIATION - var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans - var/last_blood_DNA = "" //same as last one - -/obj/item/clothing/shoes/ComponentInitialize() - . = ..() - AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /obj/item/clothing/shoes/clean_blood))) - -/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user) - if(rand(2)>1) - user.visible_message("[user] begins tying \the [src] up waaay too tightly! It looks like [user.p_theyre()] trying to commit suicide!") - var/obj/item/bodypart/l_leg = user.get_bodypart(BODY_ZONE_L_LEG) - var/obj/item/bodypart/r_leg = user.get_bodypart(BODY_ZONE_R_LEG) - if(l_leg) - l_leg.dismember() - playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - if(r_leg) - r_leg.dismember() - playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return BRUTELOSS - else//didnt realize this suicide act existed (was in miscellaneous.dm) and didnt want to remove it, so made it a 50/50 chance. Why not! - user.visible_message("[user] is bashing [user.p_their()] own head in with [src]! Ain't that a kick in the head?") - for(var/i = 0, i < 3, i++) - sleep(3) - playsound(user, 'sound/weapons/genhit2.ogg', 50, 1) - return(BRUTELOSS) - -/obj/item/clothing/shoes/transfer_blood_dna(list/blood_dna, diseases) - ..() - if(blood_dna.len) - last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works - last_blood_DNA = blood_dna[blood_dna.len] - -/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE) - . = list() - if(!isinhands) - var/bloody = FALSE - if(blood_DNA) - bloody = TRUE - else - bloody = bloody_shoes[BLOOD_STATE_BLOOD] - - if(damaged_clothes) - . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") - if(bloody) - if(adjusted == NORMAL_STYLE) - . += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color()) - else - . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color()) - -/obj/item/clothing/shoes/equipped(mob/user, slot) - . = ..() - - if(mutantrace_variation && ishuman(user)) - var/mob/living/carbon/human/H = user - if(DIGITIGRADE in H.dna.species.species_traits) - adjusted = ALT_STYLE - H.update_inv_shoes() - else if(adjusted == ALT_STYLE) - adjusted = NORMAL_STYLE - H.update_inv_shoes() - - if(offset && slot_flags & slotdefine2slotbit(slot)) - user.pixel_y += offset - worn_y_dimension -= (offset * 2) - user.update_inv_shoes() - equipped_before_drop = TRUE - -/obj/item/clothing/shoes/proc/restore_offsets(mob/user) - equipped_before_drop = FALSE - user.pixel_y -= offset - worn_y_dimension = world.icon_size - -/obj/item/clothing/shoes/dropped(mob/user) - if(offset && equipped_before_drop) - restore_offsets(user) - . = ..() - -/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE) - ..() - if(ismob(loc)) - var/mob/M = loc - M.update_inv_shoes() - -/obj/item/clothing/shoes/clean_blood(datum/source, strength) - . = ..() - bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) - blood_state = BLOOD_STATE_NOT_BLOODY - if(ismob(loc)) - var/mob/M = loc - M.update_inv_shoes() - -/obj/item/proc/negates_gravity() - return FALSE +/obj/item/clothing/shoes + name = "shoes" + icon = 'icons/obj/clothing/shoes.dmi' + desc = "Comfortable-looking shoes." + gender = PLURAL //Carn: for grammarically correct text-parsing + var/chained = 0 + + body_parts_covered = FEET + slot_flags = ITEM_SLOT_FEET + + permeability_coefficient = 0.5 + slowdown = SHOES_SLOWDOWN + var/blood_state = BLOOD_STATE_NOT_BLOODY + var/list/bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) + var/offset = 0 + var/equipped_before_drop = FALSE + + //CITADEL EDIT Enables digitigrade shoe styles + var/adjusted = NORMAL_STYLE + mutantrace_variation = MUTANTRACE_VARIATION + var/last_bloodtype = "" //used to track the last bloodtype to have graced these shoes; makes for better performing footprint shenanigans + var/last_blood_DNA = "" //same as last one + +/obj/item/clothing/shoes/ComponentInitialize() + . = ..() + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /obj/item/clothing/shoes/clean_blood) + +/obj/item/clothing/shoes/suicide_act(mob/living/carbon/user) + if(rand(2)>1) + user.visible_message("[user] begins tying \the [src] up waaay too tightly! It looks like [user.p_theyre()] trying to commit suicide!") + var/obj/item/bodypart/l_leg = user.get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/r_leg = user.get_bodypart(BODY_ZONE_R_LEG) + if(l_leg) + l_leg.dismember() + playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + if(r_leg) + r_leg.dismember() + playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return BRUTELOSS + else//didnt realize this suicide act existed (was in miscellaneous.dm) and didnt want to remove it, so made it a 50/50 chance. Why not! + user.visible_message("[user] is bashing [user.p_their()] own head in with [src]! Ain't that a kick in the head?") + for(var/i = 0, i < 3, i++) + sleep(3) + playsound(user, 'sound/weapons/genhit2.ogg', 50, 1) + return(BRUTELOSS) + +/obj/item/clothing/shoes/transfer_blood_dna(list/blood_dna, diseases) + ..() + if(blood_dna.len) + last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works + last_blood_DNA = blood_dna[blood_dna.len] + +/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE) + . = list() + if(!isinhands) + var/bloody = FALSE + if(blood_DNA) + bloody = TRUE + else + bloody = bloody_shoes[BLOOD_STATE_BLOOD] + + if(damaged_clothes) + . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") + if(bloody) + if(adjusted == NORMAL_STYLE) + . += mutable_appearance('icons/effects/blood.dmi', "shoeblood", color = blood_DNA_to_color()) + else + . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood", color = blood_DNA_to_color()) + +/obj/item/clothing/shoes/equipped(mob/user, slot) + . = ..() + + if(mutantrace_variation && ishuman(user)) + var/mob/living/carbon/human/H = user + if(DIGITIGRADE in H.dna.species.species_traits) + adjusted = ALT_STYLE + H.update_inv_shoes() + else if(adjusted == ALT_STYLE) + adjusted = NORMAL_STYLE + H.update_inv_shoes() + + if(offset && slot_flags & slotdefine2slotbit(slot)) + user.pixel_y += offset + worn_y_dimension -= (offset * 2) + user.update_inv_shoes() + equipped_before_drop = TRUE + +/obj/item/clothing/shoes/proc/restore_offsets(mob/user) + equipped_before_drop = FALSE + user.pixel_y -= offset + worn_y_dimension = world.icon_size + +/obj/item/clothing/shoes/dropped(mob/user) + if(offset && equipped_before_drop) + restore_offsets(user) + . = ..() + +/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE) + ..() + if(ismob(loc)) + var/mob/M = loc + M.update_inv_shoes() + +/obj/item/clothing/shoes/clean_blood(datum/source, strength) + . = ..() + bloody_shoes = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) + blood_state = BLOOD_STATE_NOT_BLOODY + if(ismob(loc)) + var/mob/M = loc + M.update_inv_shoes() + +/obj/item/proc/negates_gravity() + return FALSE diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index 5893e970..560455b5 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -432,7 +432,7 @@ /obj/item/clothing/suit/space/hardsuit/wizard/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, FALSE) + AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE) //Medical hardsuit /obj/item/clothing/head/helmet/space/hardsuit/medical @@ -604,7 +604,6 @@ armor = list("melee" = 30, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 75) item_color = "ancient" resistance_flags = FIRE_PROOF - var/datum/component/mobhook /obj/item/clothing/suit/space/hardsuit/ancient name = "prototype RIG hardsuit" @@ -616,7 +615,7 @@ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ancient resistance_flags = FIRE_PROOF var/footstep = 1 - var/datum/component/mobhook + var/mob/listeningTo /obj/item/clothing/suit/space/hardsuit/ancient/mason name = "M.A.S.O.N RIG" @@ -673,20 +672,24 @@ /obj/item/clothing/suit/space/hardsuit/ancient/equipped(mob/user, slot) . = ..() - if (slot == SLOT_WEAR_SUIT) - if (mobhook && mobhook.parent != user) - QDEL_NULL(mobhook) - if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_mob_move))) - else - QDEL_NULL(mobhook) + if(slot != SLOT_WEAR_SUIT) + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + return + if(listeningTo == user) + return + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move) + listeningTo = user /obj/item/clothing/suit/space/hardsuit/ancient/dropped() . = ..() - QDEL_NULL(mobhook) + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) /obj/item/clothing/suit/space/hardsuit/ancient/Destroy() - QDEL_NULL(mobhook) // mobhook is not our component + listeningTo = null return ..() /////////////SHIELDED////////////////////////////////// diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index d2423a3f..85b55607 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -368,6 +368,10 @@ Contains: resistance_flags = FIRE_PROOF mutantrace_variation = NO_MUTANTRACE_VARIATION +/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD) + /obj/item/clothing/suit/space/hardsuit/ert/paranormal name = "paranormal response team suit" desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats." @@ -380,7 +384,7 @@ Contains: /obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING) /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor name = "inquisitor's hardsuit" @@ -408,16 +412,12 @@ Contains: /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/miner name = "inquisitor's hardsuit" - icon_state = "hardsuit-inq" - item_state = "hardsuit-inq" helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/miner armor = list("melee" = 70, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 60, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 80) slowdown = 1 /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/miner name = "inquisitor's helmet" - icon_state = "hardsuit0-inq" - item_state = "hardsuit0-inq" armor = list("melee" = 70, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 60, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 80) /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/miner diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index 6ec2865f..91c7204c 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -53,8 +53,8 @@ /datum/reagent/carpet, /datum/reagent/firefighting_foam, /datum/reagent/consumable/tearjuice, - /datum/reagent/medicine/strange_reagent - + /datum/reagent/medicine/strange_reagent, + /datum/reagent/medicine/copium ) //needs to be chemid unit checked at some point diff --git a/code/modules/fields/fields.dm b/code/modules/fields/fields.dm index 5e34c934..5b0b4bc1 100644 --- a/code/modules/fields/fields.dm +++ b/code/modules/fields/fields.dm @@ -283,7 +283,7 @@ var/field_type = /datum/proximity_monitor/advanced/debug var/operating = FALSE var/datum/proximity_monitor/advanced/current = null - var/datum/component/mobhook + var/mob/listeningTo /obj/item/multitool/field_debug/Initialize() . = ..() @@ -292,7 +292,7 @@ /obj/item/multitool/field_debug/Destroy() STOP_PROCESSING(SSobj, src) QDEL_NULL(current) - QDEL_NULL(mobhook) + listeningTo = null return ..() /obj/item/multitool/field_debug/proc/setup_debug_field() @@ -303,16 +303,20 @@ /obj/item/multitool/field_debug/attack_self(mob/user) operating = !operating to_chat(user, "You turn [src] [operating? "on":"off"].") - QDEL_NULL(mobhook) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null if(!istype(current) && operating) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_mob_move))) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move) + listeningTo = user setup_debug_field() else if(!operating) QDEL_NULL(current) /obj/item/multitool/field_debug/dropped() . = ..() - QDEL_NULL(mobhook) + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null /obj/item/multitool/field_debug/proc/on_mob_move() check_turf(get_turf(src)) diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index 25c67cc3..c59a8004 100644 --- a/code/modules/fields/timestop.dm +++ b/code/modules/fields/timestop.dm @@ -133,6 +133,7 @@ /datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/L) if(L.anti_magic_check(check_anti_magic, check_holy)) + immune += L return L.Stun(20, 1, 1) frozen_mobs[L] = L.anchored diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index f229c0ce..e5aa0c3d 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -138,7 +138,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( Show() /obj/effect/hallucination/simple/Destroy() - if(target.client) + if(target && target.client) target.client.images.Remove(current_image) active = FALSE return ..() diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm index 8fa96603..c4e63937 100644 --- a/code/modules/food_and_drinks/food/snacks/meat.dm +++ b/code/modules/food_and_drinks/food/snacks/meat.dm @@ -191,7 +191,7 @@ desc = "A synthetic chunk of meat." icon_state = "meatproduct" //growing meat will make it look like a lumpo foodtype = RAW | MEAT //hurr durr chemicals we're harmed in the production of this meat thus its non-vegan. - cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/meatproduct + cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/plain/meatproduct /obj/item/reagent_containers/food/snacks/meat/slab/meatproduct name = "meat product" @@ -280,7 +280,7 @@ bitesize = 4 tastes = list("meat" = 1, "wheat" = 1) foodtype = GRAIN - cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/meatproduct + cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/plain/meatproduct /obj/item/reagent_containers/food/snacks/meat/slab/gorilla name = "gorilla meat" @@ -340,7 +340,7 @@ /obj/item/reagent_containers/food/snacks/meat/steak/plain foodtype = MEAT -/obj/item/reagent_containers/food/snacks/meat/steak/meatproduct +/obj/item/reagent_containers/food/snacks/meat/steak/plain/meatproduct foodtype = MEAT icon_state = "meatproduct_steak" @@ -497,4 +497,4 @@ /obj/item/reagent_containers/food/snacks/meat/cutlet/chicken name = "chicken cutlet" tastes = list("chicken" = 1) - icon_state = "bird_cutlet_cooked" \ No newline at end of file + icon_state = "bird_cutlet_cooked" diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index 27ee5481..6bf7fb49 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -46,7 +46,8 @@ God bless America. /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/food/condiment, /obj/item/storage/part_replacer, - /obj/item/his_grace)) + /obj/item/his_grace, + /obj/item/portallight)) var/datum/looping_sound/deep_fryer/fry_loop /obj/machinery/deepfryer/Initialize() diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm index adf710d9..54cfd0bd 100644 --- a/code/modules/hydroponics/grown/melon.dm +++ b/code/modules/hydroponics/grown/melon.dm @@ -64,14 +64,14 @@ var/uses = 1 if(seed) uses = round(seed.potency / 20) - AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_HANDS, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god /obj/item/reagent_containers/food/snacks/grown/holymelon/proc/block_magic(mob/user, major) if(major) - visible_message("[src] hums slightly, and seems to decay a bit.") + to_chat(user, "[src] hums slightly, and seems to decay a bit.") /obj/item/reagent_containers/food/snacks/grown/holymelon/proc/expire(mob/user) - visible_message("[src] rapidly turns into ash!") + to_chat(user, "[src] rapidly turns into ash!") qdel(src) new /obj/effect/decal/cleanable/ash(drop_location()) diff --git a/code/modules/jobs/job_types/civilian_chaplain.dm b/code/modules/jobs/job_types/civilian_chaplain.dm index 1a74eec9..5f3daf1b 100644 --- a/code/modules/jobs/job_types/civilian_chaplain.dm +++ b/code/modules/jobs/job_types/civilian_chaplain.dm @@ -12,6 +12,7 @@ Chaplain spawn_positions = 1 supervisors = "the head of personnel" selection_color = "#dddddd" + custom_spawn_text = "You're playing a job that is essential for when the station deals with paranormal threats. While you have access to weapons, armor and tools such as your nullrod and bible, this does not mean you should hunt those threats unless warranted. If you have any questions, don't hesitate to ask mentors." outfit = /datum/outfit/job/chaplain diff --git a/code/modules/mapping/minimaps.dm b/code/modules/mapping/minimaps.dm index c347a8d7..7a62e9ab 100644 --- a/code/modules/mapping/minimaps.dm +++ b/code/modules/mapping/minimaps.dm @@ -1,21 +1,27 @@ /datum/minimap - var/name + var/name = "minimap" + var/icon/overlay_icon + // The map icons var/icon/map_icon var/icon/meta_icon - var/icon/overlay_icon + var/list/color_area_names = list() + var/minx var/maxx var/miny var/maxy - var/z_level - var/id = 0 - var/static/next_id = 0 -/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name) + var/z_level + var/id = "" + +/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name = "minimap") + if(!z) + CRASH("ERROR: new minimap requested without z level") //CRASH to halt the operatio + src.name = name - id = ++next_id z_level = z + id = "[md5("[z_level]" + src.name + REF(src))]" //use it's own md5 as a special identifier var/crop_x1 = x2 var/crop_x2 = x1 @@ -25,10 +31,11 @@ // do the generating map_icon = new('html/blank.png') meta_icon = new('html/blank.png') - map_icon.Scale(x2-x1+1, y2-y1+1) // arrays start at 1 - meta_icon.Scale(x2-x1+1, y2-y1+1) + map_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) // arrays start at 1 + meta_icon.Scale(x2 - x1 + 1, y2 - y1 + 1) + var/list/area_to_color = list() - for(var/turf/T in block(locate(x1,y1,z),locate(x2,y2,z))) + for(var/turf/T in block(locate(x1, y1, z_level), locate(x2, y2, z_level))) var/area/A = T.loc var/img_x = T.x - x1 + 1 // arrays start at 1 var/img_y = T.y - y1 + 1 @@ -37,21 +44,26 @@ crop_x2 = max(crop_x2, T.x) crop_y1 = min(crop_y1, T.y) crop_y2 = max(crop_y2, T.y) + var/meta_color = area_to_color[A] if(!meta_color) - meta_color = rgb(rand(0,255),rand(0,255),rand(0,255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens + meta_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens area_to_color[A] = meta_color color_area_names[meta_color] = A.name meta_icon.DrawBox(meta_color, img_x, img_y) + if(istype(T, /turf/closed/wall)) map_icon.DrawBox("#000000", img_x, img_y) + else if(!istype(A, /area/space)) var/color = A.minimap_color || "#FF00FF" if(locate(/obj/machinery/power/solar) in T) color = "#02026a" + if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T)) color = BlendRGB(color, "#000000", 0.5) map_icon.DrawBox(color, img_x, img_y) + map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2) meta_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2) minx = crop_x1 @@ -60,14 +72,17 @@ maxy = crop_y2 overlay_icon = new(map_icon) overlay_icon.Scale(16, 16) - -/datum/minimap/proc/send(mob/user) + //we're done baking, now we ship it. register_asset("minimap-[id].png", map_icon) register_asset("minimap-[id]-meta.png", meta_icon) - send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon), verify=FALSE) + +/datum/minimap/proc/send(mob/user) + if(!id) + CRASH("ERROR: send called, but the minimap id is null/missing. ID: [id]") + send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon)) /datum/minimap_group - var/list/minimaps + var/list/minimaps = list() var/static/next_id = 0 var/id var/name @@ -75,45 +90,62 @@ /datum/minimap_group/New(list/maps, name) id = ++next_id src.name = name - minimaps = maps || list() + if(maps) + minimaps = maps /datum/minimap_group/proc/show(mob/user) if(!length(minimaps)) to_chat(user, "ERROR: Attempted to access an empty datum/minimap_group. This should probably not happen.") return + var/list/datas = list() var/list/info = list() - var/datum/minimap/first_map = minimaps[1] - for(var/i in 1 to length(minimaps)) + + for(var/i in 1 to length(minimaps))// OLD: for(var/i in 1 to length(minimaps)) var/datum/minimap/M = minimaps[i] M.send(user) - info += "
    " + info += {" +
    +
    + + +
    +
    +
    + "} datas += json_encode(M.color_area_names); - info = info.Join() - var/html = {" - - - - - - -[name] - -[info] -"} + + + "} - user << browse(html, "window=minimap_[id];size=768x[round(768 / first_map.map_icon.Width() * first_map.map_icon.Height() + 50)]") + var/datum/browser/popup = new(user, "minimap_[id]", name, 500, 700) + popup.add_head_content(headerJS) //set the head + popup.set_content(info) + var/datum/minimap/MICO = minimaps[1] + popup.set_title_image(MICO.overlay_icon) + popup.open(FALSE) diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index 509caf81..e013137b 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -95,8 +95,14 @@ Doesn't work on other aliens/AI.*/ var/mob/living/M = input("Select who to whisper to:","Whisper to?",null) as null|mob in options if(!M) return 0 + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return FALSE var/msg = sanitize(input("Message:", "Alien Whisper") as text|null) if(msg) + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(user, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return log_directed_talk(user, M, msg, LOG_SAY, tag="alien whisper") to_chat(M, "You hear a strange, alien voice in your head...[msg]") to_chat(user, "You said: \"[msg]\" to [M]") diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 60113b98..798a73f4 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -29,7 +29,7 @@ . = ..() - AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT = CALLBACK(src, /mob/living/carbon/human/clean_blood))) + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /mob/living/carbon/human/clean_blood) /mob/living/carbon/human/ComponentInitialize() diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 6d811bdc..137cca07 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -603,6 +603,8 @@ return FALSE if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice return FALSE + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + return FALSE if(M in linked_mobs) return FALSE linked_mobs.Add(M) @@ -688,9 +690,14 @@ var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options if(!M) return - + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return var/msg = sanitize(input("Message:", "Telepathy") as text|null) if(msg) + if(M.anti_magic_check(FALSE, FALSE, TRUE, 0)) + to_chat(H, "As you try to communicate with [M], you're suddenly stopped by a vision of a massive tinfoil wall that streches beyond visible range. It seems you've been foiled.") + return log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy") to_chat(M, "You hear an alien voice in your head... [msg]") to_chat(H, "You telepathically said: \"[msg]\" to [M]") diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 6c1ac8b1..17388825 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -88,7 +88,7 @@ to_chat(H, "[victim] doesn't have blood!") return V.drain_cooldown = world.time + 30 - if(victim.anti_magic_check(FALSE, TRUE)) + if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0)) to_chat(victim, "[H] tries to bite you, but stops before touching you!") to_chat(H, "[victim] is blessed! You stop just in time to avoid catching fire.") return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5b8bf4bc..d457a3d5 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -873,6 +873,8 @@ return 0 if(digitalcamo || digitalinvis) return 0 + if(ismimic(src)) // Are we a mimic? Mimics should not be tracked to prevent AI camera cheese. + return 0 // Now, are they viewable by a camera? (This is last because it's the most intensive check) if(!near_camera(src)) @@ -974,7 +976,7 @@ apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked) -/mob/living/anti_magic_check(magic = TRUE, holy = FALSE) +/mob/living/anti_magic_check(magic = TRUE, holy = FALSE, chargecost = 1, self = FALSE) . = ..() if(.) return diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 04d241d2..8e7ebc06 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -892,6 +892,7 @@ /mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0) . = ..() if(.) //successfully ressuscitated from death + set_eyeobj_visible(TRUE) set_core_display_icon(display_icon_override) /mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 3804bfe5..8864abd6 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -18,6 +18,7 @@ update_canmove() if(eyeobj) eyeobj.setLoc(get_turf(src)) + set_eyeobj_visible(FALSE) GLOB.shuttle_caller_list -= src SSshuttle.autoEvac() diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index e5484a3c..7477ba77 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -6,6 +6,8 @@ /mob/camera/aiEye name = "Inactive AI Eye" + icon_state = "ai_camera" + icon = 'icons/mob/cameramob.dmi' invisibility = INVISIBILITY_MAXIMUM hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST) var/list/visibleCameraChunks = list() @@ -158,11 +160,11 @@ cameraFollow = null unset_machine() - if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj)) + if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) to_chat(src, "ERROR: Eyeobj not found. Creating new eye...") create_eye() - eyeobj.setLoc(loc) + eyeobj?.setLoc(loc) /mob/living/silicon/ai/proc/create_eye() if(eyeobj) @@ -172,6 +174,13 @@ eyeobj.ai = src eyeobj.setLoc(loc) eyeobj.name = "[name] (AI Eye)" + set_eyeobj_visible(TRUE) + +/mob/living/silicon/ai/proc/set_eyeobj_visible(state = TRUE) + if(!eyeobj) + return + eyeobj.mouse_opacity = state ? MOUSE_OPACITY_ICON : initial(eyeobj.mouse_opacity) + eyeobj.invisibility = state ? INVISIBILITY_OBSERVER : initial(eyeobj.invisibility) /mob/living/silicon/ai/verb/toggle_acceleration() set category = "AI Commands" diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 0fd33110..15a04235 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -19,7 +19,7 @@ // messenging the client malfhacked(malfhack) - if(!eyeobj || QDELETED(eyeobj) || !eyeobj.loc) + if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc)) view_core() if(machine) diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm index 742edfc5..98f38652 100644 --- a/code/modules/mob/living/silicon/ai/login.dm +++ b/code/modules/mob/living/silicon/ai/login.dm @@ -6,6 +6,7 @@ O.mode = 1 O.emotion = "Neutral" O.update() + set_eyeobj_visible(TRUE) if(multicam_on) end_multicam() view_core() diff --git a/code/modules/mob/living/silicon/ai/logout.dm b/code/modules/mob/living/silicon/ai/logout.dm index 7989d1c1..73161f12 100644 --- a/code/modules/mob/living/silicon/ai/logout.dm +++ b/code/modules/mob/living/silicon/ai/logout.dm @@ -4,4 +4,5 @@ var/obj/machinery/status_display/ai/O = each O.mode = 0 O.update() + set_eyeobj_visible(FALSE) view_core() diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index fcc068b7..b358cefd 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -120,6 +120,9 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room) /mob/camera/aiEye/pic_in_pic name = "Secondary AI Eye" + invisibility = INVISIBILITY_OBSERVER + mouse_opacity = MOUSE_OPACITY_ICON + icon_state = "ai_pip_camera" var/obj/screen/movable/pic_in_pic/ai/screen var/list/cameras_telegraphed = list() var/telegraph_cameras = TRUE diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index 23531e9f..25519842 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -21,6 +21,9 @@ locked = FALSE //unlock cover + if(connected_ai) + deployed = FALSE + update_canmove() if(!QDELETED(builtInCamera) && builtInCamera.status) builtInCamera.toggle_cam(src,0) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index f75607df..972bf29c 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1232,7 +1232,6 @@ /mob/living/silicon/robot/proc/TryConnectToAI() set_connected_ai(select_active_ai_with_fewest_borgs(z)) if(connected_ai) - connected_ai.connected_robots += src lawsync() lawupdate = 1 return TRUE @@ -1270,4 +1269,4 @@ var/mob/living/silicon/ai/old_ai = . old_ai.connected_robots -= src if(connected_ai) - connected_ai.connected_robots |= src \ No newline at end of file + connected_ai.connected_robots |= src diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 5c99826d..fac2f8d3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -804,15 +804,17 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA if(client) client << output(null, "statbrowser:check_spells") -/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE) - if(!magic && !holy) +/mob/proc/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE) + if(!magic && !holy && !tinfoil) return var/list/protection_sources = list() - if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, magic, holy, protection_sources) & COMPONENT_BLOCK_MAGIC) + if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, src, magic, holy, tinfoil, chargecost, self, protection_sources) & COMPONENT_BLOCK_MAGIC) if(protection_sources.len) return pick(protection_sources) else return src + if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) + return src //You can buckle on mobs if you're next to them since most are dense /mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) diff --git a/code/modules/oracle_ui/assets.dm b/code/modules/oracle_ui/assets.dm index 5d26d80a..348860b4 100644 --- a/code/modules/oracle_ui/assets.dm +++ b/code/modules/oracle_ui/assets.dm @@ -1,8 +1,11 @@ +/datum/asset/group/oui_theme_nano + children = list( + /datum/asset/simple/jquery, + /datum/asset/simple/oui_theme_nano + ) + /datum/asset/simple/oui_theme_nano assets = list( - // JavaScript - "sui-nano-common.js" = 'html/oracle_ui/themes/nano/sui-nano-common.js', - "sui-nano-jquery.min.js" = 'html/oracle_ui/themes/nano/sui-nano-jquery.min.js', - // Stylesheets - "sui-nano-common.css" = 'html/oracle_ui/themes/nano/sui-nano-common.css', + "sui-nano-common.js" = 'html/oracle_ui/themes/nano/sui-nano-common.js', + "sui-nano-common.css" = 'html/oracle_ui/themes/nano/sui-nano-common.css', ) diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm index aa0cda91..f0aa9eae 100644 --- a/code/modules/projectiles/ammunition/energy/laser.dm +++ b/code/modules/projectiles/ammunition/energy/laser.dm @@ -59,6 +59,9 @@ /obj/item/ammo_casing/energy/laser/redtag/hitscan projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan +/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy + projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan/holy + /obj/item/ammo_casing/energy/xray projectile_type = /obj/item/projectile/beam/xray e_cost = 50 diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 353983e0..fd28694e 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -159,3 +159,65 @@ /obj/item/gun/energy/laser/redtag/hitscan ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan) + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain + name = "\improper holy lasrifle" + desc = "A lasrifle from the old Imperium. This one seems to be blessed by techpriests." + icon_state = "LaserAK" + item_state = null + force = 14 + pin = /obj/item/firing_pin/holy + icon = 'modular_citadel/icons/obj/guns/VGguns.dmi' + ammo_x_offset = 4 + ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy) + lefthand_file = 'modular_citadel/icons/mob/citadel/guns_lefthand.dmi' + righthand_file = 'modular_citadel/icons/mob/citadel/guns_righthand.dmi' + var/chaplain_spawnable = TRUE + total_mass = TOTAL_MASS_MEDIEVAL_WEAPON + throw_speed = 3 + throw_range = 4 + throwforce = 10 + obj_flags = UNIQUE_RENAME + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) + +/obj/item/gun/energy/laser/redtag/hitscan/chaplain/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer) + if(!ishuman(user) || !ishuman(target)) + return + + if(semicd) + return + + if(user == target) + target.visible_message("[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...", \ + "You stick [src] in your mouth, ready to pull the trigger...") + else + target.visible_message("[user] points [src] at [target]'s head, ready to pull the trigger...", \ + "[user] points [src] at your head, ready to pull the trigger...") + + semicd = TRUE + + if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(user) + if(user == target) + user.visible_message("[user] decided not to shoot.") + else if(target && target.Adjacent(user)) + target.visible_message("[user] has decided to spare [target]", "[user] has decided to spare your life!") + semicd = FALSE + return + + semicd = FALSE + + target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!") + + playsound('sound/weapons/dink.ogg', 30, 1) + + if((iscultist(target)) || (is_servant_of_ratvar(target))) + chambered.BB.damage *= 1500 + + else if(chambered && chambered.BB) + chambered.BB.damage *= 5 + + process_fire(target, user, TRUE, params) diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index e62392ff..f724f982 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -9,6 +9,7 @@ fire_sound = 'sound/weapons/emitter.ogg' flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_HUGE + var/checks_antimagic = FALSE var/max_charges = 6 var/charges = 0 var/recharge_rate = 4 @@ -31,6 +32,9 @@ return else no_den_usage = 0 + if(checks_antimagic && user.anti_magic_check(TRUE, FALSE, FALSE, 0, TRUE)) + to_chat(user, "Something is interfering with [src].") + return . = ..() /obj/item/gun/magic/can_shoot() diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index d5815205..52236ab6 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -87,14 +87,17 @@ max_charges = 10 //10, 5, 5, 4 /obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user) + ..() + charges-- + if(user.anti_magic_check()) + user.visible_message("[src] has no effect on [user]!") + return user.revive(full_heal = 1) if(iscarbon(user)) var/mob/living/carbon/C = user C.regenerate_limbs() C.regenerate_organs() to_chat(user, "You feel great!") - charges-- - ..() /obj/item/gun/magic/wand/resurrection/debug //for testing name = "debug wand of healing" diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index bcf44805..b6e6a01d 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -1,567 +1,570 @@ - -#define ZOOM_LOCK_AUTOZOOM_FREEMOVE 0 -#define ZOOM_LOCK_AUTOZOOM_ANGLELOCK 1 -#define ZOOM_LOCK_CENTER_VIEW 2 -#define ZOOM_LOCK_OFF 3 - -#define AUTOZOOM_PIXEL_STEP_FACTOR 48 - -#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1 - -/obj/item/gun/energy/beam_rifle - name = "particle acceleration rifle" - desc = "An energy-based anti material marksman rifle that uses highly charged particle beams moving at extreme velocities to decimate whatever is unfortunate enough to be targeted by one. \ - Hold down left click while scoped to aim, when weapon is fully aimed (Tracer goes from red to green as it charges), release to fire. Moving while aiming or \ - changing where you're pointing at while aiming will delay the aiming process depending on how much you changed." - icon = 'icons/obj/guns/energy.dmi' - icon_state = "esniper" - item_state = "esniper" - fire_sound = 'sound/weapons/beam_sniper.ogg' - slot_flags = ITEM_SLOT_BACK - force = 15 - materials = list() - recoil = 4 - ammo_x_offset = 3 - ammo_y_offset = 3 - modifystate = FALSE - weapon_weight = WEAPON_HEAVY - w_class = WEIGHT_CLASS_BULKY - ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) - cell_type = /obj/item/stock_parts/cell/beam_rifle - canMouseDown = TRUE - //Cit changes: beam rifle stats. - slowdown = 1 - item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND | NEEDS_PERMIT - pin = null - var/aiming = FALSE - var/aiming_time = 14 - var/aiming_time_fire_threshold = 5 - var/aiming_time_left = 14 - var/aiming_time_increase_user_movement = 7 - var/aiming_time_increase_angle_multiplier = 0.30 - var/last_process = 0 - - var/lastangle = 0 - var/aiming_lastangle = 0 - var/mob/current_user = null - var/list/obj/effect/projectile/tracer/current_tracers - - var/structure_piercing = 1 - var/structure_bleed_coeff = 0.7 - var/wall_pierce_amount = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 1 - var/aoe_structure_damage = 35 - var/aoe_fire_range = 1 - var/aoe_fire_chance = 100 - var/aoe_mob_range = 1 - var/aoe_mob_damage = 20 - var/impact_structure_damage = 75 - var/projectile_damage = 40 - var/projectile_stun = 0 - var/projectile_setting_pierce = TRUE - var/delay = 30 - var/lastfire = 0 - - //ZOOMING - var/zoom_current_view_increase = 0 - var/zoom_target_view_increase = 10 - var/zooming = FALSE - var/zoom_lock = ZOOM_LOCK_OFF - var/zooming_angle - var/current_zoom_x = 0 - var/current_zoom_y = 0 - - var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged") - var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty") - - var/datum/action/item_action/zoom_lock_action/zoom_lock_action - var/datum/component/mobhook - -/obj/item/gun/energy/beam_rifle/debug - delay = 0 - cell_type = /obj/item/stock_parts/cell/infinite - aiming_time = 0 - recoil = 0 - pin = /obj/item/firing_pin - -/obj/item/gun/energy/beam_rifle/equipped(mob/user) - set_user(user) - . = ..() - -/obj/item/gun/energy/beam_rifle/pickup(mob/user) - set_user(user) - . = ..() - -/obj/item/gun/energy/beam_rifle/dropped(mob/user) - set_user() - . = ..() - -/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action) - if(istype(action, /datum/action/item_action/zoom_lock_action)) - zoom_lock++ - if(zoom_lock > 3) - zoom_lock = 0 - switch(zoom_lock) - if(ZOOM_LOCK_AUTOZOOM_FREEMOVE) - to_chat(owner, "You switch [src]'s zooming processor to free directional.") - if(ZOOM_LOCK_AUTOZOOM_ANGLELOCK) - to_chat(owner, "You switch [src]'s zooming processor to locked directional.") - if(ZOOM_LOCK_CENTER_VIEW) - to_chat(owner, "You switch [src]'s zooming processor to center mode.") - if(ZOOM_LOCK_OFF) - to_chat(owner, "You disable [src]'s zooming system.") - reset_zooming() - -/obj/item/gun/energy/beam_rifle/proc/set_autozoom_pixel_offsets_immediate(current_angle) - if(zoom_lock == ZOOM_LOCK_CENTER_VIEW || zoom_lock == ZOOM_LOCK_OFF) - return - current_zoom_x = sin(current_angle) + sin(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase - current_zoom_y = cos(current_angle) + cos(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase - -/obj/item/gun/energy/beam_rifle/proc/handle_zooming() - if(!zooming || !check_user()) - return - set_autozoom_pixel_offsets_immediate(zooming_angle) - -/obj/item/gun/energy/beam_rifle/proc/start_zooming() - if(zoom_lock == ZOOM_LOCK_OFF) - return - zooming = TRUE - current_user.client.change_view(world.view + zoom_target_view_increase) - zoom_current_view_increase = zoom_target_view_increase - -/obj/item/gun/energy/beam_rifle/proc/stop_zooming(mob/user) - if(zooming) - zooming = FALSE - reset_zooming(user) - -/obj/item/gun/energy/beam_rifle/proc/reset_zooming(mob/user) - if(!user) - user = current_user - if(!user || !user.client) - return FALSE - animate(user.client, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW) - zoom_current_view_increase = 0 - user.client.change_view(CONFIG_GET(string/default_view)) - zooming_angle = 0 - current_zoom_x = 0 - current_zoom_y = 0 - -/obj/item/gun/energy/beam_rifle/update_icon() - cut_overlays() - var/obj/item/ammo_casing/energy/primary_ammo = ammo_type[1] - if(!QDELETED(cell) && (cell.charge > primary_ammo.e_cost)) - add_overlay(charged_overlay) - else - add_overlay(drained_overlay) - -/obj/item/gun/energy/beam_rifle/attack_self(mob/user) - projectile_setting_pierce = !projectile_setting_pierce - to_chat(user, "You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.") - aiming_beam() - -/obj/item/gun/energy/beam_rifle/Initialize() - . = ..() - fire_delay = delay - current_tracers = list() - START_PROCESSING(SSfastprocess, src) - zoom_lock_action = new(src) - -/obj/item/gun/energy/beam_rifle/Destroy() - STOP_PROCESSING(SSfastprocess, src) - set_user(null) - QDEL_LIST(current_tracers) - QDEL_NULL(mobhook) - return ..() - -/obj/item/gun/energy/beam_rifle/emp_act(severity) - . = ..() - if(. & EMP_PROTECT_SELF) - return - chambered = null - recharge_newshot() - -/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE) - var/diff = abs(aiming_lastangle - lastangle) - check_user() - if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update) - return - aiming_lastangle = lastangle - var/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new - P.gun = src - P.wall_pierce_amount = wall_pierce_amount - P.structure_pierce_amount = structure_piercing - P.do_pierce = projectile_setting_pierce - if(aiming_time) - var/percent = ((100/aiming_time)*aiming_time_left) - P.color = rgb(255 * percent,255 * ((100 - percent) / 100),0) - else - P.color = rgb(0, 255, 0) - var/turf/curloc = get_turf(src) - var/turf/targloc = get_turf(current_user.client.mouseObject) - if(!istype(targloc)) - if(!istype(curloc)) - return - targloc = get_turf_in_angle(lastangle, curloc, 10) - P.preparePixelProjectile(targloc, current_user, current_user.client.mouseParams, 0) - P.fire(lastangle) - -/obj/item/gun/energy/beam_rifle/process() - if(!aiming) - last_process = world.time - return - check_user() - handle_zooming() - aiming_time_left = max(0, aiming_time_left - (world.time - last_process)) - aiming_beam(TRUE) - last_process = world.time - -/obj/item/gun/energy/beam_rifle/proc/check_user(automatic_cleanup = TRUE) - if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! - if(automatic_cleanup) - stop_aiming() - set_user(null) - return FALSE - return TRUE - -/obj/item/gun/energy/beam_rifle/proc/process_aim() - if(istype(current_user) && current_user.client && current_user.client.mouseParams) - var/angle = mouse_angle_from_client(current_user.client) - current_user.setDir(angle2dir_cardinal(angle)) - var/difference = abs(closer_angle_difference(lastangle, angle)) - delay_penalty(difference * aiming_time_increase_angle_multiplier) - lastangle = angle - -/obj/item/gun/energy/beam_rifle/proc/on_mob_move() - check_user() - if(aiming) - delay_penalty(aiming_time_increase_user_movement) - process_aim() - aiming_beam(TRUE) - -/obj/item/gun/energy/beam_rifle/proc/start_aiming() - aiming_time_left = aiming_time - aiming = TRUE - process_aim() - aiming_beam(TRUE) - zooming_angle = lastangle - start_zooming() - -/obj/item/gun/energy/beam_rifle/proc/stop_aiming(mob/user) - set waitfor = FALSE - aiming_time_left = aiming_time - aiming = FALSE - QDEL_LIST(current_tracers) - stop_zooming(user) - -/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user) - if(user == current_user) - return - stop_aiming(current_user) - QDEL_NULL(mobhook) - if(istype(current_user)) - LAZYREMOVE(current_user.mousemove_intercept_objects, src) - current_user = null - if(istype(user)) - current_user = user - LAZYOR(current_user.mousemove_intercept_objects, src) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_mob_move))) - -/obj/item/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - if(aiming) - process_aim() - aiming_beam() - if(zoom_lock == ZOOM_LOCK_AUTOZOOM_FREEMOVE) - zooming_angle = lastangle - set_autozoom_pixel_offsets_immediate(zooming_angle) - return ..() - -/obj/item/gun/energy/beam_rifle/onMouseDown(object, location, params, mob/mob) - if(istype(mob)) - set_user(mob) - if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) - return - if((object in mob.contents) || (object == mob)) - return - start_aiming() - return ..() - -/obj/item/gun/energy/beam_rifle/onMouseUp(object, location, params, mob/M) - if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) - return - process_aim() - if(aiming_time_left <= aiming_time_fire_threshold && check_user()) - sync_ammo() - afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE) - stop_aiming() - QDEL_LIST(current_tracers) - return ..() - -/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE) - if(flag) //It's adjacent, is the user, or is on the user's person - if(target in user.contents) //can't shoot stuff inside us. - return - if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack - return - if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) - return - if(!passthrough && (aiming_time > aiming_time_fire_threshold)) - return - if(lastfire > world.time + delay) - return - lastfire = world.time - . = ..() - stop_aiming() - -/obj/item/gun/energy/beam_rifle/proc/sync_ammo() - for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents) - AC.sync_stats() - -/obj/item/gun/energy/beam_rifle/proc/delay_penalty(amount) - aiming_time_left = CLAMP(aiming_time_left + amount, 0, aiming_time) - -/obj/item/ammo_casing/energy/beam_rifle - name = "particle acceleration lens" - desc = "Don't look into barrel!" - var/wall_pierce_amount = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 1 - var/aoe_structure_damage = 30 - var/aoe_fire_range = 2 - var/aoe_fire_chance = 66 - var/aoe_mob_range = 1 - var/aoe_mob_damage = 20 - var/impact_structure_damage = 50 - var/projectile_damage = 40 - var/projectile_stun = 0 - var/structure_piercing = 2 - var/structure_bleed_coeff = 0.7 - var/do_pierce = TRUE - var/obj/item/gun/energy/beam_rifle/host - -/obj/item/ammo_casing/energy/beam_rifle/proc/sync_stats() - var/obj/item/gun/energy/beam_rifle/BR = loc - if(!istype(BR)) - stack_trace("Beam rifle syncing error") - host = BR - do_pierce = BR.projectile_setting_pierce - wall_pierce_amount = BR.wall_pierce_amount - wall_devastate = BR.wall_devastate - aoe_structure_range = BR.aoe_structure_range - aoe_structure_damage = BR.aoe_structure_damage - aoe_fire_range = BR.aoe_fire_range - aoe_fire_chance = BR.aoe_fire_chance - aoe_mob_range = BR.aoe_mob_range - aoe_mob_damage = BR.aoe_mob_damage - impact_structure_damage = BR.impact_structure_damage - projectile_damage = BR.projectile_damage - projectile_stun = BR.projectile_stun - delay = BR.delay - structure_piercing = BR.structure_piercing - structure_bleed_coeff = BR.structure_bleed_coeff - -/obj/item/ammo_casing/energy/beam_rifle/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") - . = ..() - var/obj/item/projectile/beam/beam_rifle/hitscan/HS_BB = BB - if(!istype(HS_BB)) - return - HS_BB.impact_direct_damage = projectile_damage - HS_BB.stun = projectile_stun - HS_BB.impact_structure_damage = impact_structure_damage - HS_BB.aoe_mob_damage = aoe_mob_damage - HS_BB.aoe_mob_range = CLAMP(aoe_mob_range, 0, 15) //Badmin safety lock - HS_BB.aoe_fire_chance = aoe_fire_chance - HS_BB.aoe_fire_range = aoe_fire_range - HS_BB.aoe_structure_damage = aoe_structure_damage - HS_BB.aoe_structure_range = CLAMP(aoe_structure_range, 0, 15) //Badmin safety lock - HS_BB.wall_devastate = wall_devastate - HS_BB.wall_pierce_amount = wall_pierce_amount - HS_BB.structure_pierce_amount = structure_piercing - HS_BB.structure_bleed_coeff = structure_bleed_coeff - HS_BB.do_pierce = do_pierce - HS_BB.gun = host - -/obj/item/ammo_casing/energy/beam_rifle/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread) - var/turf/curloc = get_turf(user) - if(!istype(curloc) || !BB) - return FALSE - var/obj/item/gun/energy/beam_rifle/gun = loc - if(!targloc && gun) - targloc = get_turf_in_angle(gun.lastangle, curloc, 10) - else if(!targloc) - return FALSE - var/firing_dir - if(BB.firer) - firing_dir = BB.firer.dir - if(!BB.suppressed && firing_effect_type) - new firing_effect_type(get_turf(src), firing_dir) - BB.preparePixelProjectile(target, user, params, spread) - BB.fire(gun? gun.lastangle : null, null) - BB = null - return TRUE - -/obj/item/ammo_casing/energy/beam_rifle/hitscan - projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan - select_name = "beam" - e_cost = 5000 - fire_sound = 'sound/weapons/beam_sniper.ogg' - -/obj/item/projectile/beam/beam_rifle - name = "particle beam" - icon = null - hitsound = 'sound/effects/explosion3.ogg' - damage = 0 //Handled manually. - damage_type = BURN - flag = "energy" - range = 150 - jitter = 10 - var/obj/item/gun/energy/beam_rifle/gun - var/structure_pierce_amount = 0 //All set to 0 so the gun can manually set them during firing. - var/structure_bleed_coeff = 0 - var/structure_pierce = 0 - var/do_pierce = TRUE - var/wall_pierce_amount = 0 - var/wall_pierce = 0 - var/wall_devastate = 0 - var/aoe_structure_range = 0 - var/aoe_structure_damage = 0 - var/aoe_fire_range = 0 - var/aoe_fire_chance = 0 - var/aoe_mob_range = 0 - var/aoe_mob_damage = 0 - var/impact_structure_damage = 0 - var/impact_direct_damage = 0 - var/turf/cached - var/list/pierced = list() - -/obj/item/projectile/beam/beam_rifle/proc/AOE(turf/epicenter) - set waitfor = FALSE - if(!epicenter) - return - new /obj/effect/temp_visual/explosion/fast(epicenter) - for(var/mob/living/L in range(aoe_mob_range, epicenter)) //handle aoe mob damage - L.adjustFireLoss(aoe_mob_damage) - to_chat(L, "\The [src] sears you!") - for(var/turf/T in range(aoe_fire_range, epicenter)) //handle aoe fire - if(prob(aoe_fire_chance)) - new /obj/effect/hotspot(T) - for(var/obj/O in range(aoe_structure_range, epicenter)) - if(!isitem(O)) - if(O.level == 1) //Please don't break underfloor items! - continue - O.take_damage(aoe_structure_damage * get_damage_coeff(O), BURN, "laser", FALSE) - -/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/target) - if(!do_pierce) - return FALSE - if(pierced[target]) //we already pierced them go away - return TRUE - if(isclosedturf(target)) - if(wall_pierce++ < wall_pierce_amount) - if(prob(wall_devastate)) - if(iswallturf(target)) - var/turf/closed/wall/W = target - W.dismantle_wall(TRUE, TRUE) - else - target.ex_act(EXPLODE_HEAVY) - return TRUE - if(ismovableatom(target)) - var/atom/movable/AM = target - if(AM.density && !AM.CanPass(src, get_turf(target)) && !ismob(AM)) - if(structure_pierce < structure_pierce_amount) - if(isobj(AM)) - var/obj/O = AM - O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE) - pierced[AM] = TRUE - structure_pierce++ - return TRUE - return FALSE - -/obj/item/projectile/beam/beam_rifle/proc/get_damage_coeff(atom/target) - if(istype(target, /obj/machinery/door)) - return 0.4 - if(istype(target, /obj/structure/window)) - return 0.5 - if(istype(target, /obj/structure/blob)) - return 0.65 //CIT CHANGE. - return 1 - -/obj/item/projectile/beam/beam_rifle/proc/handle_impact(atom/target) - if(isobj(target)) - var/obj/O = target - O.take_damage(impact_structure_damage * get_damage_coeff(target), BURN, "laser", FALSE) - if(isliving(target)) - var/mob/living/L = target - L.adjustFireLoss(impact_direct_damage) - L.emote("scream") - -/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target) - set waitfor = FALSE - if(!cached && !QDELETED(target)) - cached = get_turf(target) - if(nodamage) - return FALSE - playsound(cached, 'sound/effects/explosion3.ogg', 100, 1) - AOE(cached) - if(!QDELETED(target)) - handle_impact(target) - -/obj/item/projectile/beam/beam_rifle/Bump(atom/target) - if(check_pierce(target)) - permutated += target - trajectory_ignore_forcemove = TRUE - forceMove(target.loc) - trajectory_ignore_forcemove = FALSE - return FALSE - if(!QDELETED(target)) - cached = get_turf(target) - . = ..() - -/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE) - if(!QDELETED(target)) - cached = get_turf(target) - handle_hit(target) - . = ..() - -/obj/item/projectile/beam/beam_rifle/hitscan - icon_state = "" - hitscan = TRUE - tracer_type = /obj/effect/projectile/tracer/tracer/beam_rifle - var/constant_tracer = FALSE - -/obj/item/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, impacting = TRUE, highlander) - set waitfor = FALSE - if(isnull(highlander)) - highlander = constant_tracer - if(highlander && istype(gun)) - QDEL_LIST(gun.current_tracers) - for(var/datum/point/p in beam_segments) - gun.current_tracers += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, 0, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) - else - for(var/datum/point/p in beam_segments) - generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) - if(cleanup) - QDEL_LIST(beam_segments) - beam_segments = null - QDEL_NULL(beam_index) - -/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam - tracer_type = /obj/effect/projectile/tracer/tracer/aiming - name = "aiming beam" - hitsound = null - hitsound_wall = null - nodamage = TRUE - damage = 0 - constant_tracer = TRUE - hitscan_light_range = 0 - hitscan_light_intensity = 0 - hitscan_light_color_override = "#99ff99" - -/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target) - qdel(src) - return FALSE - -/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit() - qdel(src) - return FALSE + +#define ZOOM_LOCK_AUTOZOOM_FREEMOVE 0 +#define ZOOM_LOCK_AUTOZOOM_ANGLELOCK 1 +#define ZOOM_LOCK_CENTER_VIEW 2 +#define ZOOM_LOCK_OFF 3 + +#define AUTOZOOM_PIXEL_STEP_FACTOR 48 + +#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1 + +/obj/item/gun/energy/beam_rifle + name = "particle acceleration rifle" + desc = "An energy-based anti material marksman rifle that uses highly charged particle beams moving at extreme velocities to decimate whatever is unfortunate enough to be targeted by one. \ + Hold down left click while scoped to aim, when weapon is fully aimed (Tracer goes from red to green as it charges), release to fire. Moving while aiming or \ + changing where you're pointing at while aiming will delay the aiming process depending on how much you changed." + icon = 'icons/obj/guns/energy.dmi' + icon_state = "esniper" + item_state = "esniper" + fire_sound = 'sound/weapons/beam_sniper.ogg' + slot_flags = ITEM_SLOT_BACK + force = 15 + materials = list() + recoil = 4 + ammo_x_offset = 3 + ammo_y_offset = 3 + modifystate = FALSE + weapon_weight = WEAPON_HEAVY + w_class = WEIGHT_CLASS_BULKY + ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) + cell_type = /obj/item/stock_parts/cell/beam_rifle + canMouseDown = TRUE + //Cit changes: beam rifle stats. + slowdown = 1 + item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND | NEEDS_PERMIT + pin = null + var/aiming = FALSE + var/aiming_time = 14 + var/aiming_time_fire_threshold = 5 + var/aiming_time_left = 14 + var/aiming_time_increase_user_movement = 7 + var/aiming_time_increase_angle_multiplier = 0.30 + var/last_process = 0 + + var/lastangle = 0 + var/aiming_lastangle = 0 + var/mob/current_user = null + var/list/obj/effect/projectile/tracer/current_tracers + + var/structure_piercing = 1 + var/structure_bleed_coeff = 0.7 + var/wall_pierce_amount = 0 + var/wall_devastate = 0 + var/aoe_structure_range = 1 + var/aoe_structure_damage = 35 + var/aoe_fire_range = 1 + var/aoe_fire_chance = 100 + var/aoe_mob_range = 1 + var/aoe_mob_damage = 20 + var/impact_structure_damage = 75 + var/projectile_damage = 40 + var/projectile_stun = 0 + var/projectile_setting_pierce = TRUE + var/delay = 30 + var/lastfire = 0 + + //ZOOMING + var/zoom_current_view_increase = 0 + var/zoom_target_view_increase = 10 + var/zooming = FALSE + var/zoom_lock = ZOOM_LOCK_OFF + var/zooming_angle + var/current_zoom_x = 0 + var/current_zoom_y = 0 + + var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged") + var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty") + + var/datum/action/item_action/zoom_lock_action/zoom_lock_action + var/mob/listeningTo + +/obj/item/gun/energy/beam_rifle/debug + delay = 0 + cell_type = /obj/item/stock_parts/cell/infinite + aiming_time = 0 + recoil = 0 + pin = /obj/item/firing_pin + +/obj/item/gun/energy/beam_rifle/equipped(mob/user) + set_user(user) + . = ..() + +/obj/item/gun/energy/beam_rifle/pickup(mob/user) + set_user(user) + . = ..() + +/obj/item/gun/energy/beam_rifle/dropped(mob/user) + set_user() + . = ..() + +/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action) + if(istype(action, /datum/action/item_action/zoom_lock_action)) + zoom_lock++ + if(zoom_lock > 3) + zoom_lock = 0 + switch(zoom_lock) + if(ZOOM_LOCK_AUTOZOOM_FREEMOVE) + to_chat(owner, "You switch [src]'s zooming processor to free directional.") + if(ZOOM_LOCK_AUTOZOOM_ANGLELOCK) + to_chat(owner, "You switch [src]'s zooming processor to locked directional.") + if(ZOOM_LOCK_CENTER_VIEW) + to_chat(owner, "You switch [src]'s zooming processor to center mode.") + if(ZOOM_LOCK_OFF) + to_chat(owner, "You disable [src]'s zooming system.") + reset_zooming() + +/obj/item/gun/energy/beam_rifle/proc/set_autozoom_pixel_offsets_immediate(current_angle) + if(zoom_lock == ZOOM_LOCK_CENTER_VIEW || zoom_lock == ZOOM_LOCK_OFF) + return + current_zoom_x = sin(current_angle) + sin(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase + current_zoom_y = cos(current_angle) + cos(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase + +/obj/item/gun/energy/beam_rifle/proc/handle_zooming() + if(!zooming || !check_user()) + return + set_autozoom_pixel_offsets_immediate(zooming_angle) + +/obj/item/gun/energy/beam_rifle/proc/start_zooming() + if(zoom_lock == ZOOM_LOCK_OFF) + return + zooming = TRUE + current_user.client.change_view(world.view + zoom_target_view_increase) + zoom_current_view_increase = zoom_target_view_increase + +/obj/item/gun/energy/beam_rifle/proc/stop_zooming(mob/user) + if(zooming) + zooming = FALSE + reset_zooming(user) + +/obj/item/gun/energy/beam_rifle/proc/reset_zooming(mob/user) + if(!user) + user = current_user + if(!user || !user.client) + return FALSE + animate(user.client, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW) + zoom_current_view_increase = 0 + user.client.change_view(CONFIG_GET(string/default_view)) + zooming_angle = 0 + current_zoom_x = 0 + current_zoom_y = 0 + +/obj/item/gun/energy/beam_rifle/update_icon() + cut_overlays() + var/obj/item/ammo_casing/energy/primary_ammo = ammo_type[1] + if(!QDELETED(cell) && (cell.charge > primary_ammo.e_cost)) + add_overlay(charged_overlay) + else + add_overlay(drained_overlay) + +/obj/item/gun/energy/beam_rifle/attack_self(mob/user) + projectile_setting_pierce = !projectile_setting_pierce + to_chat(user, "You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.") + aiming_beam() + +/obj/item/gun/energy/beam_rifle/Initialize() + . = ..() + fire_delay = delay + current_tracers = list() + START_PROCESSING(SSfastprocess, src) + zoom_lock_action = new(src) + +/obj/item/gun/energy/beam_rifle/Destroy() + STOP_PROCESSING(SSfastprocess, src) + set_user(null) + QDEL_LIST(current_tracers) + listeningTo = null + return ..() + +/obj/item/gun/energy/beam_rifle/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + chambered = null + recharge_newshot() + +/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE) + var/diff = abs(aiming_lastangle - lastangle) + check_user() + if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update) + return + aiming_lastangle = lastangle + var/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new + P.gun = src + P.wall_pierce_amount = wall_pierce_amount + P.structure_pierce_amount = structure_piercing + P.do_pierce = projectile_setting_pierce + if(aiming_time) + var/percent = ((100/aiming_time)*aiming_time_left) + P.color = rgb(255 * percent,255 * ((100 - percent) / 100),0) + else + P.color = rgb(0, 255, 0) + var/turf/curloc = get_turf(src) + var/turf/targloc = get_turf(current_user.client.mouseObject) + if(!istype(targloc)) + if(!istype(curloc)) + return + targloc = get_turf_in_angle(lastangle, curloc, 10) + P.preparePixelProjectile(targloc, current_user, current_user.client.mouseParams, 0) + P.fire(lastangle) + +/obj/item/gun/energy/beam_rifle/process() + if(!aiming) + last_process = world.time + return + check_user() + handle_zooming() + aiming_time_left = max(0, aiming_time_left - (world.time - last_process)) + aiming_beam(TRUE) + last_process = world.time + +/obj/item/gun/energy/beam_rifle/proc/check_user(automatic_cleanup = TRUE) + if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! + if(automatic_cleanup) + stop_aiming() + set_user(null) + return FALSE + return TRUE + +/obj/item/gun/energy/beam_rifle/proc/process_aim() + if(istype(current_user) && current_user.client && current_user.client.mouseParams) + var/angle = mouse_angle_from_client(current_user.client) + current_user.setDir(angle2dir_cardinal(angle)) + var/difference = abs(closer_angle_difference(lastangle, angle)) + delay_penalty(difference * aiming_time_increase_angle_multiplier) + lastangle = angle + +/obj/item/gun/energy/beam_rifle/proc/on_mob_move() + check_user() + if(aiming) + delay_penalty(aiming_time_increase_user_movement) + process_aim() + aiming_beam(TRUE) + +/obj/item/gun/energy/beam_rifle/proc/start_aiming() + aiming_time_left = aiming_time + aiming = TRUE + process_aim() + aiming_beam(TRUE) + zooming_angle = lastangle + start_zooming() + +/obj/item/gun/energy/beam_rifle/proc/stop_aiming(mob/user) + set waitfor = FALSE + aiming_time_left = aiming_time + aiming = FALSE + QDEL_LIST(current_tracers) + stop_zooming(user) + +/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user) + if(user == current_user) + return + stop_aiming(current_user) + if(listeningTo) + UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) + listeningTo = null + if(istype(current_user)) + LAZYREMOVE(current_user.mousemove_intercept_objects, src) + current_user = null + if(istype(user)) + current_user = user + LAZYOR(current_user.mousemove_intercept_objects, src) + RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move) + listeningTo = user + +/obj/item/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) + if(aiming) + process_aim() + aiming_beam() + if(zoom_lock == ZOOM_LOCK_AUTOZOOM_FREEMOVE) + zooming_angle = lastangle + set_autozoom_pixel_offsets_immediate(zooming_angle) + return ..() + +/obj/item/gun/energy/beam_rifle/onMouseDown(object, location, params, mob/mob) + if(istype(mob)) + set_user(mob) + if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) + return + if((object in mob.contents) || (object == mob)) + return + start_aiming() + return ..() + +/obj/item/gun/energy/beam_rifle/onMouseUp(object, location, params, mob/M) + if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) + return + process_aim() + if(aiming_time_left <= aiming_time_fire_threshold && check_user()) + sync_ammo() + afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE) + stop_aiming() + QDEL_LIST(current_tracers) + return ..() + +/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE) + if(flag) //It's adjacent, is the user, or is on the user's person + if(target in user.contents) //can't shoot stuff inside us. + return + if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack + return + if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) + return + if(!passthrough && (aiming_time > aiming_time_fire_threshold)) + return + if(lastfire > world.time + delay) + return + lastfire = world.time + . = ..() + stop_aiming() + +/obj/item/gun/energy/beam_rifle/proc/sync_ammo() + for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents) + AC.sync_stats() + +/obj/item/gun/energy/beam_rifle/proc/delay_penalty(amount) + aiming_time_left = CLAMP(aiming_time_left + amount, 0, aiming_time) + +/obj/item/ammo_casing/energy/beam_rifle + name = "particle acceleration lens" + desc = "Don't look into barrel!" + var/wall_pierce_amount = 0 + var/wall_devastate = 0 + var/aoe_structure_range = 1 + var/aoe_structure_damage = 30 + var/aoe_fire_range = 2 + var/aoe_fire_chance = 66 + var/aoe_mob_range = 1 + var/aoe_mob_damage = 20 + var/impact_structure_damage = 50 + var/projectile_damage = 40 + var/projectile_stun = 0 + var/structure_piercing = 2 + var/structure_bleed_coeff = 0.7 + var/do_pierce = TRUE + var/obj/item/gun/energy/beam_rifle/host + +/obj/item/ammo_casing/energy/beam_rifle/proc/sync_stats() + var/obj/item/gun/energy/beam_rifle/BR = loc + if(!istype(BR)) + stack_trace("Beam rifle syncing error") + host = BR + do_pierce = BR.projectile_setting_pierce + wall_pierce_amount = BR.wall_pierce_amount + wall_devastate = BR.wall_devastate + aoe_structure_range = BR.aoe_structure_range + aoe_structure_damage = BR.aoe_structure_damage + aoe_fire_range = BR.aoe_fire_range + aoe_fire_chance = BR.aoe_fire_chance + aoe_mob_range = BR.aoe_mob_range + aoe_mob_damage = BR.aoe_mob_damage + impact_structure_damage = BR.impact_structure_damage + projectile_damage = BR.projectile_damage + projectile_stun = BR.projectile_stun + delay = BR.delay + structure_piercing = BR.structure_piercing + structure_bleed_coeff = BR.structure_bleed_coeff + +/obj/item/ammo_casing/energy/beam_rifle/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") + . = ..() + var/obj/item/projectile/beam/beam_rifle/hitscan/HS_BB = BB + if(!istype(HS_BB)) + return + HS_BB.impact_direct_damage = projectile_damage + HS_BB.stun = projectile_stun + HS_BB.impact_structure_damage = impact_structure_damage + HS_BB.aoe_mob_damage = aoe_mob_damage + HS_BB.aoe_mob_range = CLAMP(aoe_mob_range, 0, 15) //Badmin safety lock + HS_BB.aoe_fire_chance = aoe_fire_chance + HS_BB.aoe_fire_range = aoe_fire_range + HS_BB.aoe_structure_damage = aoe_structure_damage + HS_BB.aoe_structure_range = CLAMP(aoe_structure_range, 0, 15) //Badmin safety lock + HS_BB.wall_devastate = wall_devastate + HS_BB.wall_pierce_amount = wall_pierce_amount + HS_BB.structure_pierce_amount = structure_piercing + HS_BB.structure_bleed_coeff = structure_bleed_coeff + HS_BB.do_pierce = do_pierce + HS_BB.gun = host + +/obj/item/ammo_casing/energy/beam_rifle/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread) + var/turf/curloc = get_turf(user) + if(!istype(curloc) || !BB) + return FALSE + var/obj/item/gun/energy/beam_rifle/gun = loc + if(!targloc && gun) + targloc = get_turf_in_angle(gun.lastangle, curloc, 10) + else if(!targloc) + return FALSE + var/firing_dir + if(BB.firer) + firing_dir = BB.firer.dir + if(!BB.suppressed && firing_effect_type) + new firing_effect_type(get_turf(src), firing_dir) + BB.preparePixelProjectile(target, user, params, spread) + BB.fire(gun? gun.lastangle : null, null) + BB = null + return TRUE + +/obj/item/ammo_casing/energy/beam_rifle/hitscan + projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan + select_name = "beam" + e_cost = 5000 + fire_sound = 'sound/weapons/beam_sniper.ogg' + +/obj/item/projectile/beam/beam_rifle + name = "particle beam" + icon = null + hitsound = 'sound/effects/explosion3.ogg' + damage = 0 //Handled manually. + damage_type = BURN + flag = "energy" + range = 150 + jitter = 10 + var/obj/item/gun/energy/beam_rifle/gun + var/structure_pierce_amount = 0 //All set to 0 so the gun can manually set them during firing. + var/structure_bleed_coeff = 0 + var/structure_pierce = 0 + var/do_pierce = TRUE + var/wall_pierce_amount = 0 + var/wall_pierce = 0 + var/wall_devastate = 0 + var/aoe_structure_range = 0 + var/aoe_structure_damage = 0 + var/aoe_fire_range = 0 + var/aoe_fire_chance = 0 + var/aoe_mob_range = 0 + var/aoe_mob_damage = 0 + var/impact_structure_damage = 0 + var/impact_direct_damage = 0 + var/turf/cached + var/list/pierced = list() + +/obj/item/projectile/beam/beam_rifle/proc/AOE(turf/epicenter) + set waitfor = FALSE + if(!epicenter) + return + new /obj/effect/temp_visual/explosion/fast(epicenter) + for(var/mob/living/L in range(aoe_mob_range, epicenter)) //handle aoe mob damage + L.adjustFireLoss(aoe_mob_damage) + to_chat(L, "\The [src] sears you!") + for(var/turf/T in range(aoe_fire_range, epicenter)) //handle aoe fire + if(prob(aoe_fire_chance)) + new /obj/effect/hotspot(T) + for(var/obj/O in range(aoe_structure_range, epicenter)) + if(!isitem(O)) + if(O.level == 1) //Please don't break underfloor items! + continue + O.take_damage(aoe_structure_damage * get_damage_coeff(O), BURN, "laser", FALSE) + +/obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/target) + if(!do_pierce) + return FALSE + if(pierced[target]) //we already pierced them go away + return TRUE + if(isclosedturf(target)) + if(wall_pierce++ < wall_pierce_amount) + if(prob(wall_devastate)) + if(iswallturf(target)) + var/turf/closed/wall/W = target + W.dismantle_wall(TRUE, TRUE) + else + target.ex_act(EXPLODE_HEAVY) + return TRUE + if(ismovableatom(target)) + var/atom/movable/AM = target + if(AM.density && !AM.CanPass(src, get_turf(target)) && !ismob(AM)) + if(structure_pierce < structure_pierce_amount) + if(isobj(AM)) + var/obj/O = AM + O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE) + pierced[AM] = TRUE + structure_pierce++ + return TRUE + return FALSE + +/obj/item/projectile/beam/beam_rifle/proc/get_damage_coeff(atom/target) + if(istype(target, /obj/machinery/door)) + return 0.4 + if(istype(target, /obj/structure/window)) + return 0.5 + if(istype(target, /obj/structure/blob)) + return 0.65 //CIT CHANGE. + return 1 + +/obj/item/projectile/beam/beam_rifle/proc/handle_impact(atom/target) + if(isobj(target)) + var/obj/O = target + O.take_damage(impact_structure_damage * get_damage_coeff(target), BURN, "laser", FALSE) + if(isliving(target)) + var/mob/living/L = target + L.adjustFireLoss(impact_direct_damage) + L.emote("scream") + +/obj/item/projectile/beam/beam_rifle/proc/handle_hit(atom/target) + set waitfor = FALSE + if(!cached && !QDELETED(target)) + cached = get_turf(target) + if(nodamage) + return FALSE + playsound(cached, 'sound/effects/explosion3.ogg', 100, 1) + AOE(cached) + if(!QDELETED(target)) + handle_impact(target) + +/obj/item/projectile/beam/beam_rifle/Bump(atom/target) + if(check_pierce(target)) + permutated += target + trajectory_ignore_forcemove = TRUE + forceMove(target.loc) + trajectory_ignore_forcemove = FALSE + return FALSE + if(!QDELETED(target)) + cached = get_turf(target) + . = ..() + +/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE) + if(!QDELETED(target)) + cached = get_turf(target) + handle_hit(target) + . = ..() + +/obj/item/projectile/beam/beam_rifle/hitscan + icon_state = "" + hitscan = TRUE + tracer_type = /obj/effect/projectile/tracer/tracer/beam_rifle + var/constant_tracer = FALSE + +/obj/item/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, impacting = TRUE, highlander) + set waitfor = FALSE + if(isnull(highlander)) + highlander = constant_tracer + if(highlander && istype(gun)) + QDEL_LIST(gun.current_tracers) + for(var/datum/point/p in beam_segments) + gun.current_tracers += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, 0, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) + else + for(var/datum/point/p in beam_segments) + generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity) + if(cleanup) + QDEL_LIST(beam_segments) + beam_segments = null + QDEL_NULL(beam_index) + +/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam + tracer_type = /obj/effect/projectile/tracer/tracer/aiming + name = "aiming beam" + hitsound = null + hitsound_wall = null + nodamage = TRUE + damage = 0 + constant_tracer = TRUE + hitscan_light_range = 0 + hitscan_light_intensity = 0 + hitscan_light_color_override = "#99ff99" + +/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target) + qdel(src) + return FALSE + +/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit() + qdel(src) + return FALSE diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 99102a2d..381ec09c 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -186,6 +186,15 @@ desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link. It has a small explosive charge on it." selfdestruct = TRUE +/obj/item/firing_pin/holy + name = "blessed pin" + desc = "A firing pin that only responds to those who are holier than thou." + +/obj/item/firing_pin/holy/pin_auth(mob/living/user) + if(user.mind.isholy) + return TRUE + return FALSE + // Laser tag pins /obj/item/firing_pin/tag name = "laser tag firing pin" diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 5065eed6..43ca5cfd 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -151,6 +151,11 @@ /obj/item/projectile/beam/lasertag/redtag/hitscan hitscan = TRUE +/obj/item/projectile/beam/lasertag/redtag/hitscan/holy + name = "lasrifle beam" + damage = 0.1 + damage_type = BURN + /obj/item/projectile/beam/lasertag/bluetag icon_state = "bluelaser" suit_types = list(/obj/item/clothing/suit/redtag) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 254b9d4a..0a57d5b7 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -200,7 +200,8 @@ pH = 11 /datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/carbon/M) - M.hallucination += 5 + if(!M.has_quirk(/datum/quirk/insanity)) + M.hallucination += 5 return ..() /datum/reagent/toxin/plantbgone diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm index be55ed17..d698e11b 100644 --- a/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm +++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_medical_and_dinnerware.dm @@ -93,7 +93,7 @@ /datum/design/medkit - name = "Medkit Cabinent" + name = "Medkit Cabinet" id = "medkit_cabinet" build_type = AUTOLATHE | PROTOLATHE materials = list(MAT_METAL = 4000) diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 8e723ecf..df51f023 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -483,6 +483,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/ranged_analyzer + name = "Long-range Analyzer" + desc = "A new advanced atmospheric analyzer design, capable of performing scans at long range." + id = "ranged_analyzer" + build_type = PROTOLATHE + materials = list(MAT_METAL = 400, MAT_GLASS = 1000, MAT_URANIUM = 800, MAT_GOLD = 200, MAT_PLASTIC = 200) + build_path = /obj/item/analyzer/ranged + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/rcd_loaded name = "Rapid Construction Device (RCD)" desc = "A tool that can construct and deconstruct walls, airlocks and floors on the fly." diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 28e4be9a..0579b956 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -636,7 +636,7 @@ id = "exp_tools" display_name = "Experimental Tools" description = "Highly advanced construction tools." - design_ids = list("exwelder", "jawsoflife", "handdrill") + design_ids = list("exwelder", "jawsoflife", "handdrill", "ranged_analyzer") prereq_ids = list("adv_engi") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750) export_price = 5000 diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index eba26ad2..8b8cd096 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -64,10 +64,9 @@ var/interrupted = FALSE var/mob/target var/icon/bluespace - var/datum/weakref/redirect_component /datum/status_effect/slimerecall/on_apply() - redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/resistField)))) + RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/resistField) to_chat(owner, "You feel a sudden tug from an unknown force, and feel a pull to bluespace!") to_chat(owner, "Resist if you wish avoid the force!") bluespace = icon('icons/effects/effects.dmi',"chronofield") @@ -77,9 +76,9 @@ /datum/status_effect/slimerecall/proc/resistField() interrupted = TRUE owner.remove_status_effect(src) + /datum/status_effect/slimerecall/on_remove() - qdel(redirect_component.resolve()) - redirect_component = null + UnregisterSignal(owner, COMSIG_LIVING_RESIST) owner.cut_overlay(bluespace) if(interrupted || !ismob(target)) to_chat(owner, "The bluespace tug fades away, and you feel that the force has passed you by.") @@ -98,10 +97,9 @@ duration = -1 //Will remove self when block breaks. alert_type = /obj/screen/alert/status_effect/freon/stasis var/obj/structure/ice_stasis/cube - var/datum/weakref/redirect_component /datum/status_effect/frozenstasis/on_apply() - redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/breakCube)))) + RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/breakCube) cube = new /obj/structure/ice_stasis(get_turf(owner)) owner.forceMove(cube) owner.status_flags |= GODMODE @@ -118,8 +116,7 @@ if(cube) qdel(cube) owner.status_flags &= ~GODMODE - qdel(redirect_component.resolve()) - redirect_component = null + UnregisterSignal(owner, COMSIG_LIVING_RESIST) /datum/status_effect/slime_clone id = "slime_cloned" diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 04cf006e..9de6384a 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -1,8 +1,8 @@ //Xenobio control console /mob/camera/aiEye/remote/xenobio visible_icon = TRUE - icon = 'icons/obj/abductor.dmi' - icon_state = "camera_target" + icon = 'icons/mob/cameramob.dmi' + icon_state = "generic_camera" var/allowed_area = null /mob/camera/aiEye/remote/xenobio/Initialize() @@ -24,8 +24,6 @@ circuit = /obj/item/circuitboard/computer/xenobiology var/datum/action/innate/hotkey_help/hotkey_help - var/datum/component/redirect/listener - var/obj/machinery/monkey_recycler/connected_recycler var/list/stored_slimes var/obj/item/slimepotion/slime/current_potion @@ -41,7 +39,7 @@ . = ..() hotkey_help = new stored_slimes = list() - listener = AddComponent(/datum/component/redirect, list(COMSIG_ATOM_CONTENTS_DEL = CALLBACK(src, .proc/on_contents_del))) + RegisterSignal(src, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del) for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers) if(get_area(src) == get_area(recycler)) connected_recycler = recycler @@ -80,8 +78,8 @@ eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src)) eyeobj.origin = src eyeobj.visible_icon = TRUE - eyeobj.icon = 'icons/obj/abductor.dmi' - eyeobj.icon_state = "camera_target" + eyeobj.icon = 'icons/mob/cameramob.dmi' + eyeobj.icon_state = "generic_camera" /obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user) ..() diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 98eb6f56..22dee60e 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -115,6 +115,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells var/phase_allowed = 0 // If true, the spell can be cast while phased, eg. blood crawling, ethereal jaunting + var/antimagic_allowed = TRUE // If false, the spell cannot be cast while under the effect of antimagic var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell var/invocation_emote_self = null var/invocation_type = "none" //can be none, whisper, emote and shout @@ -147,27 +148,36 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(player_lock) if(!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list)) to_chat(user, "You shouldn't have this spell! Something's wrong.") - return 0 + return FALSE else if(!(src in user.mob_spell_list)) - return 0 + return FALSE var/turf/T = get_turf(user) if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel to_chat(user, "You can't cast this spell here.") - return 0 + return FALSE if(!skipcharge) if(!charge_check(user)) - return 0 + return FALSE if(user.stat && !stat_allowed) to_chat(user, "Not when you're incapacitated.") - return 0 + return FALSE + + if(!antimagic_allowed) + var/antimagic = user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE) + if(antimagic) + if(isitem(antimagic)) + to_chat(user, "[antimagic] is interfering with your magic.") + else + to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.") + return FALSE if(!phase_allowed && istype(user.loc, /obj/effect/dummy)) to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.") - return 0 + return FALSE if(ishuman(user)) @@ -175,7 +185,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal()) to_chat(user, "You can't get the words out!") - return 0 + return FALSE var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe, /obj/item/clothing/suit/space/hardsuit/wizard, @@ -187,24 +197,24 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(clothes_req) //clothes check if(!is_type_in_typecache(H.wear_suit, casting_clothes)) to_chat(H, "I don't feel strong enough without my robe.") - return 0 + return FALSE if(!is_type_in_typecache(H.head, casting_clothes)) to_chat(H, "I don't feel strong enough without my hat.") - return 0 + return FALSE if(cult_req) //CULT_REQ CLOTHES CHECK if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult)) to_chat(H, "I don't feel strong enough without my armor.") - return 0 + return FALSE if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult)) to_chat(H, "I don't feel strong enough without my helmet.") - return 0 + return FALSE else if(clothes_req || human_req) to_chat(user, "This spell can only be cast by humans!") - return 0 + return FALSE if(nonabstract_req && (isbrain(user) || ispAI(user))) to_chat(user, "This spell can only be cast by physical beings!") - return 0 + return FALSE if(!skipcharge) @@ -499,6 +509,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(user.stat && !stat_allowed) return FALSE + if(!antimagic_allowed && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE)) + return FALSE + if(!ishuman(user)) if(clothes_req || human_req) return FALSE diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm index 47d6f71f..ed78e331 100644 --- a/code/modules/spells/spell_types/forcewall.dm +++ b/code/modules/spells/spell_types/forcewall.dm @@ -35,6 +35,6 @@ return TRUE if(ismob(mover)) var/mob/M = mover - if(M.anti_magic_check()) + if(M.anti_magic_check(chargecost = 0)) return TRUE return FALSE diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index 7fd857dc..7a197876 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -86,7 +86,7 @@ /obj/effect/cross_action/spacetime_dist/proc/walk_link(atom/movable/AM) if(ismob(AM)) var/mob/M = AM - if(M.anti_magic_check()) + if(M.anti_magic_check(chargecost = 0)) return if(linked_dist && walks_left > 0) flick("purplesparkles", src) diff --git a/code/modules/spells/spell_types/telepathy.dm b/code/modules/spells/spell_types/telepathy.dm index db7e284e..34f100f7 100644 --- a/code/modules/spells/spell_types/telepathy.dm +++ b/code/modules/spells/spell_types/telepathy.dm @@ -10,9 +10,11 @@ action_background_icon_state = "bg_spell" var/notice = "notice" var/boldnotice = "boldnotice" - var/magic_check = TRUE + var/magic_check = FALSE + var/holy_check = FALSE + var/tinfoil_check = TRUE -/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/simple_animal/revenant/user = usr) +/obj/effect/proc_holder/spell/targeted/telepathy/cast(list/targets, mob/living/user = usr) for(var/mob/living/M in targets) var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") if(!msg) @@ -20,11 +22,11 @@ return log_directed_talk(user, M, msg, LOG_SAY, "[name]") to_chat(user, "You transmit to [M]: [msg]") - if(!magic_check || !M.anti_magic_check(FALSE, TRUE)) //hear no evil + if(!M.anti_magic_check(magic_check, holy_check, tinfoil_check, 0)) //hear no evil to_chat(M, "You hear something behind you talking... [msg]") for(var/ded in GLOB.dead_mob_list) if(!isobserver(ded)) continue var/follow_rev = FOLLOW_LINK(ded, user) var/follow_whispee = FOLLOW_LINK(ded, M) - to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]") \ No newline at end of file + to_chat(ded, "[follow_rev] [user] [name]: \"[msg]\" to [follow_whispee] [M]") diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 3f616d5a..309e554e 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -254,7 +254,8 @@ var/static/regex/clap_words = regex("clap|applaud") var/static/regex/honk_words = regex("ho+nk") //hooooooonk var/static/regex/multispin_words = regex("like a record baby|right round") - var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE + var/static/regex/family_friendly_words = regex("family") //Hyper change + //var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE var/static/regex/dab_words = regex("dab|mood") //CITADEL CHANGE var/static/regex/snap_words = regex("snap") //CITADEL CHANGE var/static/regex/bwoink_words = regex("what the fuck are you doing|bwoink|hey you got a moment?") //CITADEL CHANGE @@ -572,6 +573,7 @@ var/mob/living/L = V L.SpinAnimation(speed = 10, loops = 5) + /* Yeah nah fam. //CITADEL CHANGES //ORGASM else if((findtext(message, orgasm_words))) @@ -580,6 +582,13 @@ var/mob/living/carbon/human/H = V if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure H.mob_climax(forced_climax=TRUE) + */ + else if((findtext(message, family_friendly_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/M = V + M.say(pick("You don't turn your back on family.","...Even when they do.")) + SEND_SOUND(M, sound('hyperstation/sound/misc/family.ogg',volume=75)) //DAB else if((findtext(message, dab_words))) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index c739d426..aae422bc 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -1,13 +1,13 @@ -//include unit test files in this module in this ifdef -//Keep this sorted alphabetically - -#ifdef UNIT_TESTS -#include "anchored_mobs.dm" -#include "component_tests.dm" -#include "reagent_id_typos.dm" -#include "reagent_recipe_collisions.dm" -#include "spawn_humans.dm" -#include "subsystem_init.dm" -#include "timer_sanity.dm" -#include "unit_test.dm" -#endif +//include unit test files in this module in this ifdef +//Keep this sorted alphabetically + +#ifdef UNIT_TESTS +#include "anchored_mobs.dm" +#include "component_tests.dm" +#include "reagent_id_typos.dm" +#include "reagent_recipe_collisions.dm" +#include "spawn_humans.dm" +#include "subsystem_init.dm" +#include "timer_sanity.dm" +#include "unit_test.dm" +#endif diff --git a/code/modules/unit_tests/component_tests.dm b/code/modules/unit_tests/component_tests.dm new file mode 100644 index 00000000..409d7f43 --- /dev/null +++ b/code/modules/unit_tests/component_tests.dm @@ -0,0 +1,12 @@ +/datum/unit_test/component_duping/Run() + var/list/bad_dms = list() + var/list/bad_dts = list() + for(var/t in typesof(/datum/component)) + var/datum/component/comp = t + if(!isnum(initial(comp.dupe_mode))) + bad_dms += t + var/dupe_type = initial(comp.dupe_type) + if(dupe_type && !ispath(dupe_type)) + bad_dts += t + if(length(bad_dms) || length(bad_dts)) + Fail("Components with invalid dupe modes: ([bad_dms.Join(",")]) ||| Components with invalid dupe types: ([bad_dts.Join(",")])") \ No newline at end of file diff --git a/hyperstation/code/datums/mood_events/events.dm b/hyperstation/code/datums/mood_events/events.dm index 5c58d9ab..b61bff1c 100644 --- a/hyperstation/code/datums/mood_events/events.dm +++ b/hyperstation/code/datums/mood_events/events.dm @@ -22,3 +22,8 @@ description = "I feel like I'm held together by flimsy string, and could fall apart at any moment!\n" mood_change = -4 timeout = 2 MINUTES + +/datum/mood_event/copium + description = "Things are going to be okay, right?\n" + mood_change = 3 + timeout = 3 MINUTES diff --git a/hyperstation/code/game/machinery/lore_terminal.dm b/hyperstation/code/game/machinery/lore_terminal.dm index 7381b128..d2510224 100644 --- a/hyperstation/code/game/machinery/lore_terminal.dm +++ b/hyperstation/code/game/machinery/lore_terminal.dm @@ -1,7 +1,7 @@ GLOBAL_DATUM_INIT(lore_terminal_controller, /datum/lore_controller, new) /obj/machinery/computer/lore_terminal - name = "Staff Seegson info-link terminal" + name = "Staff info-link terminal" desc = "A small CRT display with an inbuilt microcomputer which is loaded with an extensive database. These terminals contain eveyrthing from information about historical events to instruction manuals for common ship appliances." icon = 'nsv13/icons/obj/computers.dmi' icon_state = "terminal" @@ -9,16 +9,21 @@ GLOBAL_DATUM_INIT(lore_terminal_controller, /datum/lore_controller, new) density = FALSE anchored = TRUE idle_power_usage = 15 - var/access_tag = "ntcommon" //Every subtype of this type will be readable by this console. Use this for away terms as seen here \/ + var/access_tag = "kncommon" //Every subtype of this type will be readable by this console. Use this for away terms as seen here \/ var/list/entries = list() //Every entry that we've got. var/in_use = FALSE //Stops sound spam var/datum/looping_sound/computer_click/soundloop /obj/machinery/computer/lore_terminal/command //Put sensitive information on this one - name = "Command Seegson info-link terminal" - access_tag = "ntcommand" + name = "Command info-link terminal" + access_tag = "kncommand" req_access = list(ACCESS_HEADS) +/obj/machinery/computer/lore_terminal/security + name = "Security info-link terminal" + access_tag = "knsecurity" + req_access = list(ACCESS_SECURITY) + /obj/machinery/computer/lore_terminal/awaymission //Example for having a terminal preloaded with only a set list of files. access_tag = "awaymission_default" @@ -201,12 +206,12 @@ SPECIAL KEYS RESPOND AS FOLLOWS: name = "new_employees_memo.mail" title = "Intercepted message" path = "lore_entries/welcome.txt" - access_tag = "ntcommon" + access_tag = "kncommon" /datum/lore_entry/all name = "nuclear_authdisk_instructions.mail" title = "Handling the Nuclear Authentication Disk and You!" - content = "SYSADMIN -> allcrew@seegnet.kin. RE: The Nuclear Authentication Disk. ` Greetings staff members! We're aware of the questions you have in regards to the Nuclear Authentication disk. The disk itself contains the codes needed to unlock nuclear devices used in a Nuclear Emergency and trigger a station self-destruction sequence. ` It is the duty of every member of this crew to take responsibility for the disk in the off chance that station command is currently absent. ` Don't leave it lying in the Captain's office. ` Keep it in movement to prevent Syndicate triangulation devices from functioning. ` If the disk location is unknown, look for a red pinpointer, the Head of Security and the Captain should always have one in their offices or lockers. These will help you locate the disk. ` If the disk is in enemy hands, call all hands on deck immediately and order a red alert. ` ` Protect the disk with your life, for the lives of the station's crew depend on it. Stay safe through vigilance." + content = "SYSADMIN -> allcrew@seegnet.kin. RE: The Nuclear Authentication Disk. ` Greetings staff members! We're aware of the questions you have in regards to the Nuclear Authentication disk. The disk itself contains the codes needed to unlock nuclear devices used in a Nuclear Emergency and trigger a station self-destruction sequence. ` It is the duty of every member of this crew to take responsibility for the disk in the off chance that station command is currently absent. ` Even though Layenia itself is a mobile facility and prevents Disk Triangulation in most circumstances, it is still important to hold onto the disk even when not needed- it is a good formality and keeps things secure! ` If the disk location is unknown, look for a red pinpointer, the Head of Security and the Captain should always have one in their offices or lockers. These will help you locate the disk. ` If the disk is in enemy hands, call all hands on deck immediately and order a red alert. ` ` Protect the disk with your life, for the lives of the station's crew depend on it. Stay safe through vigilance." access_tag = "all" /datum/lore_entry/all/meltdown_proceedures @@ -217,7 +222,7 @@ SPECIAL KEYS RESPOND AS FOLLOWS: /datum/lore_entry/command name = "command_memo.mail" title = "Intercepted Message" - access_tag = "ntcommand" + access_tag = "kncommand" classified = "Restricted" content = "SYSADMIN -> command@seegnet.kin. RE: Orientation. ` Greetings station command staff, congratulations on your placement! It is now company policy to attend all briefings as issued by centcom staff. Please speak to your centcom officer for clarification on the new procedures." @@ -238,3 +243,54 @@ SPECIAL KEYS RESPOND AS FOLLOWS: /datum/lore_entry/away_example/weapons_log name = "weapon_systems_dump2259/11/25.txt" content = "Life support systems terminated. Railgun system status: A6E3. Torpedo system status: ~@##6#6#^^6 -=File Access Terminated=-" + +/datum/lore_entry/security + name = "usage_and_terms.memo" + title = "Usage and Terms" + access_tag = "knsecurity" + path = "lore_entries/security/usageandterms.txt" + +/datum/lore_entry/security/introduction + name = "introduction.memo" + title = "Security Introduction" + path = "lore_entries/security/introduction.txt" + +/datum/lore_entry/security/basicgearandyou + name = "gearbasics.memo" + title = "Basic Gear and You" + path = "lore_entries/security/basicgearandyou.txt" + +/datum/lore_entry/security/advancedgearandyou + name = "gearadvanced.memo" + title = "Advanced Gear and You" + path = "lore_entries/security/advancedgearandyou.txt" + +/datum/lore_entry/security/defensivegearandyou + name = "geardefensive.memo" + title = "Defensive Gear and You" + path = "lore_entries/security/defensivegearandyou.txt" + +/datum/lore_entry/security/sop + name = "standard_operating_procedure.txt" + title = "Standard Operating Procedure" + path = "lore_entries/security/wip.txt" + +/datum/lore_entry/security/lowcrime + name = "low_infractions.txt" + title = "Minor Infractions" + path = "lore_entries/security/wip.txt" + +/datum/lore_entry/security/mediumcrime + name = "medium_infractions.txt" + title = "Medium-risk Infractions" + path = "lore_entries/security/wip.txt" + +/datum/lore_entry/security/highcrime + name = "high_infractions.txt" + title = "Dangerous Infractions" + path = "lore_entries/security/wip.txt" + +/datum/lore_entry/security/deltacrime + name = "delta_infractions.txt" + title = "Zealot-class Notice and Warning" + path = "lore_entries/security/wip.txt" \ No newline at end of file diff --git a/hyperstation/code/game/objects/structures/sauna_oven.dm b/hyperstation/code/game/objects/structures/sauna_oven.dm new file mode 100644 index 00000000..64727606 --- /dev/null +++ b/hyperstation/code/game/objects/structures/sauna_oven.dm @@ -0,0 +1,120 @@ +#define SAUNA_H2O_TEMP T20C + 20 +#define SAUNA_LOG_FUEL 150 +#define SAUNA_PAPER_FUEL 5 +#define SAUNA_MAXIMUM_FUEL 3000 +#define SAUNA_WATER_PER_WATER_UNIT 5 + +/obj/structure/sauna_oven + name = "sauna oven" + desc = "A modest sauna oven with rocks. Add some fuel, pour some water and enjoy the moment." + icon = 'hyperstation/icons/obj/structures/sauna_oven.dmi' + icon_state = "sauna_oven" + density = TRUE + anchored = TRUE + resistance_flags = FIRE_PROOF + var/lit = FALSE + var/fuel_amount = 0 + var/water_amount = 0 + +/obj/structure/sauna_oven/examine(mob/user) + . = ..() + . += "The rocks are [water_amount ? "moist" : "dry"]." + . += "There's [fuel_amount ? "some fuel" : "no fuel"] in the oven." + +/obj/structure/sauna_oven/Destroy() + if(lit) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/sauna_oven/attack_hand(mob/user) + . = ..() + if(.) + return + if(lit) + lit = FALSE + STOP_PROCESSING(SSobj, src) + user.visible_message("[user] turns on [src].", "You turn on [src].") + else if (fuel_amount) + lit = TRUE + START_PROCESSING(SSobj, src) + user.visible_message("[user] turns off [src].", "You turn off [src].") + update_icon() + +/obj/structure/sauna_oven/update_overlays() + . = ..() + if(lit) + . += "sauna_oven_on_overlay" + +/obj/structure/sauna_oven/update_icon() + ..() + icon_state = "[lit ? "sauna_oven_on" : initial(icon_state)]" + +/obj/structure/sauna_oven/attackby(obj/item/T, mob/user) + if(T.tool_behaviour == TOOL_WRENCH) + to_chat(user, "You begin to deconstruct [src].") + if(T.use_tool(src, user, 60, volume=50)) + to_chat(user, "You successfully deconstructed [src].") + new /obj/item/stack/sheet/mineral/wood(get_turf(src), 30) + qdel(src) + return TRUE + + else if(istype(T, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/reagent_container = T + if(!reagent_container.is_open_container()) + return ..() + if(reagent_container.reagents.has_reagent(/datum/reagent/water)) + reagent_container.reagents.remove_reagent(/datum/reagent/water, 5) + user.visible_message("[user] pours some \ + water into [src].", "You pour \ + some water to [src].") + water_amount += 5 * SAUNA_WATER_PER_WATER_UNIT + return TRUE + else + to_chat(user, "There's no water in [reagent_container]") + return FALSE + + else if(istype(T, /obj/item/stack/sheet/mineral/wood)) + var/obj/item/stack/sheet/mineral/wood/wood = T + if(fuel_amount > SAUNA_MAXIMUM_FUEL) + to_chat(user, "You can't fit any more of [T] in [src]!") + return FALSE + fuel_amount += SAUNA_LOG_FUEL * wood.amount + wood.use(wood.amount) + user.visible_message("[user] tosses some \ + wood into [src].", "You add \ + some fuel to [src].") + return TRUE + else if(istype(T, /obj/item/paper_bin)) + var/obj/item/paper_bin/paper_bin = T + user.visible_message("[user] throws [T] into \ + [src].", "You add [T] to [src].\ + ") + fuel_amount += SAUNA_PAPER_FUEL * paper_bin.total_paper + qdel(paper_bin) + return TRUE + else if(istype(T, /obj/item/paper)) + user.visible_message("[user] throws [T] into \ + [src].", "You throw [T] into [src].\ + ") + fuel_amount += SAUNA_PAPER_FUEL + qdel(T) + return TRUE + return ..() + +/obj/structure/sauna_oven/process() + if(water_amount) + water_amount-- + var/turf/pos = get_turf(src) + if(pos) + pos.atmos_spawn_air("water_vapor=10;TEMP=[SAUNA_H2O_TEMP]") + fuel_amount-- + if(fuel_amount <= 0) + lit = FALSE + STOP_PROCESSING(SSobj, src) + update_icon() + +#undef SAUNA_H2O_TEMP +#undef SAUNA_LOG_FUEL +#undef SAUNA_PAPER_FUEL +#undef SAUNA_MAXIMUM_FUEL +#undef SAUNA_WATER_PER_WATER_UNIT diff --git a/hyperstation/code/mobs/mimic.dm b/hyperstation/code/mobs/mimic.dm index 96707f75..a98282da 100644 --- a/hyperstation/code/mobs/mimic.dm +++ b/hyperstation/code/mobs/mimic.dm @@ -1,14 +1,14 @@ /mob/living/simple_animal/hostile/hs13mimic name = "Mimic" icon = 'hyperstation/icons/mobs/mimic.dmi' - desc = "What the fuck is that?" + desc = "A writhing mass of black flesh, unlikely to be happy to see you." icon_state = "mimic" icon_living = "mimic" icon_dead = "mimic_dead" gender = NEUTER speak_chance = 0 - maxHealth = 38 - health = 38 + maxHealth = 35 + health = 35 turns_per_move = 5 move_to_delay = 1 speed = 0 @@ -21,14 +21,14 @@ response_harm = "smacks" melee_damage_lower = 8 melee_damage_upper = 12 - attacktext = "glomps" - attack_sound = 'sound/effects/blobattack.ogg' + attacktext = "stings" + attack_sound = 'hyperstation/sound/creatures/mimic/mimic_attack.ogg' atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) ventcrawler = VENTCRAWLER_ALWAYS blood_volume = 0 faction = list("mimic") gold_core_spawnable = NO_SPAWN - vision_range = 2 + vision_range = 1 aggro_vision_range = 9 wander = TRUE minbodytemp = 250 //weak to cold @@ -43,6 +43,7 @@ /obj/item/projectile, /obj/item/radio/intercom, /mob/living/simple_animal/bot)) + var/transformsound = 'hyperstation/sound/creatures/mimic/mimic_transform.ogg' var/playstyle_string = "You are a mimic, a tricky creature that can take the form of \ almost any item nearby by shift-clicking it. While morphed, you move slowly and do less damage. \ Finally, you can restore yourself to your original form while morphed by shift-clicking yourself. \ @@ -139,10 +140,10 @@ icon_state = "yellow" desc = "These gloves will protect the wearer from electric shock." if(21 to 30) - name = "Private Security Officer" - desc = "A cardboard cutout of a private security officer." - icon = 'icons/obj/cardboard_cutout.dmi' - icon_state = "cutout_ntsec" + name = "stunbaton" + desc = "A stun baton for incapacitating people with." + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "stunbaton" if(31 to 40) name = "pen" icon = 'icons/obj/bureaucracy.dmi' @@ -154,10 +155,10 @@ icon = 'icons/obj/bureaucracy.dmi' icon_state = "newspaper" if(51 to 60) - name = "toolbox" - desc = "Danger. Very robust." - icon = 'icons/obj/storage.dmi' - icon_state = "red" + name = "stechkin pistol" //greytider bait + desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors." + icon = 'icons/obj/guns/projectile.dmi' + icon_state = "pistol" if(61 to 70) name = "emergency oxygen tank" desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it." @@ -212,7 +213,7 @@ if(stealthed && stat == CONSCIOUS) visible_message("The [src] Reveals itself to be a Mimic!") restore() - playsound(loc, 'hyperstation/sound/creatures/mimictransform.ogg', 75, TRUE) + playsound(loc, transformsound, 75, TRUE) triggerOthers(target) // Friends too! /mob/living/simple_animal/hostile/hs13mimic/proc/triggerOthers(passtarget) // @@ -252,7 +253,7 @@ return if(istype(A) && allowed(A)) stealthed = TRUE - SEND_SOUND(src, sound('hyperstation/sound/creatures/mimictransform.ogg',volume=50)) + SEND_SOUND(src, sound(transformsound,volume=50)) name = A.name icon = A.icon icon_state = A.icon_state diff --git a/hyperstation/code/modules/reagents/chemistry/reagents/food_reagents.dm b/hyperstation/code/modules/reagents/chemistry/reagents/food_reagents.dm index e5a052d1..d8cda7c0 100644 --- a/hyperstation/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/hyperstation/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -6,6 +6,3 @@ nutriment_factor = 5 * REAGENTS_METABOLISM metabolization_rate = 1 * REAGENTS_METABOLISM taste_description = "sweetness" - -/datum/reagent/consumable/alienhoney/on_mob_life(mob/living/carbon/M) - ..() \ No newline at end of file diff --git a/hyperstation/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/hyperstation/code/modules/reagents/chemistry/reagents/medicine_reagents.dm new file mode 100644 index 00000000..3db0e93f --- /dev/null +++ b/hyperstation/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -0,0 +1,29 @@ +/datum/reagent/medicine/copium + name = "copium" + description = "A heavy scented substance meant to help one deal with loss." + reagent_state = LIQUID + color = "#a8707e" + overdose_threshold = 21 + metabolization_rate = 0.75 * REAGENTS_METABOLISM + pH = 4 + +/datum/reagent/medicine/copium/on_mob_life(mob/living/carbon/M) + var/datum/component/mood/mood = M.GetComponent(/datum/component/mood) + if(mood.sanity <= SANITY_NEUTRAL && current_cycle >= 5) + mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL)) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "copium", /datum/mood_event/copium) + ..() + +/datum/reagent/medicine/copium/overdose_process(mob/living/carbon/M) //copious amounts of copium + M.blur_eyes(10) + if(prob(50)) + M.adjustToxLoss(1, 0) + if(prob(5)) + M.say(pick("That's okay. Things are going to be okay.", "This is fine.", "I'm okay with the events that are unfolding currently.", "World of Spacecraft is still a good game...", "I'm winning.", "Diesels are far more powerful.")) + if(prob(5)) + M.emote("me", 1, "seems to be crying.") + if(prob(4)) + M.emote("me", 1, "falls over, crying.") + M.Knockdown(40) + +//To-do: /datum/reagent/medicine/seethium diff --git a/hyperstation/code/modules/reagents/chemistry/recipes/medicine.dm b/hyperstation/code/modules/reagents/chemistry/recipes/medicine.dm new file mode 100644 index 00000000..7a542dc5 --- /dev/null +++ b/hyperstation/code/modules/reagents/chemistry/recipes/medicine.dm @@ -0,0 +1,6 @@ +/datum/chemical_reaction/copium + name = "copium" + id = /datum/reagent/medicine/copium + results = list(/datum/reagent/medicine/copium = 5) + required_reagents = list(/datum/reagent/medicine/mannitol = 2, /datum/reagent/water = 1, /datum/reagent/medicine/epinephrine = 1, /datum/reagent/consumable/sugar = 1) + required_temp = 266 diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 7ba5421d..19aff71e 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -164,6 +164,13 @@ C.adjustArousalLoss(20) M.adjustArousalLoss(20) M.do_jitter_animation() //make your partner shake too! + + if (M.getArousalLoss() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~ + if(V.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill + M.mob_climax_outside(V, spillage = TRUE) + else + M.mob_climax_outside(V, spillage = FALSE) + if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) var/mob/living/carbon/human/O = C diff --git a/hyperstation/code/obj/leash.dm b/hyperstation/code/obj/leash.dm index cc057c92..46dcc35c 100644 --- a/hyperstation/code/obj/leash.dm +++ b/hyperstation/code/obj/leash.dm @@ -35,7 +35,7 @@ Icons, maybe? /datum/status_effect/leash_pet id = "leashed" status_type = STATUS_EFFECT_UNIQUE - var/datum/weakref/redirect_component + var/mob/redirect_component alert_type = /obj/screen/alert/status_effect/leash_pet /obj/screen/alert/status_effect/leash_pet @@ -45,7 +45,9 @@ Icons, maybe? /datum/status_effect/leash_pet/on_apply() - redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) + //redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) + RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) + redirect_component = owner if(!owner.stat) to_chat(owner, "You have been leashed!") return ..() @@ -80,9 +82,9 @@ Icons, maybe? var/leash_used = 0 //A flag to see if the leash has been used yet, because for some reason picking up an unused leash is weird var/mob/living/leash_pet = "null" //Variable to store our pet later var/mob/living/leash_master = "null" //And our master too - var/datum/component/mobhook_leash_pet - var/datum/component/mobhook_leash_master //Needed to watch for these entities to move - var/datum/component/mobhook_leash_freepet + var/mob/mobhook_leash_pet + var/mob/mobhook_leash_master //Needed to watch for these entities to move + var/mob/mobhook_leash_freepet var/leash_location[3] //Three digit list for us to store coordinates later //Called when someone is clicked with the leash @@ -101,8 +103,12 @@ Icons, maybe? user.apply_status_effect(/datum/status_effect/leash_dom) //Is the leasher leash_pet = C //Save pet reference for later leash_master = user //Save dom reference for later - mobhook_leash_pet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_pet_move))) - mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move))) + //mobhook_leash_pet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_pet_move))) + RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_pet_move) + mobhook_leash_pet = leash_pet + //mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move))) + RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move) + mobhook_leash_master = leash_master leash_used = 1 if(!leash_pet.has_status_effect(/datum/status_effect/leash_dom)) //Add slowdown if the pet didn't leash themselves leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH, multiplicative_slowdown = 5) @@ -126,9 +132,12 @@ Icons, maybe? leash_pet.remove_status_effect(/datum/status_effect/leash_pet) if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) //If there is no pet, there is no dom. Loop breaks. - QDEL_NULL(mobhook_leash_master) - QDEL_NULL(mobhook_leash_pet) - QDEL_NULL(mobhook_leash_freepet) + //QDEL_NULL(mobhook_leash_master) + UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED) + //QDEL_NULL(mobhook_leash_pet) + UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED) + //QDEL_NULL(mobhook_leash_freepet) + UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED) if(leash_pet.has_status_effect(/datum/status_effect/leash_freepet)) leash_pet.remove_status_effect(/datum/status_effect/leash_freepet) if(leash_pet.has_movespeed_modifier(MOVESPEED_ID_LEASH)) @@ -183,7 +192,8 @@ Icons, maybe? if(leash_pet == leash_master) //Pet is the master return if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) - QDEL_NULL(mobhook_leash_master) //Probably redundant, but it's nice to be safe + //QDEL_NULL(mobhook_leash_master) //Probably redundant, but it's nice to be safe + UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED) leash_master.remove_status_effect(/datum/status_effect/leash_dom) return @@ -252,8 +262,10 @@ Icons, maybe? leash_pet.remove_status_effect(/datum/status_effect/leash_pet) leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH) leash_master.remove_status_effect(/datum/status_effect/leash_dom) - QDEL_NULL(mobhook_leash_master) - QDEL_NULL(mobhook_leash_pet) + //QDEL_NULL(mobhook_leash_master) + UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED) + //QDEL_NULL(mobhook_leash_pet) + UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED) leash_pet = "null" leash_master = "null" leash_used = 0 @@ -267,7 +279,8 @@ Icons, maybe? return //Make sure the pet is still a pet if(!leash_pet.has_status_effect(/datum/status_effect/leash_pet)) - QDEL_NULL(mobhook_leash_pet) //Probably redundant, but it's nice to be safe + //QDEL_NULL(mobhook_leash_pet) //Probably redundant, but it's nice to be safe + UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED) return //The pet has escaped. There is no DOM. GO PET RUN. @@ -356,8 +369,10 @@ Icons, maybe? leash_pet.adjustOxyLoss(5) leash_pet.remove_status_effect(/datum/status_effect/leash_pet) leash_pet.remove_status_effect(/datum/status_effect/leash_freepet) - QDEL_NULL(mobhook_leash_pet) - QDEL_NULL(mobhook_leash_freepet) + //QDEL_NULL(mobhook_leash_pet) + UnregisterSignal(mobhook_leash_pet, COMSIG_MOVABLE_MOVED) + //QDEL_NULL(mobhook_leash_freepet) + UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED) leash_pet = "null" leash_used = 0 @@ -375,10 +390,13 @@ Icons, maybe? viewing.show_message("[leash_master] has dropped the leash.", 1) //DOM HAS DROPPED LEASH. PET IS FREE. SCP HAS BREACHED CONTAINMENT. leash_pet.remove_movespeed_modifier(MOVESPEED_ID_LEASH) - mobhook_leash_freepet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_freepet_move))) + //mobhook_leash_freepet = leash_pet.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_freepet_move))) + RegisterSignal(leash_pet, COMSIG_MOVABLE_MOVED, .proc/on_freepet_move) + mobhook_leash_freepet = leash_pet leash_master.remove_status_effect(/datum/status_effect/leash_dom) //No dom with no leash. We will get a new dom if the leash is picked back up. leash_master = "null" - QDEL_NULL(mobhook_leash_master) + //QDEL_NULL(mobhook_leash_master) + UnregisterSignal(mobhook_leash_master, COMSIG_MOVABLE_MOVED) /obj/item/leash/equipped(mob/user) . = ..() @@ -392,9 +410,12 @@ Icons, maybe? leash_master = "null" return leash_master.apply_status_effect(/datum/status_effect/leash_dom) - mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move))) + //mobhook_leash_master = leash_master.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/on_master_move))) + RegisterSignal(leash_master, COMSIG_MOVABLE_MOVED, .proc/on_master_move) + mobhook_leash_master = leash_master leash_pet.remove_status_effect(/datum/status_effect/leash_freepet) - QDEL_NULL(mobhook_leash_freepet) + //QDEL_NULL(mobhook_leash_freepet) + UnregisterSignal(mobhook_leash_freepet, COMSIG_MOVABLE_MOVED) leash_pet.add_movespeed_modifier(MOVESPEED_ID_LEASH, multiplicative_slowdown = 5) /datum/crafting_recipe/leash @@ -403,4 +424,4 @@ Icons, maybe? time = 40 reqs = list(/obj/item/stack/sheet/metal = 1, /obj/item/stack/sheet/cloth = 3) - category = CAT_MISC \ No newline at end of file + category = CAT_MISC diff --git a/hyperstation/icons/obj/structures/sauna_oven.dmi b/hyperstation/icons/obj/structures/sauna_oven.dmi new file mode 100644 index 00000000..fb0871ca Binary files /dev/null and b/hyperstation/icons/obj/structures/sauna_oven.dmi differ diff --git a/hyperstation/sound/creatures/mimic/mimic_attack.ogg b/hyperstation/sound/creatures/mimic/mimic_attack.ogg new file mode 100644 index 00000000..4d448840 Binary files /dev/null and b/hyperstation/sound/creatures/mimic/mimic_attack.ogg differ diff --git a/hyperstation/sound/creatures/mimictransform.ogg b/hyperstation/sound/creatures/mimic/mimic_transform.ogg similarity index 100% rename from hyperstation/sound/creatures/mimictransform.ogg rename to hyperstation/sound/creatures/mimic/mimic_transform.ogg diff --git a/hyperstation/sound/misc/family.ogg b/hyperstation/sound/misc/family.ogg new file mode 100644 index 00000000..39c97e7e Binary files /dev/null and b/hyperstation/sound/misc/family.ogg differ diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi index 115629dd..6964160c 100644 Binary files a/icons/mob/blob.dmi and b/icons/mob/blob.dmi differ diff --git a/icons/mob/cameramob.dmi b/icons/mob/cameramob.dmi new file mode 100644 index 00000000..a35d6c37 Binary files /dev/null and b/icons/mob/cameramob.dmi differ diff --git a/icons/mob/suit_digi.dmi b/icons/mob/suit_digi.dmi index cfe1617e..88c30722 100644 Binary files a/icons/mob/suit_digi.dmi and b/icons/mob/suit_digi.dmi differ diff --git a/icons/obj/abductor.dmi b/icons/obj/abductor.dmi index b5dc7e00..75f84347 100644 Binary files a/icons/obj/abductor.dmi and b/icons/obj/abductor.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 331dc911..9d1323cc 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/statue_egypty.dmi b/icons/obj/statue_egypty.dmi new file mode 100644 index 00000000..3234f8bb Binary files /dev/null and b/icons/obj/statue_egypty.dmi differ diff --git a/icons/turf/walls/sandstone_wall.dmi b/icons/turf/walls/sandstone_wall.dmi index 4118a3db..3eac01e9 100644 Binary files a/icons/turf/walls/sandstone_wall.dmi and b/icons/turf/walls/sandstone_wall.dmi differ diff --git a/lore_entries/security/advancedgearandyou.txt b/lore_entries/security/advancedgearandyou.txt new file mode 100644 index 00000000..7949e97b --- /dev/null +++ b/lore_entries/security/advancedgearandyou.txt @@ -0,0 +1 @@ +SYSADMIN -> security@frontier.infolink.kin. Advanced Gear and You ` When threats start to intensify, standard gear may not work. As Layenia station is a recycled facility from NT subsystems, you don't have access to Holostasis Projectors and Blaze Javelins- however, there should be some noteworthy items in the armory should the threat level support it. ` ` DRAGnet ` A strong, versatile tool which is capable of teleporting those left within it's field once the charge is complete. This mode is semi-useless, however, it has an alternative fire which shoots an energy snare and trap. If it directly hits someone, it knocks them down and ties their legs together, making movement difficult. If it misses, it will deploy a trap on the ground that will snare anyone who steps on it, even yourself. Caution advised; please remember that this item may not work on animals and silicons. ` ` Blaster carbine ` An outdated and unreliable laser weapon to the likes of Kinaris's own, however it serves it's own purpose in light engagements. It's main firing mode is a disabler bolt of energy that is capable of slowly draining the stamina of a target. The alternate fire mode heats up the lasers intensely, causing them to be that much more lethal and burning. Avoid using this mode when unnecessary. Needs to be recharged after energy capacity is lost. ` ` Blaster rifle ` Similar to the carbine, this is a very old model of laser weaponry. However, it lacks a nonlethal option and has only one lethal firing mode. Because of this, it has a higher energy capacity and damage rate. Needs to be recharged after energy capacity is lost. ` ` Riot shotgun ` A pump-action shotgun that is not automatic. Load a round in, rack the shotgun, turn off the safety, and fire. Ammo types can be nonlethal beanbag slugs, which still do a slight amount of bruising, but aim to disable effectively with sheer stopping power compared to it's lethal counterpart. This weapon has a maximum ammo capacity of 6 at a time. Not to be confused with automatic combat shotguns, which don't need to be racked after it's been fired. ` ` Riot armor and shields ` A very bulky suit that is capable of stopping most blunt force in it's tracks. Best used with a shield, but it overall slows the wearer down. Not very worth it; you'd be better off trying not to tank damage. ` ` Reflector vest ` A worn vest with a toggle that is capable of reflecting energy projectiles from once they came. Ensure that the toggle is turned on, and the vest is applied properly. This will not protect against ballistics and melee. ` ` Ion rifle ` A bulky weapon that is capable of shooting ionized energy blasts that can disrupt mechanical subsystems and disable them in an area of effect. This is especially effective against cyborgs and mechs, as well as an augmented crew member. Otherwise, this may cause a lot of damage to the station itself. ` ` Security temperature gun ` A single-fire weapon that can blast either freezing-cold or blazing-hot waves of energy onto a target. This is especially effective against animals that struggle against extreme temperatures, such as using the cold mode on a slime. Be wary that it is lethal. \ No newline at end of file diff --git a/lore_entries/security/basicgearandyou.txt b/lore_entries/security/basicgearandyou.txt new file mode 100644 index 00000000..43f1da58 --- /dev/null +++ b/lore_entries/security/basicgearandyou.txt @@ -0,0 +1 @@ +SYSADMIN -> security@frontier.infolink.kin. Basic Gear and You ` Not only must an SSP know what mindset to be in, they must also recognize the effects of their gear and items, as well as when they're needed. This section will cover some items, and how they can be useful given certain circumstances. Note that Layenia Station is using much older, and has access to less state-of-the-art technology, as it is using recycled Nanotrasen subsystems. ` ` Handcuffs ` A tool utilized for restraining criminals on the wrists. Apply on both wrists, fasten and lock. These should only be used when transporting prisoners, NOT when they're in a cell. Can only be applied on creatures with applicable limbs. ` ` Flash ` A device with a bright bulb, used to temporarily disorient visuals, both on cyborgs and living creatures. While harmless, extended use may result in eye damage. Using in hand will result in an area of flash, while using against another will flash that specific being. Useless against anything with flash protection ` ` Pepperspray ` A small nozzle used to spray irritant chemicals, most effective when used on the eyes of a living being who is not wearing eye protection. Otherwise, this item services as nothing more than an irritating spray. Can be refilled. ` ` Stunbaton ` An electrically charged rod with a prod on the end, which can be activated to deal incredible amounts of stamina drain. This is your primary melee-ranged tool, which should be applied to criminals approximately four times (size may vary, or until target is exhausted) followed up by handcuffing. Do not hit harmfully with this without just cause; requires a recharge after frequent use, and can be upgraded with better power cells. ` ` Flashbang ` A chemical payload that will prime upon activation, and will explode into a disorienting blast after a few seconds. Requires flash and ear protection to completely nullify it's effects, but being too close can override that. This is a prime tool for crowd control, and should only be used when it's absolutely necessary. Effective for dispersing crowds. ` ` Taser ` A handheld sidearm that is capable of launching an electric volt of energy which can temporarily stun and disarm most attackers via electric shock to the muscles. It can have it's firing mode switched to a disabler mode, which is capable of draining the stamina of the target, without the stun. Use only on creatures that aren't immune. \ No newline at end of file diff --git a/lore_entries/security/defensivegearandyou.txt b/lore_entries/security/defensivegearandyou.txt new file mode 100644 index 00000000..c789909f --- /dev/null +++ b/lore_entries/security/defensivegearandyou.txt @@ -0,0 +1 @@ +SYSADMIN - > security@frontier.infolink.kin Defensive Gear and You ` Sometimes, situations may call for a more defensive approach, especially when asset protection is kept in-mind. Layenia has access to some light defensive armaments within the station; it is not equipped with defensive battery cannons on the exterior. ` ` Barrier grenade ` These grenades are capable of deploying a barrier on it's location after explosion. The barrier itself cannot be clambered over, and can take quite a beating before it goes down. Effective for narrowing passageways. ` ` Portable flasher ` A bulky unit which can be bolted to the floor with a wrench, and will flash any fast-moving personnel within it's radius. Will not flash if people are walking by it. ` ` Security holobarrier projector ` A handheld device which can project a hardlight barrier- three total- at a location of choosing. It can be dispelled easily with the same device as well. \ No newline at end of file diff --git a/lore_entries/security/introduction.txt b/lore_entries/security/introduction.txt new file mode 100644 index 00000000..f8926f32 --- /dev/null +++ b/lore_entries/security/introduction.txt @@ -0,0 +1 @@ +SYSADMIN -> security@frontier.infolink.kin. Introduction ` The act of securing and protection any Kinaris asset is not an easy one. Difficulty can range from monotanous and dreary, to outright hellish and overwhelming. It is a SSP's job to ensure that regardless of circumstance, they are both mentally and physically equipped to deal with any situation that may come up. This section will cover the very basics of what you need to know to be educated in the instance of standard security work. ` To act as a SSP, the first step would be to think like one. Sentient Security Personnel are equipped with a plethora of both resources and gear to apprehend criminals, as well an array of support from the station and heads alike. Do not betray your station's trust. Your job as an SSP should be- above all- securing peace. Before anything, you should always consider the outcome of your actions, and others' as well. A responsible SSP would understand when a good time to use a baton is, and when words will allow a better outcome. Lack of this proper resolve may result in uneasiness around your workplace, both from your team and those you are to protect. This is not only grounds for demotion when abuse is repeated, but may result in an abusive SSP's inevitable lynching. These effects can snowball into much worse; so ensure that you and your team are well-communicative, and are proper in terms of gear use and protocol. Catch problems at the source. Think like a proper SSP. ` Following up a proper mindset, it is important to note the infinite complexity that situations may involve themselves in. A responsible SSP will always keep in mind truths and lies when proposed with a situation, and must acknowledge that their guess can be wrong as well. Following Kinaris Security Protocol to the letter may also be problematic, due to the malleable nature that people can involve themselves within. Leeway is important to give when necessary, and a firm hand provided otherwise. Know when to apply proper protocol, and when to give leeway. \ No newline at end of file diff --git a/lore_entries/security/usageandterms.txt b/lore_entries/security/usageandterms.txt new file mode 100644 index 00000000..4291ee2d --- /dev/null +++ b/lore_entries/security/usageandterms.txt @@ -0,0 +1 @@ +SYSADMIN -> security@frontier.infolink.kin. Usage and Terms ` This specific protocol terminal refers to the processes and operation of Sentient Security Personnel (SSP) in regards to their workplace and behavior within reasonable operating conditions. The usage of this terminal is for both educational and referral purposes. Punishments given out by SSP should be based upon the data within this terminal. Note that these should be a baseline, and following to the letter may or may not be preffered. Case-by-case basis analysis is encouraged. \ No newline at end of file diff --git a/lore_entries/security/wip.txt b/lore_entries/security/wip.txt new file mode 100644 index 00000000..3c829afd --- /dev/null +++ b/lore_entries/security/wip.txt @@ -0,0 +1 @@ +SYSADMIN -> security@frontier.infolink.kin. Unauthorized Access ` File is currently undergoing approval via your local Central Command authority. Please seek previous methods for this specific file. \ No newline at end of file diff --git a/modular_citadel/code/datums/components/phantomthief.dm b/modular_citadel/code/datums/components/phantomthief.dm deleted file mode 100644 index d34e16f6..00000000 --- a/modular_citadel/code/datums/components/phantomthief.dm +++ /dev/null @@ -1,49 +0,0 @@ -//This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack. - -/datum/component/phantomthief - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS - - var/filter_x - var/filter_y - var/filter_size - var/filter_border - var/filter_color - - var/datum/component/redirect/combattoggle_redir - -/datum/component/phantomthief/Initialize(_x = -2, _y = 0, _size = 0, _border = 0, _color = "#E62111") - filter_x = _x - filter_y = _y - filter_size = _size - filter_border = _border - filter_color = _color - - RegisterSignal(parent, COMSIG_COMBAT_TOGGLED, .proc/handlefilterstuff) - RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/OnEquipped) - RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/OnDropped) - -/datum/component/phantomthief/proc/handlefilterstuff(mob/user, combatmodestate) - if(istype(user)) - var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color) - if(!combatmodestate) - user.filters -= thefilter - else - user.filters += thefilter - -/datum/component/phantomthief/proc/stripdesiredfilter(mob/user) - if(istype(user)) - var/thefilter = filter(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, border = filter_border, color = filter_color) - user.filters -= thefilter - -/datum/component/phantomthief/proc/OnEquipped(mob/user, slot) - if(!istype(user)) - return - if(!combattoggle_redir) - combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/handlefilterstuff))) - -/datum/component/phantomthief/proc/OnDropped(mob/user) - if(!istype(user)) - return - if(combattoggle_redir) - QDEL_NULL(combattoggle_redir) - stripdesiredfilter(user) diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index ef45e07b..a35a5f50 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -201,7 +201,6 @@ var/enthrallGender //Use master or mistress var/mental_capacity //Higher it is, lower the cooldown on commands, capacity reduces with resistance. - var/datum/weakref/redirect_component //resistance var/distancelist = list(2,1.5,1,0.8,0.6,0.5,0.4,0.3,0.2) //Distance multipliers @@ -231,7 +230,7 @@ master = get_mob_by_key(enthrallID) //if(M.ckey == enthrallID) // owner.remove_status_effect(src)//At the moment, a user can enthrall themselves, toggle this back in if that should be removed. - redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) //Do resistance calc if resist is pressed# + RegisterSignal(owner, COMSIG_LIVING_RESIST, .proc/owner_resist) //Do resistance calc if resist is pressed# RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/owner_hear) //var/obj/item/organ/brain/B = M.getorganslot(ORGAN_SLOT_BRAIN) //removing this, may cause some issues unsure. mental_capacity = 500 - M.getOrganLoss(ORGAN_SLOT_BRAIN)//It's their brain! @@ -570,8 +569,7 @@ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2") SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3") SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing4") - qdel(redirect_component.resolve()) - redirect_component = null + UnregisterSignal(M, COMSIG_LIVING_RESIST) UnregisterSignal(owner, COMSIG_MOVABLE_HEAR) REMOVE_TRAIT(owner, TRAIT_PACIFISM, "MKUltra") to_chat(owner, "You're now free of [master]'s influence, and fully independent!'") diff --git a/modular_citadel/code/game/objects/items/holy_weapons.dm b/modular_citadel/code/game/objects/items/holy_weapons.dm index 3ecc6cc3..06cdb0f5 100644 --- a/modular_citadel/code/game/objects/items/holy_weapons.dm +++ b/modular_citadel/code/game/objects/items/holy_weapons.dm @@ -30,24 +30,16 @@ "You kneel[M == user ? null : " next to [M]"] and begin a prayer to [deity_name].") praying = TRUE - if(do_after(user, 100, target = M)) + if(do_after(user, 20, target = M)) if(istype(M, /mob/living/carbon/human)) // This probably should not work on catpeople. They're unholy abominations. var/mob/living/carbon/human/target = M - - if(iscultist(M) || is_servant_of_ratvar(M)) //ripped from holywater code. - if(iscultist(M)) - SSticker.mode.remove_cultist(M.mind, FALSE, TRUE) - else if(is_servant_of_ratvar(M)) - remove_servant_of_ratvar(M) - + M.reagents.add_reagent("holywater", 5) to_chat(target, "[user]'s prayer to [deity_name] has eased your pain!") target.adjustToxLoss(-5, TRUE, TRUE) target.adjustOxyLoss(-5) target.adjustBruteLoss(-5) target.adjustFireLoss(-5) - praying = FALSE - else to_chat(user, "Your prayer to [deity_name] was interrupted.") praying = FALSE diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm index d0e059e7..ff0ab7df 100644 --- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm +++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm @@ -275,7 +275,7 @@ /obj/item/twohanded/dualsaber/hypereutactic/chaplain/Initialize() . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE) + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE) /obj/item/twohanded/dualsaber/hypereutactic/chaplain/IsReflect() return FALSE diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 8c5bf255..beb5f8b9 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -284,7 +284,7 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) //This is used for forced orgasms and other hands-free climaxes var/total_fluids = 0 var/datum/reagents/fluid_source = null var/unable_to_come = FALSE @@ -310,12 +310,18 @@ "You feel yourself about to orgasm.", \ "You feel yourself about to orgasm.") if(do_after(src, mb_time, target = src)) - if(total_fluids > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], using [p_their()] [G.name]!", \ - "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].", \ - "You climax using your [G.name].") + if(spillage) + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + fluid_source.clear_reagents() + src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], with [p_their()] [G.name]!", \ + "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].", \ + "You climax using your [G.name].") + else //Else from spillage check, also note subtle text change + src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ + "You climax with your [G.name].", \ + "You climax using your [G.name].") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) @@ -420,7 +426,7 @@ src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ "You ejaculate with someone, using your [G.name].", \ "You have climaxed inside someone, using your [G.name].") - to_chat(L, "You feel someone ejeculate inside you.") + to_chat(L, "You feel someone ejaculate inside you.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) diff --git a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm index 716e33c7..669697c6 100644 --- a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm +++ b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm @@ -6,19 +6,18 @@ icon_state = "s-ninja" item_state = "s-ninja" -/obj/item/clothing/glasses/phantomthief/Initialize() +/obj/item/clothing/glasses/phantomthief/ComponentInitialize() . = ..() - AddComponent(/datum/component/phantomthief) + AddComponent(/datum/component/wearertargeting/phantomthief) /obj/item/clothing/glasses/phantomthief/syndicate name = "suspicious plastic mask" desc = "A cheap, bulky, Syndicate-branded plastic face mask. You have to break in to break out." var/nextadrenalinepop - var/datum/component/redirect/combattoggle_redir -/obj/item/clothing/glasses/phantomthief/syndicate/examine(user) +/obj/item/clothing/glasses/phantomthief/syndicate/examine(mob/user) . = ..() - if(combattoggle_redir) + if(user.get_item_by_slot(SLOT_GLASSES) == src) if(world.time >= nextadrenalinepop) . += "The built-in adrenaline injector is ready for use." else @@ -34,12 +33,12 @@ . = ..() if(!istype(user)) return - if(!combattoggle_redir) - combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/injectadrenaline))) + if(slot != SLOT_GLASSES) + return + RegisterSignal(user, COMSIG_COMBAT_TOGGLED, .proc/injectadrenaline) /obj/item/clothing/glasses/phantomthief/syndicate/dropped(mob/user) . = ..() if(!istype(user)) return - if(combattoggle_redir) - QDEL_NULL(combattoggle_redir) + UnregisterSignal(user, COMSIG_COMBAT_TOGGLED) diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi index f3edd3c2..fb2ba77f 100644 Binary files a/modular_citadel/icons/mob/suit_digi.dmi and b/modular_citadel/icons/mob/suit_digi.dmi differ diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf index 9fa01387..28a498a8 100644 --- a/modular_citadel/interface/skin.dmf +++ b/modular_citadel/interface/skin.dmf @@ -80,6 +80,7 @@ window "mainwindow" anchor2 = none background-color = #272727 is-visible = false + auto-format = false saved-params = "" elem "tooltip" type = BROWSER diff --git a/tgstation.dme b/tgstation.dme index 5f39bb4b..416e1083 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -382,12 +382,12 @@ #include "code\datums\components\ntnet_interface.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\paintable.dm" +#include "code\datums\components\phantomthief.dm" #include "code\datums\components\rad_insulation.dm" #include "code\datums\components\radioactive.dm" #include "code\datums\components\remote_materials.dm" #include "code\datums\components\riding.dm" #include "code\datums\components\rotation.dm" -#include "code\datums\components\signal_redirect.dm" #include "code\datums\components\sizzle.dm" #include "code\datums\components\slippery.dm" #include "code\datums\components\spawner.dm" @@ -478,6 +478,7 @@ #include "code\datums\elements\flavor_text.dm" #include "code\datums\elements\ghost_role_eligibility.dm" #include "code\datums\elements\mob_holder.dm" +#include "code\datums\elements\squish.dm" #include "code\datums\elements\swimming.dm" #include "code\datums\elements\wuv.dm" #include "code\datums\helper_datums\events.dm" @@ -1446,6 +1447,11 @@ #include "code\modules\assembly\signaler.dm" #include "code\modules\assembly\timer.dm" #include "code\modules\assembly\voice.dm" +#include "code\modules\asset_cache\asset_cache.dm" +#include "code\modules\asset_cache\asset_cache_client.dm" +#include "code\modules\asset_cache\asset_cache_item.dm" +#include "code\modules\asset_cache\asset_list.dm" +#include "code\modules\asset_cache\asset_list_items.dm" #include "code\modules\atmospherics\multiz.dm" #include "code\modules\atmospherics\environmental\LINDA_fire.dm" #include "code\modules\atmospherics\environmental\LINDA_system.dm" @@ -1589,7 +1595,6 @@ #include "code\modules\cargo\packs\security.dm" #include "code\modules\cargo\packs\service.dm" #include "code\modules\chatter\chatter.dm" -#include "code\modules\client\asset_cache.dm" #include "code\modules\client\client_colour.dm" #include "code\modules\client\client_defines.dm" #include "code\modules\client\client_procs.dm" @@ -3069,6 +3074,7 @@ #include "hyperstation\code\game\objects\items\cosmetics.dm" #include "hyperstation\code\game\objects\items\storage\big_bag.dm" #include "hyperstation\code\game\objects\structures\ghost_role_spawners.dm" +#include "hyperstation\code\game\objects\structures\sauna_oven.dm" #include "hyperstation\code\gamemode\traitor_lewd.dm" #include "hyperstation\code\gamemode\traitor_thief.dm" #include "hyperstation\code\gamemode\werewolf\werewolf.dm" @@ -3123,6 +3129,8 @@ #include "hyperstation\code\modules\power\reactor\reactor_cargo.dm" #include "hyperstation\code\modules\reagents\chemistry\reagents\food_reagents.dm" #include "hyperstation\code\modules\reagents\chemistry\reagents\hydroponics_reactions.dm" +#include "hyperstation\code\modules\reagents\chemistry\reagents\medicine_reagents.dm" +#include "hyperstation\code\modules\reagents\chemistry\recipes\medicine.dm" #include "hyperstation\code\modules\resize\resize_action.dm" #include "hyperstation\code\modules\resize\resizing.dm" #include "hyperstation\code\modules\resize\sizechems.dm" @@ -3165,7 +3173,6 @@ #include "modular_citadel\code\controllers\configuration\entries\general.dm" #include "modular_citadel\code\controllers\subsystem\job.dm" #include "modular_citadel\code\datums\components\material_container.dm" -#include "modular_citadel\code\datums\components\phantomthief.dm" #include "modular_citadel\code\datums\components\souldeath.dm" #include "modular_citadel\code\datums\mood_events\chem_events.dm" #include "modular_citadel\code\datums\mood_events\generic_negative_events.dm"